@safercity/sdk-react 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -35
- package/package.json +3 -8
package/README.md
CHANGED
|
@@ -10,9 +10,31 @@ npm install @safercity/sdk-react @tanstack/react-query
|
|
|
10
10
|
bun add @safercity/sdk-react @tanstack/react-query
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Authentication Modes
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The provider supports three authentication modes. Choose the one that fits your architecture:
|
|
16
|
+
|
|
17
|
+
### Proxy Mode (Default - Most Secure)
|
|
18
|
+
|
|
19
|
+
Client -> Your Backend -> SaferCity API. Your backend handles credentials.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { SaferCityProvider } from '@safercity/sdk-react';
|
|
23
|
+
|
|
24
|
+
function App() {
|
|
25
|
+
return (
|
|
26
|
+
<SaferCityProvider mode="proxy" proxyBaseUrl="/api/safercity">
|
|
27
|
+
<YourApp />
|
|
28
|
+
</SaferCityProvider>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Set up the proxy on your backend with `createNextHandler` or `createExpressMiddleware` from `@safercity/sdk`.
|
|
34
|
+
|
|
35
|
+
### Direct Mode
|
|
36
|
+
|
|
37
|
+
Client -> SaferCity API with an external auth token. For white-label apps using Clerk, Auth0, better-auth, etc.
|
|
16
38
|
|
|
17
39
|
```tsx
|
|
18
40
|
import { SaferCityProvider } from '@safercity/sdk-react';
|
|
@@ -20,9 +42,10 @@ import { SaferCityProvider } from '@safercity/sdk-react';
|
|
|
20
42
|
function App() {
|
|
21
43
|
return (
|
|
22
44
|
<SaferCityProvider
|
|
45
|
+
mode="direct"
|
|
23
46
|
baseUrl="https://api.safercity.com"
|
|
24
|
-
token={userToken}
|
|
25
47
|
tenantId="tenant-123"
|
|
48
|
+
getAccessToken={() => session?.accessToken}
|
|
26
49
|
>
|
|
27
50
|
<YourApp />
|
|
28
51
|
</SaferCityProvider>
|
|
@@ -30,7 +53,84 @@ function App() {
|
|
|
30
53
|
}
|
|
31
54
|
```
|
|
32
55
|
|
|
33
|
-
|
|
56
|
+
The provider automatically refreshes the token every 30 seconds by calling `getAccessToken`.
|
|
57
|
+
|
|
58
|
+
### Cookie Mode
|
|
59
|
+
|
|
60
|
+
Browser with `credentials: include`. For first-party web apps using session cookies.
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { SaferCityProvider } from '@safercity/sdk-react';
|
|
64
|
+
|
|
65
|
+
function App() {
|
|
66
|
+
return (
|
|
67
|
+
<SaferCityProvider mode="cookie" baseUrl="https://api.safercity.com">
|
|
68
|
+
<YourApp />
|
|
69
|
+
</SaferCityProvider>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The provider automatically checks session status on mount via `/v1/auth/session/status`.
|
|
75
|
+
|
|
76
|
+
### Legacy Mode
|
|
77
|
+
|
|
78
|
+
For backward compatibility, you can still pass `baseUrl` and `token` directly without a `mode`:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<SaferCityProvider baseUrl="https://api.safercity.com" token={userToken} tenantId="tenant-123">
|
|
82
|
+
<YourApp />
|
|
83
|
+
</SaferCityProvider>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Session Management (Cookie Mode)
|
|
87
|
+
|
|
88
|
+
When using cookie mode, the provider exposes session management hooks:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { useSession, useSessionManager, useAuthMode } from '@safercity/sdk-react';
|
|
92
|
+
|
|
93
|
+
function AuthStatus() {
|
|
94
|
+
const session = useSession();
|
|
95
|
+
const mode = useAuthMode(); // "proxy" | "direct" | "cookie"
|
|
96
|
+
|
|
97
|
+
if (session.isLoading) return <div>Loading...</div>;
|
|
98
|
+
if (session.error) return <div>Error: {session.error.message}</div>;
|
|
99
|
+
|
|
100
|
+
return <div>Authenticated: {session.isAuthenticated ? 'Yes' : 'No'}</div>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function LoginButton() {
|
|
104
|
+
const { createSession, clearSession, refreshCsrf, isAuthenticated } = useSessionManager();
|
|
105
|
+
|
|
106
|
+
const handleLogin = async (externalToken: string) => {
|
|
107
|
+
await createSession(externalToken, 'tenant-123');
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleLogout = async () => {
|
|
111
|
+
await clearSession();
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return isAuthenticated
|
|
115
|
+
? <button onClick={handleLogout}>Logout</button>
|
|
116
|
+
: <button onClick={() => handleLogin('...')}>Login</button>;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### SessionState
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
interface SessionState {
|
|
124
|
+
isAuthenticated: boolean;
|
|
125
|
+
isLoading: boolean;
|
|
126
|
+
userId?: string;
|
|
127
|
+
tenantId?: string;
|
|
128
|
+
expiresAt?: number;
|
|
129
|
+
error?: Error;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Using Hooks
|
|
34
134
|
|
|
35
135
|
```tsx
|
|
36
136
|
import { useUsers, usePanics, useCreatePanic } from '@safercity/sdk-react';
|
|
@@ -68,32 +168,16 @@ function PanicButton({ userId }: { userId: string }) {
|
|
|
68
168
|
}
|
|
69
169
|
```
|
|
70
170
|
|
|
71
|
-
## Streaming Hook
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
import { usePanicStream } from '@safercity/sdk-react';
|
|
75
|
-
|
|
76
|
-
function PanicTracker({ panicId }: { panicId: string }) {
|
|
77
|
-
const { data, isConnected, error, events } = usePanicStream(panicId, {
|
|
78
|
-
keepHistory: true,
|
|
79
|
-
onEvent: (event) => console.log('Update:', event),
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (error) return <div>Error: {error.message}</div>;
|
|
83
|
-
if (!isConnected) return <div>Connecting...</div>;
|
|
84
|
-
|
|
85
|
-
return (
|
|
86
|
-
<div>
|
|
87
|
-
<p>Latest: {data?.data}</p>
|
|
88
|
-
<p>Total events: {events.length}</p>
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
171
|
## Available Hooks
|
|
95
172
|
|
|
96
|
-
###
|
|
173
|
+
### Provider Hooks
|
|
174
|
+
- `useSaferCity()` - Full context (client, mode, session, session management)
|
|
175
|
+
- `useSaferCityClient()` - SaferCity client instance
|
|
176
|
+
- `useSession()` - Session state (cookie mode)
|
|
177
|
+
- `useAuthMode()` - Current auth mode (`"proxy"` | `"direct"` | `"cookie"`)
|
|
178
|
+
- `useSessionManager()` - Session management functions (cookie mode)
|
|
179
|
+
|
|
180
|
+
### Health and Auth
|
|
97
181
|
- `useHealthCheck()` - API health status
|
|
98
182
|
- `useWhoAmI()` - Current auth context
|
|
99
183
|
|
|
@@ -126,12 +210,36 @@ function PanicTracker({ panicId }: { panicId: string }) {
|
|
|
126
210
|
- `useCrimeCategories()` - Get crime categories
|
|
127
211
|
- `useCrimeTypes()` - Get crime types
|
|
128
212
|
|
|
213
|
+
## Streaming Hook
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import { usePanicStream } from '@safercity/sdk-react';
|
|
217
|
+
|
|
218
|
+
function PanicTracker({ panicId }: { panicId: string }) {
|
|
219
|
+
const { data, isConnected, error, events } = usePanicStream(panicId, {
|
|
220
|
+
keepHistory: true,
|
|
221
|
+
onEvent: (event) => console.log('Update:', event),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
225
|
+
if (!isConnected) return <div>Connecting...</div>;
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<div>
|
|
229
|
+
<p>Latest: {data?.data}</p>
|
|
230
|
+
<p>Total events: {events.length}</p>
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
129
236
|
## Query Keys
|
|
130
237
|
|
|
131
238
|
Use query keys for manual cache management:
|
|
132
239
|
|
|
133
240
|
```tsx
|
|
134
|
-
import { saferCityKeys
|
|
241
|
+
import { saferCityKeys } from '@safercity/sdk-react';
|
|
242
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
135
243
|
|
|
136
244
|
function RefreshButton() {
|
|
137
245
|
const queryClient = useQueryClient();
|
|
@@ -164,11 +272,7 @@ const queryClient = new QueryClient({
|
|
|
164
272
|
|
|
165
273
|
function App() {
|
|
166
274
|
return (
|
|
167
|
-
<SaferCityProvider
|
|
168
|
-
baseUrl="https://api.safercity.com"
|
|
169
|
-
token={token}
|
|
170
|
-
queryClient={queryClient}
|
|
171
|
-
>
|
|
275
|
+
<SaferCityProvider mode="proxy" proxyBaseUrl="/api/safercity" queryClient={queryClient}>
|
|
172
276
|
<YourApp />
|
|
173
277
|
</SaferCityProvider>
|
|
174
278
|
);
|
|
@@ -184,7 +288,6 @@ function CustomComponent() {
|
|
|
184
288
|
const client = useSaferCityClient();
|
|
185
289
|
|
|
186
290
|
const customRequest = async () => {
|
|
187
|
-
// Use raw client for custom requests
|
|
188
291
|
const response = await client._client.get('/custom-endpoint');
|
|
189
292
|
return response.data;
|
|
190
293
|
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@safercity/sdk-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React hooks and components for SaferCity SDK with TanStack Query integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "SaferCity"
|
|
8
8
|
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "https://github.com/safercity/safercity-v2.git",
|
|
12
|
-
"directory": "packages/sdk/react"
|
|
13
|
-
},
|
|
14
9
|
"keywords": ["safercity", "sdk", "react", "hooks", "tanstack-query"],
|
|
15
10
|
"sideEffects": false,
|
|
16
11
|
"type": "module",
|
|
@@ -41,8 +36,8 @@
|
|
|
41
36
|
"prepublishOnly": "bun run build"
|
|
42
37
|
},
|
|
43
38
|
"dependencies": {
|
|
44
|
-
"@safercity/sdk": "
|
|
45
|
-
"@safercity/sdk-core": "
|
|
39
|
+
"@safercity/sdk": "^0.1.2",
|
|
40
|
+
"@safercity/sdk-core": "^0.1.2"
|
|
46
41
|
},
|
|
47
42
|
"peerDependencies": {
|
|
48
43
|
"@tanstack/react-query": ">=5.0.0",
|