@safercity/sdk 0.0.1 → 0.1.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/dist/index.cjs CHANGED
@@ -233,6 +233,230 @@ function createSaferCityClient(options) {
233
233
  }
234
234
  };
235
235
  }
236
+ var ServerClient = class extends sdkCore.BaseClient {
237
+ tokenManager;
238
+ constructor(config) {
239
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
240
+ super({
241
+ baseUrl,
242
+ timeout: config.timeout,
243
+ fetch: config.fetch
244
+ });
245
+ this.tokenManager = new sdkCore.TokenManager({
246
+ credentials: config.auth,
247
+ baseUrl,
248
+ storage: config.tokenStore,
249
+ fetch: config.fetch
250
+ });
251
+ }
252
+ /**
253
+ * Get a valid access token
254
+ */
255
+ async getAccessToken() {
256
+ return this.tokenManager.getToken();
257
+ }
258
+ /**
259
+ * Force refresh the token
260
+ */
261
+ async refreshToken() {
262
+ return this.tokenManager.forceRefresh();
263
+ }
264
+ /**
265
+ * Clear stored tokens
266
+ */
267
+ clearTokens() {
268
+ this.tokenManager.clear();
269
+ }
270
+ /**
271
+ * Make an authenticated request
272
+ * Automatically adds the Authorization header with a valid token
273
+ */
274
+ async request(method, path, options) {
275
+ const token = await this.getAccessToken();
276
+ const authHeaders = {
277
+ ...options?.headers,
278
+ Authorization: `Bearer ${token}`
279
+ };
280
+ return super.request(method, path, {
281
+ ...options,
282
+ headers: authHeaders
283
+ });
284
+ }
285
+ };
286
+ function createServerClient(config) {
287
+ return new ServerClient(config);
288
+ }
289
+ var tokenManagers = /* @__PURE__ */ new Map();
290
+ function getTokenManager(config) {
291
+ const key = `${config.clientId}:${config.baseUrl ?? "default"}`;
292
+ let manager = tokenManagers.get(key);
293
+ if (!manager) {
294
+ manager = new sdkCore.TokenManager({
295
+ credentials: {
296
+ clientId: config.clientId,
297
+ clientSecret: config.clientSecret,
298
+ tenantId: config.tenantId
299
+ },
300
+ baseUrl: config.baseUrl ?? "https://api.safercity.com",
301
+ storage: config.tokenStore,
302
+ fetch: config.fetch
303
+ });
304
+ tokenManagers.set(key, manager);
305
+ }
306
+ return manager;
307
+ }
308
+ function createNextHandler(config) {
309
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
310
+ const pathPrefix = config.pathPrefix ?? "/api/safercity";
311
+ const forwardHeaders = config.forwardHeaders ?? ["content-type", "accept", "x-request-id"];
312
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
313
+ return async function handler(request) {
314
+ const tokenManager = getTokenManager(config);
315
+ try {
316
+ const token = await tokenManager.getToken();
317
+ const url = new URL(request.url);
318
+ const path = url.pathname.replace(new RegExp(`^${pathPrefix}`), "");
319
+ const targetUrl = `${baseUrl}${path}${url.search}`;
320
+ const headers = {
321
+ Authorization: `Bearer ${token}`
322
+ };
323
+ for (const header of forwardHeaders) {
324
+ const value = request.headers.get(header);
325
+ if (value) {
326
+ headers[header] = value;
327
+ }
328
+ }
329
+ const tenantIdHeader = request.headers.get("x-tenant-id");
330
+ if (tenantIdHeader) {
331
+ headers["X-Tenant-ID"] = tenantIdHeader;
332
+ } else if (config.tenantId) {
333
+ headers["X-Tenant-ID"] = config.tenantId;
334
+ }
335
+ let body;
336
+ if (request.method !== "GET" && request.method !== "HEAD") {
337
+ body = await request.text();
338
+ }
339
+ const response = await fetchFn(targetUrl, {
340
+ method: request.method,
341
+ headers,
342
+ body
343
+ });
344
+ const responseHeaders = new Headers(response.headers);
345
+ responseHeaders.set("Access-Control-Allow-Origin", "*");
346
+ responseHeaders.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
347
+ responseHeaders.set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Tenant-ID");
348
+ return new Response(response.body, {
349
+ status: response.status,
350
+ statusText: response.statusText,
351
+ headers: responseHeaders
352
+ });
353
+ } catch (error) {
354
+ console.error("[SaferCity Proxy] Error:", error);
355
+ return new Response(
356
+ JSON.stringify({
357
+ error: "proxy_error",
358
+ message: error instanceof Error ? error.message : "Proxy request failed"
359
+ }),
360
+ {
361
+ status: 502,
362
+ headers: {
363
+ "Content-Type": "application/json"
364
+ }
365
+ }
366
+ );
367
+ }
368
+ };
369
+ }
370
+ function createExpressMiddleware(config) {
371
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
372
+ const forwardHeaders = config.forwardHeaders ?? ["content-type", "accept", "x-request-id"];
373
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
374
+ return async function middleware(req, res, next) {
375
+ const tokenManager = getTokenManager(config);
376
+ try {
377
+ const token = await tokenManager.getToken();
378
+ const targetUrl = `${baseUrl}${req.path}${req.url.includes("?") ? req.url.slice(req.url.indexOf("?")) : ""}`;
379
+ const headers = {
380
+ Authorization: `Bearer ${token}`
381
+ };
382
+ for (const header of forwardHeaders) {
383
+ const value = req.headers[header.toLowerCase()];
384
+ if (value) {
385
+ headers[header] = Array.isArray(value) ? value[0] : value;
386
+ }
387
+ }
388
+ const tenantIdHeader = req.headers["x-tenant-id"];
389
+ if (tenantIdHeader) {
390
+ headers["X-Tenant-ID"] = Array.isArray(tenantIdHeader) ? tenantIdHeader[0] : tenantIdHeader;
391
+ } else if (config.tenantId) {
392
+ headers["X-Tenant-ID"] = config.tenantId;
393
+ }
394
+ let body;
395
+ if (req.method !== "GET" && req.method !== "HEAD" && req.body) {
396
+ body = typeof req.body === "string" ? req.body : JSON.stringify(req.body);
397
+ }
398
+ const response = await fetchFn(targetUrl, {
399
+ method: req.method,
400
+ headers,
401
+ body
402
+ });
403
+ const contentType = response.headers.get("content-type");
404
+ const responseBody = contentType?.includes("application/json") ? await response.json() : await response.text();
405
+ res.status(response.status);
406
+ res.set({
407
+ "Access-Control-Allow-Origin": "*",
408
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
409
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Tenant-ID",
410
+ "Content-Type": contentType ?? "application/json"
411
+ });
412
+ if (typeof responseBody === "string") {
413
+ res.send(responseBody);
414
+ } else {
415
+ res.json(responseBody);
416
+ }
417
+ } catch (error) {
418
+ console.error("[SaferCity Proxy] Error:", error);
419
+ next(error);
420
+ }
421
+ };
422
+ }
423
+ function createProxyHandler(config) {
424
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
425
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
426
+ return async function proxy(request) {
427
+ const tokenManager = getTokenManager(config);
428
+ const token = await tokenManager.getToken();
429
+ let targetUrl = `${baseUrl}${request.path}`;
430
+ if (request.query && Object.keys(request.query).length > 0) {
431
+ const params = new URLSearchParams(request.query);
432
+ targetUrl += `?${params.toString()}`;
433
+ }
434
+ const headers = {
435
+ Authorization: `Bearer ${token}`,
436
+ "Content-Type": "application/json",
437
+ ...request.headers
438
+ };
439
+ if (config.tenantId) {
440
+ headers["X-Tenant-ID"] = config.tenantId;
441
+ }
442
+ const response = await fetchFn(targetUrl, {
443
+ method: request.method,
444
+ headers,
445
+ body: request.body ? JSON.stringify(request.body) : void 0
446
+ });
447
+ const contentType = response.headers.get("content-type");
448
+ const body = contentType?.includes("application/json") ? await response.json() : await response.text();
449
+ const responseHeaders = {};
450
+ response.headers.forEach((value, key) => {
451
+ responseHeaders[key] = value;
452
+ });
453
+ return {
454
+ status: response.status,
455
+ headers: responseHeaders,
456
+ body
457
+ };
458
+ };
459
+ }
236
460
 
