@safercity/sdk 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -49
- package/dist/index.cjs +510 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +724 -91
- package/dist/index.d.ts +724 -91
- package/dist/index.js +510 -88
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Official SaferCity API client for TypeScript/JavaScript.
|
|
4
4
|
|
|
5
|
+
## What's New in v0.2.0
|
|
6
|
+
|
|
7
|
+
- **User-Scoped Client** - The main client is now user-scoped (Stripe publishable key pattern). Admin operations moved to `ServerClient`.
|
|
8
|
+
- **Panic Information** - Full CRUD for user panic profiles and emergency contacts.
|
|
9
|
+
- **Proxy Enhancements** - Added allowlist/blocklist support for proxy endpoints.
|
|
10
|
+
- **Automatic Scoping** - Client now tracks `userId` and automatically scopes requests.
|
|
11
|
+
- **Path Alignment** - All SDK paths now match the latest API schema (singular `/v1/panic`, etc.).
|
|
12
|
+
|
|
13
|
+
## What's New in v0.1.3
|
|
14
|
+
|
|
15
|
+
- **OAuth endpoint path fix** - Fixed paths (`/oauth/*` → `/v1/oauth/*`)
|
|
16
|
+
- **ServerClient domain helpers** - Added typed domain helpers to `ServerClient`
|
|
17
|
+
- **Security hardening** - Removed `panics.list()` and `subscriptions.stats()` from client-side SDK (available on `ServerClient` only)
|
|
18
|
+
|
|
5
19
|
## Installation
|
|
6
20
|
|
|
7
21
|
```bash
|
|
@@ -40,10 +54,12 @@ const client = createSaferCityClient({
|
|
|
40
54
|
baseUrl: 'https://api.safercity.com',
|
|
41
55
|
token: externalAuthToken,
|
|
42
56
|
tenantId: 'your-tenant-id',
|
|
57
|
+
userId: 'user-123', // optional, for auto-scoping
|
|
43
58
|
});
|
|
44
59
|
|
|
45
|
-
// Update token when
|
|
60
|
+
// Update token or user when they change
|
|
46
61
|
client.setToken(newToken);
|
|
62
|
+
client.setUserId(newUserId);
|
|
47
63
|
```
|
|
48
64
|
|
|
49
65
|
### Cookie Mode
|
|
@@ -54,6 +70,7 @@ Browser with `credentials: include`. For first-party web apps using session cook
|
|
|
54
70
|
const client = createSaferCityClient({
|
|
55
71
|
baseUrl: 'https://api.safercity.com',
|
|
56
72
|
tenantId: 'your-tenant-id',
|
|
73
|
+
userId: 'user-123', // optional
|
|
57
74
|
});
|
|
58
75
|
```
|
|
59
76
|
|
|
@@ -72,13 +89,12 @@ const client = createSaferCityClient({
|
|
|
72
89
|
const { data: health } = await client.health.check();
|
|
73
90
|
console.log('API Status:', health.status);
|
|
74
91
|
|
|
75
|
-
// Get user
|
|
76
|
-
const { data: user } = await client.users.get(
|
|
92
|
+
// Get user (auto-resolves userId from client if not passed)
|
|
93
|
+
const { data: user } = await client.users.get();
|
|
77
94
|
console.log('User:', user);
|
|
78
95
|
|
|
79
|
-
// Create panic
|
|
96
|
+
// Create panic (userId is optional if set on client)
|
|
80
97
|
const { data: panic } = await client.panics.create({
|
|
81
|
-
userId: 'user-123',
|
|
82
98
|
latitude: -26.2041,
|
|
83
99
|
longitude: 28.0473,
|
|
84
100
|
});
|
|
@@ -104,7 +120,26 @@ const client = createServerClient({
|
|
|
104
120
|
|
|
105
121
|
// All requests are automatically authenticated with OAuth tokens
|
|
106
122
|
// Tokens are refreshed automatically before expiration
|
|
107
|
-
const users = await client.
|
|
123
|
+
const { data: users } = await client.users.list(); // Admin only
|
|
124
|
+
const { data: panic } = await client.panics.create({
|
|
125
|
+
userId: 'user-123',
|
|
126
|
+
latitude: -26.2041,
|
|
127
|
+
longitude: 28.0473,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// ServerClient has ALL endpoints including admin-only ones:
|
|
131
|
+
// - client.oauth.*
|
|
132
|
+
// - client.tenants.*
|
|
133
|
+
// - client.credentials.*
|
|
134
|
+
// - client.users.list()
|
|
135
|
+
// - client.users.delete()
|
|
136
|
+
// - client.users.updateStatus()
|
|
137
|
+
// - client.panics.list()
|
|
138
|
+
// - client.subscriptions.stats()
|
|
139
|
+
// - client.panicInformation.list()
|
|
140
|
+
|
|
141
|
+
// Low-level requests still work too
|
|
142
|
+
const response = await client.get('/v1/custom-endpoint');
|
|
108
143
|
|
|
109
144
|
// Manual token control
|
|
110
145
|
const token = await client.getAccessToken();
|
|
@@ -112,6 +147,8 @@ await client.refreshToken();
|
|
|
112
147
|
client.clearTokens();
|
|
113
148
|
```
|
|
114
149
|
|
|
150
|
+
> **Note**: The `ServerClient` includes `panics.list()` and `subscriptions.stats()` which are not available on the client-side SDK for security reasons.
|
|
151
|
+
|
|
115
152
|
### ServerClientConfig
|
|
116
153
|
|
|
117
154
|
```typescript
|
|
@@ -191,26 +228,15 @@ interface ProxyConfig {
|
|
|
191
228
|
pathPrefix?: string; // default: "/api/safercity"
|
|
192
229
|
forwardHeaders?: string[]; // default: ["content-type", "accept", "x-request-id"]
|
|
193
230
|
fetch?: typeof fetch;
|
|
231
|
+
allowedEndpoints?: EndpointPattern[]; // Explicit allowlist
|
|
232
|
+
blockedEndpoints?: EndpointPattern[]; // Explicit blocklist
|
|
194
233
|
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## OAuth Token Flow
|
|
198
234
|
|
|
199
|
-
|
|
200
|
-
const client = createSaferCityClient({
|
|
201
|
-
baseUrl: 'https://api.safercity.com',
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// Get access token
|
|
205
|
-
const { data: tokens } = await client.oauth.token({
|
|
206
|
-
grant_type: 'client_credentials',
|
|
207
|
-
tenantId: 'your-tenant-id',
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
// Set token on client
|
|
211
|
-
client.setToken(tokens.access_token);
|
|
235
|
+
type EndpointPattern = string | { method?: string; path: string };
|
|
212
236
|
```
|
|
213
237
|
|
|
238
|
+
Allowlist takes precedence over blocklist. Patterns match by path prefix (case-insensitive).
|
|
239
|
+
|
|
214
240
|
## Streaming (SSE)
|
|
215
241
|
|
|
216
242
|
Stream real-time panic updates:
|
|
@@ -230,56 +256,51 @@ for await (const event of client.panics.streamUpdates('panic-123')) {
|
|
|
230
256
|
- `client.auth.whoami()` - Get current auth context
|
|
231
257
|
- `client.auth.check()` - Check if authenticated (optional auth)
|
|
232
258
|
|
|
233
|
-
###
|
|
234
|
-
- `client.oauth.token(body)` - Get access token
|
|
235
|
-
- `client.oauth.refresh(body)` - Refresh token
|
|
236
|
-
- `client.oauth.introspect(body)` - Introspect token
|
|
237
|
-
- `client.oauth.revoke(body)` - Revoke token
|
|
238
|
-
|
|
239
|
-
### Tenants
|
|
240
|
-
- `client.tenants.create(body)` - Create a new tenant
|
|
241
|
-
- `client.tenants.list(query?)` - List tenants
|
|
242
|
-
|
|
243
|
-
### Credentials
|
|
244
|
-
- `client.credentials.setup(body)` - Exchange setup token for credentials
|
|
245
|
-
- `client.credentials.list()` - List credentials
|
|
246
|
-
- `client.credentials.revoke(credentialId)` - Revoke credential
|
|
247
|
-
|
|
248
|
-
### Users
|
|
259
|
+
### Users (User-Scoped)
|
|
249
260
|
- `client.users.create(body)` - Create user
|
|
250
|
-
- `client.users.
|
|
251
|
-
- `client.users.
|
|
252
|
-
- `client.users.update(userId, body)` - Update user
|
|
253
|
-
- `client.users.updateStatus(userId, body)` - Update user status
|
|
254
|
-
- `client.users.delete(userId)` - Delete user
|
|
261
|
+
- `client.users.get(userId?)` - Get user by ID (defaults to client's `userId`)
|
|
262
|
+
- `client.users.update(userId?, body)` - Update user (defaults to client's `userId`)
|
|
255
263
|
|
|
256
264
|
### Panics
|
|
257
265
|
- `client.panics.create(body)` - Create panic
|
|
258
266
|
- `client.panics.get(panicId, query?)` - Get panic
|
|
259
|
-
- `client.panics.list(query?)` - List panics
|
|
260
267
|
- `client.panics.updateLocation(panicId, body)` - Update location
|
|
261
268
|
- `client.panics.cancel(panicId, body)` - Cancel panic
|
|
269
|
+
- `client.panics.types(userId?)` - Get available panic types for a user
|
|
262
270
|
- `client.panics.streamUpdates(panicId, options?)` - Stream updates (SSE)
|
|
263
271
|
|
|
272
|
+
### Panic Information
|
|
273
|
+
- `client.panicInformation.create(body)` - Create panic profile
|
|
274
|
+
- `client.panicInformation.get(id)` - Get profile by ID
|
|
275
|
+
- `client.panicInformation.getByUser(userId?)` - Get profile by user ID
|
|
276
|
+
- `client.panicInformation.update(id, body)` - Update profile
|
|
277
|
+
- `client.panicInformation.delete(id)` - Delete profile
|
|
278
|
+
- `client.panicInformation.validateEligibility(userId?)` - Check if user is eligible for panic services
|
|
279
|
+
|
|
264
280
|
### Subscriptions
|
|
265
281
|
- `client.subscriptions.listTypes()` - List subscription types
|
|
266
282
|
- `client.subscriptions.create(body)` - Create subscription
|
|
267
|
-
- `client.subscriptions.list(query?)` - List subscriptions
|
|
268
|
-
- `client.subscriptions.
|
|
283
|
+
- `client.subscriptions.list(query?)` - List subscriptions for a user
|
|
284
|
+
- `client.subscriptions.subscribeUser(body)` - Shorthand to subscribe a user
|
|
269
285
|
|
|
270
286
|
### Notifications
|
|
271
287
|
- `client.notifications.createSubscriber(body)` - Create subscriber
|
|
272
288
|
- `client.notifications.trigger(body)` - Trigger notification
|
|
273
|
-
- `client.notifications.
|
|
274
|
-
- `client.notifications.
|
|
289
|
+
- `client.notifications.bulkTrigger(body)` - Bulk trigger notifications
|
|
290
|
+
- `client.notifications.getPreferences(userId?)` - Get user preferences
|
|
291
|
+
- `client.notifications.updatePreferences(userId?, body)` - Update preferences
|
|
275
292
|
|
|
276
293
|
### Location Safety
|
|
277
|
-
- `client.locationSafety.check(
|
|
294
|
+
- `client.locationSafety.check(body)` - Check location safety (POST)
|
|
295
|
+
|
|
296
|
+
### Banner
|
|
297
|
+
- `client.banner.get(body)` - Get crime banner data for a location
|
|
278
298
|
|
|
279
299
|
### Crimes
|
|
280
300
|
- `client.crimes.list(query?)` - List crimes
|
|
281
301
|
- `client.crimes.categories()` - Get crime categories
|
|
282
302
|
- `client.crimes.types()` - Get crime types
|
|
303
|
+
- `client.crimes.categoriesWithTypes()` - Get categories with nested types
|
|
283
304
|
|
|
284
305
|
## Error Handling
|
|
285
306
|
|