237
461
  Object.defineProperty(exports, "FetchStreamAdapter", {
238
462
  enumerable: true,
@@ -246,6 +470,10 @@ Object.defineProperty(exports, "SaferCityApiError", {
246
470
  enumerable: true,
247
471
  get: function () { return sdkCore.SaferCityApiError; }
248
472
  });
473
+ Object.defineProperty(exports, "TokenManager", {
474
+ enumerable: true,
475
+ get: function () { return sdkCore.TokenManager; }
476
+ });
249
477
  Object.defineProperty(exports, "WebStreamAdapter", {
250
478
  enumerable: true,
251
479
  get: function () { return sdkCore.WebStreamAdapter; }
@@ -270,6 +498,11 @@ Object.defineProperty(exports, "parseJwtPayload", {
270
498
  enumerable: true,
271
499
  get: function () { return sdkCore.parseJwtPayload; }
272
500
  });
501
+ exports.ServerClient = ServerClient;
502
+ exports.createExpressMiddleware = createExpressMiddleware;
503
+ exports.createNextHandler = createNextHandler;
504
+ exports.createProxyHandler = createProxyHandler;
273
505
  exports.createSaferCityClient = createSaferCityClient;
506
+ exports.createServerClient = createServerClient;
274
507
  //# sourceMappingURL=index.cjs.map
275
508
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["BaseClient","createStreamAdapter","options"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SaferCity API Client\n * \n * Main client for interacting with the SaferCity multi-tenant API.\n * Provides typed methods for all API endpoints with streaming support.\n */\n\nimport {\n BaseClient,\n type SaferCityConfig,\n type StreamAdapter,\n createStreamAdapter,\n type ServerSentEvent,\n type EventSourceOptions,\n} from '@safercity/sdk-core';\n\nexport interface SaferCityClientOptions extends SaferCityConfig {\n /**\n * Custom stream adapter for SSE (auto-detected if not provided)\n */\n streamAdapter?: StreamAdapter;\n}\n\n/**\n * Create a SaferCity API client\n */\nexport function createSaferCityClient(options: SaferCityClientOptions) {\n const baseClient = new BaseClient(options);\n const streamAdapter = options.streamAdapter ?? createStreamAdapter(options.fetch);\n \n return {\n /**\n * Access the underlying base client for custom requests\n */\n _client: baseClient,\n \n /**\n * Update authentication token\n */\n setToken: (token: string | undefined) => baseClient.setToken(token),\n \n /**\n * Update tenant ID\n */\n setTenantId: (tenantId: string | undefined) => baseClient.setTenantId(tenantId),\n \n /**\n * Get current configuration\n */\n getConfig: () => baseClient.getConfig(),\n\n // ==================\n // Health & System\n // ==================\n \n health: {\n /**\n * Check API health status\n */\n check: () => baseClient.get<{\n status: string;\n timestamp: string;\n panicProviders?: {\n healthy: boolean;\n stats?: unknown;\n providers?: unknown;\n };\n }>('/health'),\n },\n\n // ==================\n // Authentication\n // ==================\n \n auth: {\n /**\n * Get current authentication context\n */\n whoami: () => baseClient.get<{\n tenantId: string | null;\n environment: string;\n scopes: string[];\n sessionId: string;\n }>('/auth/whoami'),\n \n /**\n * Check if authenticated (optional auth)\n */\n check: () => baseClient.get<{\n authenticated: boolean;\n tenantId: string | null;\n }>('/auth/optional'),\n },\n\n // ==================\n // OAuth\n // ==================\n \n oauth: {\n /**\n * Get access token\n */\n token: (body: {\n grant_type: 'client_credentials' | 'refresh_token';\n tenantId?: string;\n userId?: string;\n refresh_token?: string;\n }) => baseClient.post<{\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n }>('/oauth/token', body),\n \n /**\n * Refresh access token\n */\n refresh: (body: { refresh_token: string }) =>\n baseClient.post<{\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n }>('/oauth/refresh', body),\n \n /**\n * Introspect token\n */\n introspect: (body: { token: string }) =>\n baseClient.post<{\n active: boolean;\n tenantId?: string;\n sub?: string;\n scope?: string;\n exp?: number;\n }>('/oauth/introspect', body),\n \n /**\n * Revoke token\n */\n revoke: (body: { token: string }) =>\n baseClient.post<{ success: boolean }>('/oauth/revoke', body),\n },\n\n // ==================\n // Tenants\n // ==================\n \n tenants: {\n /**\n * Create a new tenant\n */\n create: (body: { name: string; domain?: string }) =>\n baseClient.post<{\n tenantId: string;\n name: string;\n setupToken: string;\n }>('/v1/tenants', body),\n \n /**\n * List tenants (admin)\n */\n list: (query?: { limit?: number; cursor?: string }) =>\n baseClient.get<{\n tenants: Array<{ id: string; name: string }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/tenants', { query }),\n },\n\n // ==================\n // Credentials\n // ==================\n \n credentials: {\n /**\n * Exchange setup token for credentials\n */\n setup: (body: { setupToken: string }) =>\n baseClient.post<{\n clientId: string;\n clientSecret: string;\n tenantId: string;\n }>('/v1/credentials', body),\n \n /**\n * List credentials\n */\n list: () =>\n baseClient.get<{\n credentials: Array<{\n id: string;\n clientId: string;\n createdAt: string;\n lastUsed?: string;\n }>;\n }>('/v1/credentials'),\n \n /**\n * Revoke credential\n */\n revoke: (credentialId: string) =>\n baseClient.delete<{ success: boolean }>(`/v1/credentials/${credentialId}`),\n },\n\n // ==================\n // Users\n // ==================\n \n users: {\n /**\n * Create user\n */\n create: (body: {\n email?: string;\n phone?: string;\n firstName?: string;\n lastName?: string;\n metadata?: Record<string, unknown>;\n }) => baseClient.post<{ id: string; email?: string; phone?: string }>('/v1/users', body),\n \n /**\n * List users\n */\n list: (query?: { limit?: number; cursor?: string; status?: string }) =>\n baseClient.get<{\n users: Array<{\n id: string;\n email?: string;\n phone?: string;\n status: string;\n }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/users', { query }),\n \n /**\n * Get user by ID\n */\n get: (userId: string) =>\n baseClient.get<{\n id: string;\n email?: string;\n phone?: string;\n firstName?: string;\n lastName?: string;\n status: string;\n metadata?: Record<string, unknown>;\n }>(`/v1/users/${userId}`),\n \n /**\n * Update user\n */\n update: (userId: string, body: {\n email?: string;\n phone?: string;\n firstName?: string;\n lastName?: string;\n metadata?: Record<string, unknown>;\n }) => baseClient.put<{ id: string }>(`/v1/users/${userId}`, body),\n \n /**\n * Update user status\n */\n updateStatus: (userId: string, body: { status: string }) =>\n baseClient.patch<{ id: string; status: string }>(`/v1/users/${userId}/status`, body),\n \n /**\n * Delete user\n */\n delete: (userId: string) =>\n baseClient.delete<{ success: boolean }>(`/v1/users/${userId}`),\n },\n\n // ==================\n // Panics\n // ==================\n \n panics: {\n /**\n * Create panic\n */\n create: (body: {\n userId: string;\n panicTypeId?: string;\n latitude: number;\n longitude: number;\n accuracy?: number;\n metadata?: Record<string, unknown>;\n }) => baseClient.post<{\n id: string;\n status: string;\n createdAt: string;\n }>('/v1/panics', body),\n \n /**\n * Get panic by ID\n */\n get: (panicId: string, query?: { userId?: string }) =>\n baseClient.get<{\n id: string;\n userId: string;\n status: string;\n latitude: number;\n longitude: number;\n createdAt: string;\n updatedAt?: string;\n }>(`/v1/panics/${panicId}`, { query }),\n \n /**\n * List panics\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n cursor?: string;\n }) => baseClient.get<{\n panics: Array<{\n id: string;\n userId: string;\n status: string;\n createdAt: string;\n }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/panics', { query }),\n \n /**\n * Update panic location\n */\n updateLocation: (panicId: string, body: {\n userId: string;\n latitude: number;\n longitude: number;\n accuracy?: number;\n }) => baseClient.put<{\n id: string;\n latitude: number;\n longitude: number;\n }>(`/v1/panics/${panicId}/location`, body),\n \n /**\n * Cancel panic\n */\n cancel: (panicId: string, body: { userId: string; reason?: string }) =>\n baseClient.put<{\n id: string;\n status: string;\n cancelledAt: string;\n }>(`/v1/panics/${panicId}/cancel`, body),\n \n /**\n * Stream panic updates (SSE)\n */\n streamUpdates: (\n panicId: string,\n options?: EventSourceOptions\n ): AsyncIterable<ServerSentEvent> => {\n const config = baseClient.getConfig();\n const url = `${config.baseUrl}/v1/panics/${panicId}/stream`;\n \n return streamAdapter.createEventSource(url, {\n ...options,\n headers: {\n ...options?.headers,\n ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),\n },\n });\n },\n },\n\n // ==================\n // Subscriptions\n // ==================\n \n subscriptions: {\n /**\n * List subscription types\n */\n listTypes: () =>\n baseClient.get<{\n types: Array<{\n id: string;\n name: string;\n description?: string;\n price?: number;\n }>;\n }>('/v1/subscriptions/types'),\n \n /**\n * Create subscription\n */\n create: (body: {\n userId: string;\n subscriptionTypeId: string;\n status?: string;\n }) => baseClient.post<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>('/v1/subscriptions', body),\n \n /**\n * List subscriptions\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n }) => baseClient.get<{\n subscriptions: Array<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>;\n }>('/v1/subscriptions', { query }),\n \n /**\n * Get subscription stats\n */\n stats: () =>\n baseClient.get<{\n total: number;\n active: number;\n byType: Record<string, number>;\n }>('/v1/subscriptions/stats'),\n },\n\n // ==================\n // Notifications\n // ==================\n \n notifications: {\n /**\n * Create subscriber\n */\n createSubscriber: (body: {\n userId: string;\n email?: string;\n phone?: string;\n data?: Record<string, unknown>;\n }) => baseClient.post<{ subscriberId: string }>('/v1/notifications/subscribers', body),\n \n /**\n * Trigger notification\n */\n trigger: (body: {\n userId: string;\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => baseClient.post<{\n transactionId: string;\n status: string;\n }>('/v1/notifications/trigger', body),\n \n /**\n * Get user preferences\n */\n getPreferences: (userId: string) =>\n baseClient.get<{\n preferences: Record<string, unknown>;\n }>(`/v1/notifications/preferences/${userId}`),\n \n /**\n * Update user preferences\n */\n updatePreferences: (userId: string, body: {\n preferences: Record<string, unknown>;\n }) => baseClient.put<{ success: boolean }>(`/v1/notifications/preferences/${userId}`, body),\n },\n\n // ==================\n // Location Safety\n // ==================\n \n locationSafety: {\n /**\n * Check location safety\n */\n check: (query: { latitude: number; longitude: number; radius?: number }) =>\n baseClient.get<{\n safetyScore: number;\n riskLevel: string;\n factors: Array<{ type: string; impact: number }>;\n }>('/v1/location-safety', { query }),\n },\n\n // ==================\n // Crimes\n // ==================\n \n crimes: {\n /**\n * List crimes\n */\n list: (query?: {\n latitude?: number;\n longitude?: number;\n radius?: number;\n type?: string;\n from?: string;\n to?: string;\n limit?: number;\n }) => baseClient.get<{\n crimes: Array<{\n id: string;\n type: string;\n latitude: number;\n longitude: number;\n occurredAt: string;\n }>;\n }>('/v1/crimes', { query }),\n \n /**\n * Get crime categories\n */\n categories: () =>\n baseClient.get<{\n categories: Array<{ id: string; name: string }>;\n }>('/v1/crime-categories'),\n \n /**\n * Get crime types\n */\n types: () =>\n baseClient.get<{\n types: Array<{ id: string; name: string; categoryId: string }>;\n }>('/v1/crime-types'),\n },\n };\n}\n\nexport type SaferCityClient = ReturnType<typeof createSaferCityClient>;\n"]}
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"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _safercity_sdk_core from '@safercity/sdk-core';
2
- import { SaferCityConfig, StreamAdapter, BaseClient, EventSourceOptions, ServerSentEvent } from '@safercity/sdk-core';
3
- export { ApiError, ApiResponse, AuthTokens, EventSourceOptions, FetchStreamAdapter, MemoryTokenStorage, RequestOptions, SaferCityApiError, SaferCityConfig, SaferCityJwtPayload, ServerSentEvent, StreamAdapter, TokenStorage, WebStreamAdapter, createAuthHeader, createStreamAdapter, getJwtExpiration, isTokenExpired, parseJwtPayload } from '@safercity/sdk-core';
2
+ import { SaferCityConfig, StreamAdapter, BaseClient, EventSourceOptions, ServerSentEvent, OAuthCredentials, TokenStorage } from '@safercity/sdk-core';
3
+ export { ApiError, ApiResponse, AuthMode, AuthTokens, ClientModeConfig, CookieModeConfig, DirectModeConfig, EventSourceOptions, FetchStreamAdapter, MemoryTokenStorage, OAuthCredentials, ProxyModeConfig, RequestOptions, SaferCityApiError, SaferCityConfig, SaferCityJwtPayload, ServerSentEvent, StreamAdapter, TokenManager, TokenManagerConfig, TokenStorage, WebStreamAdapter, createAuthHeader, createStreamAdapter, getJwtExpiration, isTokenExpired, parseJwtPayload } from '@safercity/sdk-core';
4
4
 
5
5
  interface SaferCityClientOptions extends SaferCityConfig {
6
6
  /**
@@ -460,4 +460,218 @@ declare function createSaferCityClient(options: SaferCityClientOptions): {
460
460
  };
461
461
  type SaferCityClient = ReturnType<typeof createSaferCityClient>;
462
462
 
463
- export { type SaferCityClient, type SaferCityClientOptions, createSaferCityClient };
463
+ /**
464
+ * Server-side SaferCity Client
465
+ *
466
+ * For backend applications that need to authenticate with OAuth client credentials.
467
+ * Handles automatic token management and refresh.
468
+ */
469
+
470
+ interface ServerClientConfig {
471
+ /**
472
+ * SaferCity API base URL
473
+ * @default "https://api.safercity.com"
474
+ */
475
+ baseUrl?: string;
476
+ /**
477
+ * OAuth credentials for authentication
478
+ */
479
+ auth: OAuthCredentials;
480
+ /**
481
+ * Custom token storage (defaults to in-memory)
482
+ */
483
+ tokenStore?: TokenStorage;
484
+ /**
485
+ * Request timeout in milliseconds
486
+ * @default 30000
487
+ */
488
+ timeout?: number;
489
+ /**
490
+ * Custom fetch implementation
491
+ */
492
+ fetch?: typeof fetch;
493
+ }
494
+ /**
495
+ * Server client that wraps the base client with automatic OAuth token management
496
+ */
497
+ declare class ServerClient extends BaseClient {
498
+ private tokenManager;
499
+ constructor(config: ServerClientConfig);
500
+ /**
501
+ * Get a valid access token
502
+ */
503
+ getAccessToken(): Promise<string>;
504
+ /**
505
+ * Force refresh the token
506
+ */
507
+ refreshToken(): Promise<string>;
508
+ /**
509
+ * Clear stored tokens
510
+ */
511
+ clearTokens(): void;
512
+ /**
513
+ * Make an authenticated request
514
+ * Automatically adds the Authorization header with a valid token
515
+ */
516
+ protected request<T>(method: string, path: string, options?: Parameters<BaseClient['request']>[2]): Promise<{
517
+ data: T;
518
+ status: number;
519
+ headers: Headers;
520
+ }>;
521
+ }
522
+ /**
523
+ * Create a server-side SaferCity client with automatic OAuth token management
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * const client = createServerClient({
528
+ * auth: {
529
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
530
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
531
+ * },
532
+ * });
533
+ *
534
+ * // All requests are automatically authenticated
535
+ * const users = await client.get('/v1/users');
536
+ * ```
537
+ */
538
+ declare function createServerClient(config: ServerClientConfig): ServerClient;
539
+
540
+ /**
541
+ * Proxy Middleware Helpers
542
+ *
543
+ * Helpers for creating proxy endpoints that forward requests to SaferCity API
544
+ * with automatic tenant authentication.
545
+ */
546
+
547
+ interface ProxyConfig {
548
+ /**
549
+ * OAuth client ID
550
+ */
551
+ clientId: string;
552
+ /**
553
+ * OAuth client secret
554
+ */
555
+ clientSecret: string;
556
+ /**
557
+ * SaferCity API base URL
558
+ * @default "https://api.safercity.com"
559
+ */
560
+ baseUrl?: string;
561
+ /**
562
+ * Tenant ID (optional, can be extracted from request)
563
+ */
564
+ tenantId?: string;
565
+ /**
566
+ * Custom token storage
567
+ */
568
+ tokenStore?: TokenStorage;
569
+ /**
570
+ * Path prefix to strip from incoming requests
571
+ * @default "/api/safercity"
572
+ */
573
+ pathPrefix?: string;
574
+ /**
575
+ * Headers to forward from the original request
576
+ * @default ["content-type", "accept", "x-request-id"]
577
+ */
578
+ forwardHeaders?: string[];
579
+ /**
580
+ * Custom fetch implementation
581
+ */
582
+ fetch?: typeof fetch;
583
+ }
584
+ /**
585
+ * Create a Next.js App Router handler for proxying SaferCity API requests
586
+ *
587
+ * @example
588
+ * ```typescript
589
+ * // app/api/safercity/[...path]/route.ts
590
+ * import { createNextHandler } from "@safercity/sdk";
591
+ *
592
+ * const handler = createNextHandler({
593
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
594
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
595
+ * });
596
+ *
597
+ * export { handler as GET, handler as POST, handler as PUT, handler as DELETE, handler as PATCH };
598
+ * ```
599
+ */
600
+ declare function createNextHandler(config: ProxyConfig): (request: Request) => Promise<Response>;
601
+ /**
602
+ * Express/Node.js compatible request type
603
+ */
604
+ interface ExpressRequest {
605
+ method: string;
606
+ path: string;
607
+ url: string;
608
+ headers: Record<string, string | string[] | undefined>;
609
+ body?: unknown;
610
+ query?: Record<string, string>;
611
+ }
612
+ /**
613
+ * Express/Node.js compatible response type
614
+ */
615
+ interface ExpressResponse {
616
+ status(code: number): ExpressResponse;
617
+ set(headers: Record<string, string>): ExpressResponse;
618
+ json(data: unknown): void;
619
+ send(data: string | ArrayBuffer | Uint8Array): void;
620
+ }
621
+ /**
622
+ * Express next function type
623
+ */
624
+ type NextFunction = (error?: unknown) => void;
625
+ /**
626
+ * Create an Express middleware for proxying SaferCity API requests
627
+ *
628
+ * @example
629
+ * ```typescript
630
+ * // Express middleware
631
+ * import express from "express";
632
+ * import { createExpressMiddleware } from "@safercity/sdk";
633
+ *
634
+ * const app = express();
635
+ *
636
+ * app.use(
637
+ * "/api/safercity",
638
+ * createExpressMiddleware({
639
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
640
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
641
+ * })
642
+ * );
643
+ * ```
644
+ */
645
+ declare function createExpressMiddleware(config: ProxyConfig): (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => Promise<void>;
646
+ /**
647
+ * Create a generic proxy handler that works with any framework
648
+ * Returns a function that takes a request and returns a response
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * const proxy = createProxyHandler({
653
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
654
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
655
+ * });
656
+ *
657
+ * // Use with any framework
658
+ * const response = await proxy({
659
+ * method: "GET",
660
+ * path: "/v1/users",
661
+ * headers: {},
662
+ * });
663
+ * ```
664
+ */
665
+ declare function createProxyHandler(config: ProxyConfig): (request: {
666
+ method: string;
667
+ path: string;
668
+ headers?: Record<string, string>;
669
+ body?: unknown;
670
+ query?: Record<string, string>;
671
+ }) => Promise<{
672
+ status: number;
673
+ headers: Record<string, string>;
674
+ body: unknown;
675
+ }>;
676
+
677
+ export { type ProxyConfig, type SaferCityClient, type SaferCityClientOptions, ServerClient, type ServerClientConfig, createExpressMiddleware, createNextHandler, createProxyHandler, createSaferCityClient, createServerClient };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _safercity_sdk_core from '@safercity/sdk-core';
2
- import { SaferCityConfig, StreamAdapter, BaseClient, EventSourceOptions, ServerSentEvent } from '@safercity/sdk-core';
3
- export { ApiError, ApiResponse, AuthTokens, EventSourceOptions, FetchStreamAdapter, MemoryTokenStorage, RequestOptions, SaferCityApiError, SaferCityConfig, SaferCityJwtPayload, ServerSentEvent, StreamAdapter, TokenStorage, WebStreamAdapter, createAuthHeader, createStreamAdapter, getJwtExpiration, isTokenExpired, parseJwtPayload } from '@safercity/sdk-core';
2
+ import { SaferCityConfig, StreamAdapter, BaseClient, EventSourceOptions, ServerSentEvent, OAuthCredentials, TokenStorage } from '@safercity/sdk-core';
3
+ export { ApiError, ApiResponse, AuthMode, AuthTokens, ClientModeConfig, CookieModeConfig, DirectModeConfig, EventSourceOptions, FetchStreamAdapter, MemoryTokenStorage, OAuthCredentials, ProxyModeConfig, RequestOptions, SaferCityApiError, SaferCityConfig, SaferCityJwtPayload, ServerSentEvent, StreamAdapter, TokenManager, TokenManagerConfig, TokenStorage, WebStreamAdapter, createAuthHeader, createStreamAdapter, getJwtExpiration, isTokenExpired, parseJwtPayload } from '@safercity/sdk-core';
4
4
 
5
5
  interface SaferCityClientOptions extends SaferCityConfig {
6
6
  /**
@@ -460,4 +460,218 @@ declare function createSaferCityClient(options: SaferCityClientOptions): {
460
460
  };
461
461
  type SaferCityClient = ReturnType<typeof createSaferCityClient>;
462
462
 
463
- export { type SaferCityClient, type SaferCityClientOptions, createSaferCityClient };
463
+ /**
464
+ * Server-side SaferCity Client
465
+ *
466
+ * For backend applications that need to authenticate with OAuth client credentials.
467
+ * Handles automatic token management and refresh.
468
+ */
469
+
470
+ interface ServerClientConfig {
471
+ /**
472
+ * SaferCity API base URL
473
+ * @default "https://api.safercity.com"
474
+ */
475
+ baseUrl?: string;
476
+ /**
477
+ * OAuth credentials for authentication
478
+ */
479
+ auth: OAuthCredentials;
480
+ /**
481
+ * Custom token storage (defaults to in-memory)
482
+ */
483
+ tokenStore?: TokenStorage;
484
+ /**
485
+ * Request timeout in milliseconds
486
+ * @default 30000
487
+ */
488
+ timeout?: number;
489
+ /**
490
+ * Custom fetch implementation
491
+ */
492
+ fetch?: typeof fetch;
493
+ }
494
+ /**
495
+ * Server client that wraps the base client with automatic OAuth token management
496
+ */
497
+ declare class ServerClient extends BaseClient {
498
+ private tokenManager;
499
+ constructor(config: ServerClientConfig);
500
+ /**
501
+ * Get a valid access token
502
+ */
503
+ getAccessToken(): Promise<string>;
504
+ /**
505
+ * Force refresh the token
506
+ */
507
+ refreshToken(): Promise<string>;
508
+ /**
509
+ * Clear stored tokens
510
+ */
511
+ clearTokens(): void;
512
+ /**
513
+ * Make an authenticated request
514
+ * Automatically adds the Authorization header with a valid token
515
+ */
516
+ protected request<T>(method: string, path: string, options?: Parameters<BaseClient['request']>[2]): Promise<{
517
+ data: T;
518
+ status: number;
519
+ headers: Headers;
520
+ }>;
521
+ }
522
+ /**
523
+ * Create a server-side SaferCity client with automatic OAuth token management
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * const client = createServerClient({
528
+ * auth: {
529
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
530
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
531
+ * },
532
+ * });
533
+ *
534
+ * // All requests are automatically authenticated
535
+ * const users = await client.get('/v1/users');
536
+ * ```
537
+ */
538
+ declare function createServerClient(config: ServerClientConfig): ServerClient;
539
+
540
+ /**
541
+ * Proxy Middleware Helpers
542
+ *
543
+ * Helpers for creating proxy endpoints that forward requests to SaferCity API
544
+ * with automatic tenant authentication.
545
+ */
546
+
547
+ interface ProxyConfig {
548
+ /**
549
+ * OAuth client ID
550
+ */
551
+ clientId: string;
552
+ /**
553
+ * OAuth client secret
554
+ */
555
+ clientSecret: string;
556
+ /**
557
+ * SaferCity API base URL
558
+ * @default "https://api.safercity.com"
559
+ */
560
+ baseUrl?: string;
561
+ /**
562
+ * Tenant ID (optional, can be extracted from request)
563
+ */
564
+ tenantId?: string;
565
+ /**
566
+ * Custom token storage
567
+ */
568
+ tokenStore?: TokenStorage;
569
+ /**
570
+ * Path prefix to strip from incoming requests
571
+ * @default "/api/safercity"
572
+ */
573
+ pathPrefix?: string;
574
+ /**
575
+ * Headers to forward from the original request
576
+ * @default ["content-type", "accept", "x-request-id"]
577
+ */
578
+ forwardHeaders?: string[];
579
+ /**
580
+ * Custom fetch implementation
581
+ */
582
+ fetch?: typeof fetch;
583
+ }
584
+ /**
585
+ * Create a Next.js App Router handler for proxying SaferCity API requests
586
+ *
587
+ * @example
588
+ * ```typescript
589
+ * // app/api/safercity/[...path]/route.ts
590
+ * import { createNextHandler } from "@safercity/sdk";
591
+ *
592
+ * const handler = createNextHandler({
593
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
594
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
595
+ * });
596
+ *
597
+ * export { handler as GET, handler as POST, handler as PUT, handler as DELETE, handler as PATCH };
598
+ * ```
599
+ */
600
+ declare function createNextHandler(config: ProxyConfig): (request: Request) => Promise<Response>;
601
+ /**
602
+ * Express/Node.js compatible request type
603
+ */
604
+ interface ExpressRequest {
605
+ method: string;
606
+ path: string;
607
+ url: string;
608
+ headers: Record<string, string | string[] | undefined>;
609
+ body?: unknown;
610
+ query?: Record<string, string>;
611
+ }
612
+ /**
613
+ * Express/Node.js compatible response type
614
+ */
615
+ interface ExpressResponse {
616
+ status(code: number): ExpressResponse;
617
+ set(headers: Record<string, string>): ExpressResponse;
618
+ json(data: unknown): void;
619
+ send(data: string | ArrayBuffer | Uint8Array): void;
620
+ }
621
+ /**
622
+ * Express next function type
623
+ */
624
+ type NextFunction = (error?: unknown) => void;
625
+ /**
626
+ * Create an Express middleware for proxying SaferCity API requests
627
+ *
628
+ * @example
629
+ * ```typescript
630
+ * // Express middleware
631
+ * import express from "express";
632
+ * import { createExpressMiddleware } from "@safercity/sdk";
633
+ *
634
+ * const app = express();
635
+ *
636
+ * app.use(
637
+ * "/api/safercity",
638
+ * createExpressMiddleware({
639
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
640
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
641
+ * })
642
+ * );
643
+ * ```
644
+ */
645
+ declare function createExpressMiddleware(config: ProxyConfig): (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => Promise<void>;
646
+ /**
647
+ * Create a generic proxy handler that works with any framework
648
+ * Returns a function that takes a request and returns a response
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * const proxy = createProxyHandler({
653
+ * clientId: process.env.SAFERCITY_CLIENT_ID!,
654
+ * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
655
+ * });
656
+ *
657
+ * // Use with any framework
658
+ * const response = await proxy({
659
+ * method: "GET",
660
+ * path: "/v1/users",
661
+ * headers: {},
662
+ * });
663
+ * ```
664
+ */
665
+ declare function createProxyHandler(config: ProxyConfig): (request: {
666
+ method: string;
667
+ path: string;
668
+ headers?: Record<string, string>;
669
+ body?: unknown;
670
+ query?: Record<string, string>;
671
+ }) => Promise<{
672
+ status: number;
673
+ headers: Record<string, string>;
674
+ body: unknown;
675
+ }>;
676
+
677
+ export { type ProxyConfig, type SaferCityClient, type SaferCityClientOptions, ServerClient, type ServerClientConfig, createExpressMiddleware, createNextHandler, createProxyHandler, createSaferCityClient, createServerClient };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { BaseClient, createStreamAdapter } from '@safercity/sdk-core';
2
- export { FetchStreamAdapter, MemoryTokenStorage, SaferCityApiError, WebStreamAdapter, createAuthHeader, createStreamAdapter, getJwtExpiration, isTokenExpired, parseJwtPayload } from '@safercity/sdk-core';
1
+ import { BaseClient, createStreamAdapter, TokenManager } from '@safercity/sdk-core';
2
+ export { FetchStreamAdapter, MemoryTokenStorage, SaferCityApiError, TokenManager, WebStreamAdapter, createAuthHeader, createStreamAdapter, getJwtExpiration, isTokenExpired, parseJwtPayload } from '@safercity/sdk-core';
3
3
 
4
4
  function createSaferCityClient(options) {
5
5
  const baseClient = new BaseClient(options);
@@ -232,7 +232,231 @@ function createSaferCityClient(options) {
232
232
  }
233
233
  };
234
234
  }
235
+ var ServerClient = class extends BaseClient {
236
+ tokenManager;
237
+ constructor(config) {
238
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
239
+ super({
240
+ baseUrl,
241
+ timeout: config.timeout,
242
+ fetch: config.fetch
243
+ });
244
+ this.tokenManager = new TokenManager({
245
+ credentials: config.auth,
246
+ baseUrl,
247
+ storage: config.tokenStore,
248
+ fetch: config.fetch
249
+ });
250
+ }
251
+ /**
252
+ * Get a valid access token
253
+ */
254
+ async getAccessToken() {
255
+ return this.tokenManager.getToken();
256
+ }
257
+ /**
258
+ * Force refresh the token
259
+ */
260
+ async refreshToken() {
261
+ return this.tokenManager.forceRefresh();
262
+ }
263
+ /**
264
+ * Clear stored tokens
265
+ */
266
+ clearTokens() {
267
+ this.tokenManager.clear();
268
+ }
269
+ /**
270
+ * Make an authenticated request
271
+ * Automatically adds the Authorization header with a valid token
272
+ */
273
+ async request(method, path, options) {
274
+ const token = await this.getAccessToken();
275
+ const authHeaders = {
276
+ ...options?.headers,
277
+ Authorization: `Bearer ${token}`
278
+ };
279
+ return super.request(method, path, {
280
+ ...options,
281
+ headers: authHeaders
282
+ });
283
+ }
284
+ };
285
+ function createServerClient(config) {
286
+ return new ServerClient(config);
287
+ }
288
+ var tokenManagers = /* @__PURE__ */ new Map();
289
+ function getTokenManager(config) {
290
+ const key = `${config.clientId}:${config.baseUrl ?? "default"}`;
291
+ let manager = tokenManagers.get(key);
292
+ if (!manager) {
293
+ manager = new TokenManager({
294
+ credentials: {
295
+ clientId: config.clientId,
296
+ clientSecret: config.clientSecret,
297
+ tenantId: config.tenantId
298
+ },
299
+ baseUrl: config.baseUrl ?? "https://api.safercity.com",
300
+ storage: config.tokenStore,
301
+ fetch: config.fetch
302
+ });
303
+ tokenManagers.set(key, manager);
304
+ }
305
+ return manager;
306
+ }
307
+ function createNextHandler(config) {
308
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
309
+ const pathPrefix = config.pathPrefix ?? "/api/safercity";
310
+ const forwardHeaders = config.forwardHeaders ?? ["content-type", "accept", "x-request-id"];
311
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
312
+ return async function handler(request) {
313
+ const tokenManager = getTokenManager(config);
314
+ try {
315
+ const token = await tokenManager.getToken();
316
+ const url = new URL(request.url);
317
+ const path = url.pathname.replace(new RegExp(`^${pathPrefix}`), "");
318
+ const targetUrl = `${baseUrl}${path}${url.search}`;
319
+ const headers = {
320
+ Authorization: `Bearer ${token}`
321
+ };
322
+ for (const header of forwardHeaders) {
323
+ const value = request.headers.get(header);
324
+ if (value) {
325
+ headers[header] = value;
326
+ }
327
+ }
328
+ const tenantIdHeader = request.headers.get("x-tenant-id");
329
+ if (tenantIdHeader) {
330
+ headers["X-Tenant-ID"] = tenantIdHeader;
331
+ } else if (config.tenantId) {
332
+ headers["X-Tenant-ID"] = config.tenantId;
333
+ }
334
+ let body;
335
+ if (request.method !== "GET" && request.method !== "HEAD") {
336
+ body = await request.text();
337
+ }
338
+ const response = await fetchFn(targetUrl, {
339
+ method: request.method,
340
+ headers,
341
+ body
342
+ });
343
+ const responseHeaders = new Headers(response.headers);
344
+ responseHeaders.set("Access-Control-Allow-Origin", "*");
345
+ responseHeaders.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
346
+ responseHeaders.set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Tenant-ID");
347
+ return new Response(response.body, {
348
+ status: response.status,
349
+ statusText: response.statusText,
350
+ headers: responseHeaders
351
+ });
352
+ } catch (error) {
353
+ console.error("[SaferCity Proxy] Error:", error);
354
+ return new Response(
355
+ JSON.stringify({
356
+ error: "proxy_error",
357
+ message: error instanceof Error ? error.message : "Proxy request failed"
358
+ }),
359
+ {
360
+ status: 502,
361
+ headers: {
362
+ "Content-Type": "application/json"
363
+ }
364
+ }
365
+ );
366
+ }
367
+ };
368
+ }
369
+ function createExpressMiddleware(config) {
370
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
371
+ const forwardHeaders = config.forwardHeaders ?? ["content-type", "accept", "x-request-id"];
372
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
373
+ return async function middleware(req, res, next) {
374
+ const tokenManager = getTokenManager(config);
375
+ try {
376
+ const token = await tokenManager.getToken();
377
+ const targetUrl = `${baseUrl}${req.path}${req.url.includes("?") ? req.url.slice(req.url.indexOf("?")) : ""}`;
378
+ const headers = {
379
+ Authorization: `Bearer ${token}`
380
+ };
381
+ for (const header of forwardHeaders) {
382
+ const value = req.headers[header.toLowerCase()];
383
+ if (value) {
384
+ headers[header] = Array.isArray(value) ? value[0] : value;
385
+ }
386
+ }
387
+ const tenantIdHeader = req.headers["x-tenant-id"];
388
+ if (tenantIdHeader) {
389
+ headers["X-Tenant-ID"] = Array.isArray(tenantIdHeader) ? tenantIdHeader[0] : tenantIdHeader;
390
+ } else if (config.tenantId) {
391
+ headers["X-Tenant-ID"] = config.tenantId;
392
+ }
393
+ let body;
394
+ if (req.method !== "GET" && req.method !== "HEAD" && req.body) {
395
+ body = typeof req.body === "string" ? req.body : JSON.stringify(req.body);
396
+ }
397
+ const response = await fetchFn(targetUrl, {
398
+ method: req.method,
399
+ headers,
400
+ body
401
+ });
402
+ const contentType = response.headers.get("content-type");
403
+ const responseBody = contentType?.includes("application/json") ? await response.json() : await response.text();
404
+ res.status(response.status);
405
+ res.set({
406
+ "Access-Control-Allow-Origin": "*",
407
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
408
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Tenant-ID",
409
+ "Content-Type": contentType ?? "application/json"
410
+ });
411
+ if (typeof responseBody === "string") {
412
+ res.send(responseBody);
413
+ } else {
414
+ res.json(responseBody);
415
+ }
416
+ } catch (error) {
417
+ console.error("[SaferCity Proxy] Error:", error);
418
+ next(error);
419
+ }
420
+ };
421
+ }
422
+ function createProxyHandler(config) {
423
+ const baseUrl = config.baseUrl ?? "https://api.safercity.com";
424
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
425
+ return async function proxy(request) {
426
+ const tokenManager = getTokenManager(config);
427
+ const token = await tokenManager.getToken();
428
+ let targetUrl = `${baseUrl}${request.path}`;
429
+ if (request.query && Object.keys(request.query).length > 0) {
430
+ const params = new URLSearchParams(request.query);
431
+ targetUrl += `?${params.toString()}`;
432
+ }
433
+ const headers = {
434
+ Authorization: `Bearer ${token}`,
435
+ "Content-Type": "application/json",
436
+ ...request.headers
437
+ };
438
+ if (config.tenantId) {
439
+ headers["X-Tenant-ID"] = config.tenantId;
440
+ }
441
+ const response = await fetchFn(targetUrl, {
442
+ method: request.method,
443
+ headers,
444
+ body: request.body ? JSON.stringify(request.body) : void 0
445
+ });
446
+ const contentType = response.headers.get("content-type");
447
+ const body = contentType?.includes("application/json") ? await response.json() : await response.text();
448
+ const responseHeaders = {};
449
+ response.headers.forEach((value, key) => {
450
+ responseHeaders[key] = value;
451
+ });
452
+ return {
453
+ status: response.status,
454
+ headers: responseHeaders,
455
+ body
456
+ };
457
+ };
458
+ }
235
459
 
236
- export { createSaferCityClient };
460
+ export { ServerClient, createExpressMiddleware, createNextHandler, createProxyHandler, createSaferCityClient, createServerClient };
237
461
  //# sourceMappingURL=index.js.map
238
462
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":["options"],"mappings":"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","file":"index.js","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"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/server.ts","../src/proxy.ts"],"names":["options","BaseClient","TokenManager"],"mappings":"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","file":"index.js","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@safercity/sdk",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Official SaferCity API client for TypeScript/JavaScript",
5
5
  "license": "MIT",
6
6
  "author": {