@prmichaelsen/agentbase-core 0.1.1 → 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 +204 -87
- package/dist/client/api-types.generated.d.ts +4024 -0
- package/dist/client/api-types.generated.d.ts.map +1 -0
- package/dist/client/api-types.generated.js +6 -0
- package/dist/client/api-types.generated.js.map +1 -0
- package/dist/client/app.d.ts +126 -0
- package/dist/client/app.d.ts.map +1 -0
- package/dist/client/app.js +107 -0
- package/dist/client/app.js.map +1 -0
- package/dist/client/http-transport.d.ts +42 -0
- package/dist/client/http-transport.d.ts.map +1 -0
- package/dist/client/http-transport.js +113 -0
- package/dist/client/http-transport.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/oauth.d.ts +86 -0
- package/dist/client/oauth.d.ts.map +1 -0
- package/dist/client/oauth.js +148 -0
- package/dist/client/oauth.js.map +1 -0
- package/dist/client/svc.d.ts +511 -0
- package/dist/client/svc.d.ts.map +1 -0
- package/dist/client/svc.js +409 -0
- package/dist/client/svc.js.map +1 -0
- package/dist/config/index.d.ts +34 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +50 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors/app-errors.d.ts +34 -0
- package/dist/errors/app-errors.d.ts.map +1 -0
- package/dist/errors/app-errors.js +34 -0
- package/dist/errors/app-errors.js.map +1 -0
- package/dist/errors/base.error.d.ts +8 -0
- package/dist/errors/base.error.d.ts.map +1 -0
- package/dist/errors/base.error.js +9 -0
- package/dist/errors/base.error.js.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +12 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/auth/error-handler.d.ts +6 -0
- package/dist/lib/auth/error-handler.d.ts.map +1 -0
- package/dist/lib/auth/error-handler.js +18 -0
- package/dist/lib/auth/error-handler.js.map +1 -0
- package/dist/lib/auth/guards.d.ts +5 -6
- package/dist/lib/auth/guards.d.ts.map +1 -1
- package/dist/lib/auth/guards.js +7 -18
- package/dist/lib/auth/guards.js.map +1 -1
- package/dist/lib/auth/index.d.ts +1 -0
- package/dist/lib/auth/index.d.ts.map +1 -1
- package/dist/lib/auth/index.js +1 -0
- package/dist/lib/auth/index.js.map +1 -1
- package/dist/lib/auth/session.d.ts.map +1 -1
- package/dist/lib/auth/session.js +8 -7
- package/dist/lib/auth/session.js.map +1 -1
- package/dist/lib/rate-limiter.d.ts.map +1 -1
- package/dist/lib/rate-limiter.js +2 -1
- package/dist/lib/rate-limiter.js.map +1 -1
- package/dist/services/auth.interface.d.ts +15 -0
- package/dist/services/auth.interface.d.ts.map +1 -0
- package/dist/services/auth.interface.js +2 -0
- package/dist/services/auth.interface.js.map +1 -0
- package/dist/services/base.service.d.ts +17 -1
- package/dist/services/base.service.d.ts.map +1 -1
- package/dist/services/base.service.js +26 -3
- package/dist/services/base.service.js.map +1 -1
- package/dist/services/confirmation-token.service.d.ts +5 -1
- package/dist/services/confirmation-token.service.d.ts.map +1 -1
- package/dist/services/confirmation-token.service.js.map +1 -1
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/types/branded.d.ts +24 -0
- package/dist/types/branded.d.ts.map +1 -0
- package/dist/types/branded.js +9 -0
- package/dist/types/branded.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/result.d.ts +20 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +44 -0
- package/dist/types/result.js.map +1 -0
- package/package.json +16 -2
- package/dist/lib/auth/guards.test.d.ts +0 -2
- package/dist/lib/auth/guards.test.d.ts.map +0 -1
- package/dist/lib/auth/guards.test.js +0 -105
- package/dist/lib/auth/guards.test.js.map +0 -1
- package/dist/lib/auth/helpers.test.d.ts +0 -2
- package/dist/lib/auth/helpers.test.d.ts.map +0 -1
- package/dist/lib/auth/helpers.test.js +0 -43
- package/dist/lib/auth/helpers.test.js.map +0 -1
- package/dist/lib/auth/session.test.d.ts +0 -2
- package/dist/lib/auth/session.test.d.ts.map +0 -1
- package/dist/lib/auth/session.test.js +0 -114
- package/dist/lib/auth/session.test.js.map +0 -1
- package/dist/lib/firebase-admin.test.d.ts +0 -2
- package/dist/lib/firebase-admin.test.d.ts.map +0 -1
- package/dist/lib/firebase-admin.test.js +0 -36
- package/dist/lib/firebase-admin.test.js.map +0 -1
- package/dist/lib/firebase-client.test.d.ts +0 -2
- package/dist/lib/firebase-client.test.d.ts.map +0 -1
- package/dist/lib/firebase-client.test.js +0 -167
- package/dist/lib/firebase-client.test.js.map +0 -1
- package/dist/lib/format-time.test.d.ts +0 -2
- package/dist/lib/format-time.test.d.ts.map +0 -1
- package/dist/lib/format-time.test.js +0 -41
- package/dist/lib/format-time.test.js.map +0 -1
- package/dist/lib/linkify.test.d.ts +0 -2
- package/dist/lib/linkify.test.d.ts.map +0 -1
- package/dist/lib/linkify.test.js +0 -40
- package/dist/lib/linkify.test.js.map +0 -1
- package/dist/lib/logger.test.d.ts +0 -2
- package/dist/lib/logger.test.d.ts.map +0 -1
- package/dist/lib/logger.test.js +0 -167
- package/dist/lib/logger.test.js.map +0 -1
- package/dist/lib/rate-limiter.test.d.ts +0 -2
- package/dist/lib/rate-limiter.test.d.ts.map +0 -1
- package/dist/lib/rate-limiter.test.js +0 -70
- package/dist/lib/rate-limiter.test.js.map +0 -1
- package/dist/lib/uuid.test.d.ts +0 -2
- package/dist/lib/uuid.test.d.ts.map +0 -1
- package/dist/lib/uuid.test.js +0 -22
- package/dist/lib/uuid.test.js.map +0 -1
- package/dist/services/base.service.test.d.ts +0 -2
- package/dist/services/base.service.test.d.ts.map +0 -1
- package/dist/services/base.service.test.js +0 -62
- package/dist/services/base.service.test.js.map +0 -1
- package/dist/services/confirmation-token.service.test.d.ts +0 -2
- package/dist/services/confirmation-token.service.test.d.ts.map +0 -1
- package/dist/services/confirmation-token.service.test.js +0 -65
- package/dist/services/confirmation-token.service.test.js.map +0 -1
- package/dist/smoke.test.d.ts +0 -2
- package/dist/smoke.test.d.ts.map +0 -1
- package/dist/smoke.test.js +0 -7
- package/dist/smoke.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @prmichaelsen/agentbase-core
|
|
2
2
|
|
|
3
|
-
Shared service infrastructure for agentbase projects — BaseService, auth, Firebase wrappers, logging, and common utilities.
|
|
3
|
+
Shared service infrastructure for agentbase projects — BaseService, auth, Firebase wrappers, logging, typed errors, Result type, client SDK, and common utilities.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -25,33 +25,40 @@ import { ... } from '@prmichaelsen/agentbase-core' // everything
|
|
|
25
25
|
import { ... } from '@prmichaelsen/agentbase-core/services' // BaseService, ConfirmationTokenService
|
|
26
26
|
import { ... } from '@prmichaelsen/agentbase-core/lib' // logger, firebase, utilities
|
|
27
27
|
import { ... } from '@prmichaelsen/agentbase-core/lib/auth' // server auth guards
|
|
28
|
-
import
|
|
28
|
+
import { ... } from '@prmichaelsen/agentbase-core/types' // AuthUser, Result, branded types
|
|
29
|
+
import { ... } from '@prmichaelsen/agentbase-core/client' // HTTP client, SvcClient, AppClient, OAuth
|
|
30
|
+
import { ... } from '@prmichaelsen/agentbase-core/config' // loadConfig, validateConfig
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
## Services
|
|
32
34
|
|
|
33
35
|
### BaseService
|
|
34
36
|
|
|
35
|
-
Abstract base class
|
|
37
|
+
Abstract base class with config injection, structured logging, lifecycle hooks, and state tracking.
|
|
36
38
|
|
|
37
39
|
```ts
|
|
38
|
-
import { BaseService, type Logger } from '@prmichaelsen/agentbase-core/services'
|
|
40
|
+
import { BaseService, ServiceState, type Logger } from '@prmichaelsen/agentbase-core/services'
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class UserService extends BaseService<MyConfig> {
|
|
43
|
-
constructor(config: MyConfig, logger: Logger) {
|
|
42
|
+
class UserService extends BaseService<{ dbUrl: string }> {
|
|
43
|
+
constructor(config: { dbUrl: string }, logger: Logger) {
|
|
44
44
|
super(config, logger)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
async initialize() {
|
|
48
|
-
|
|
48
|
+
await super.initialize() // sets state to Initialized
|
|
49
|
+
this.logger.info('Connected', { url: this.config.dbUrl })
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
async
|
|
52
|
-
this.
|
|
52
|
+
async findUser(id: string) {
|
|
53
|
+
this.ensureInitialized() // throws if not initialized
|
|
54
|
+
// ...
|
|
53
55
|
}
|
|
54
56
|
}
|
|
57
|
+
|
|
58
|
+
const svc = new UserService({ dbUrl: '...' }, logger)
|
|
59
|
+
svc.getState() // ServiceState.Uninitialized
|
|
60
|
+
await svc.initialize()
|
|
61
|
+
svc.getState() // ServiceState.Initialized
|
|
55
62
|
```
|
|
56
63
|
|
|
57
64
|
### ConfirmationTokenService
|
|
@@ -74,9 +81,76 @@ const token = confirmations.generateToken({
|
|
|
74
81
|
|
|
75
82
|
// Step 2: Consume token (single-use)
|
|
76
83
|
const action = confirmations.consumeToken(token, 'user-123')
|
|
77
|
-
if (action) {
|
|
78
|
-
|
|
84
|
+
if (action) { /* execute */ }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Error Types
|
|
88
|
+
|
|
89
|
+
Typed error hierarchy with discriminated `kind` field and HTTP status mapping.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import {
|
|
93
|
+
UnauthorizedError, ForbiddenError, ValidationError, NotFoundError,
|
|
94
|
+
ConflictError, RateLimitError, ExternalError, InternalError,
|
|
95
|
+
isAppError, errorToStatusCode,
|
|
96
|
+
} from '@prmichaelsen/agentbase-core'
|
|
97
|
+
|
|
98
|
+
// Throw typed errors
|
|
99
|
+
throw new ValidationError('Email is required', { field: 'email' })
|
|
100
|
+
throw new NotFoundError('User not found')
|
|
101
|
+
|
|
102
|
+
// Type guard
|
|
103
|
+
try {
|
|
104
|
+
await doSomething()
|
|
105
|
+
} catch (err) {
|
|
106
|
+
if (isAppError(err)) {
|
|
107
|
+
console.log(err.kind) // 'VALIDATION' | 'NOT_FOUND' | ...
|
|
108
|
+
console.log(err.statusCode) // 400, 404, ...
|
|
109
|
+
console.log(err.context) // { field: 'email' }
|
|
110
|
+
}
|
|
79
111
|
}
|
|
112
|
+
|
|
113
|
+
// Map to HTTP status
|
|
114
|
+
const status = errorToStatusCode(err) // 400 for ValidationError, 500 for unknown
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
| Error | Kind | Status |
|
|
118
|
+
|-------|------|--------|
|
|
119
|
+
| `ValidationError` | `VALIDATION` | 400 |
|
|
120
|
+
| `UnauthorizedError` | `UNAUTHORIZED` | 401 |
|
|
121
|
+
| `ForbiddenError` | `FORBIDDEN` | 403 |
|
|
122
|
+
| `NotFoundError` | `NOT_FOUND` | 404 |
|
|
123
|
+
| `ConflictError` | `CONFLICT` | 409 |
|
|
124
|
+
| `RateLimitError` | `RATE_LIMIT` | 429 |
|
|
125
|
+
| `ExternalError` | `EXTERNAL` | 502 |
|
|
126
|
+
| `InternalError` | `INTERNAL` | 500 |
|
|
127
|
+
|
|
128
|
+
## Result Type
|
|
129
|
+
|
|
130
|
+
Discriminated `Result<T, E>` for operations where failure is expected.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { ok, err, isOk, isErr, mapOk, andThen, getOrElse, tryCatchAsync } from '@prmichaelsen/agentbase-core'
|
|
134
|
+
import type { Result } from '@prmichaelsen/agentbase-core'
|
|
135
|
+
|
|
136
|
+
// Create results
|
|
137
|
+
const success: Result<number> = ok(42)
|
|
138
|
+
const failure: Result<number, string> = err('not found')
|
|
139
|
+
|
|
140
|
+
// Type guards
|
|
141
|
+
if (isOk(success)) console.log(success.value) // 42
|
|
142
|
+
if (isErr(failure)) console.log(failure.error) // 'not found'
|
|
143
|
+
|
|
144
|
+
// Combinators
|
|
145
|
+
const doubled = mapOk(ok(5), x => x * 2) // Ok(10)
|
|
146
|
+
const chained = andThen(ok(5), x => x > 0 ? ok(x) : err('negative'))
|
|
147
|
+
const value = getOrElse(err('fail'), 0) // 0
|
|
148
|
+
|
|
149
|
+
// Wrap async functions
|
|
150
|
+
const result = await tryCatchAsync(
|
|
151
|
+
() => fetchUser(id),
|
|
152
|
+
(e) => new NotFoundError('User not found')
|
|
153
|
+
)
|
|
80
154
|
```
|
|
81
155
|
|
|
82
156
|
## Auth
|
|
@@ -84,20 +158,23 @@ if (action) {
|
|
|
84
158
|
### Server-Side (requires `@prmichaelsen/firebase-admin-sdk-v8`)
|
|
85
159
|
|
|
86
160
|
```ts
|
|
87
|
-
import {
|
|
161
|
+
import {
|
|
162
|
+
getServerSession, requireAuth, requireAdmin, isAdmin,
|
|
163
|
+
handleAuthError,
|
|
164
|
+
} from '@prmichaelsen/agentbase-core/lib/auth'
|
|
88
165
|
|
|
89
166
|
// Get session from request cookies
|
|
90
167
|
const session = await getServerSession(request)
|
|
91
168
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
169
|
+
// Guards throw typed errors — use try-catch
|
|
170
|
+
try {
|
|
171
|
+
await requireAuth(request) // throws UnauthorizedError
|
|
172
|
+
await requireAdmin(request, 'admin@example.com') // throws Unauthorized or Forbidden
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return handleAuthError(error) // converts to Response(401/403/500)
|
|
175
|
+
}
|
|
99
176
|
|
|
100
|
-
//
|
|
177
|
+
// Boolean check (does not throw)
|
|
101
178
|
const admin = await isAdmin(request, 'admin@example.com')
|
|
102
179
|
```
|
|
103
180
|
|
|
@@ -109,22 +186,15 @@ import {
|
|
|
109
186
|
upgradeAnonymousAccount, logout, onAuthChange, getIdToken,
|
|
110
187
|
} from '@prmichaelsen/agentbase-core/lib'
|
|
111
188
|
|
|
112
|
-
// Initialize once
|
|
113
189
|
initializeFirebase({ apiKey: '...', authDomain: '...', projectId: '...' })
|
|
114
190
|
|
|
115
|
-
// Auth flows
|
|
116
191
|
await signIn('user@example.com', 'password')
|
|
117
192
|
await signUp('user@example.com', 'password')
|
|
118
193
|
await signInAnonymously()
|
|
119
194
|
await upgradeAnonymousAccount('user@example.com', 'password')
|
|
120
195
|
await logout()
|
|
121
196
|
|
|
122
|
-
|
|
123
|
-
const unsubscribe = onAuthChange((user) => {
|
|
124
|
-
console.log(user ? `Signed in: ${user.uid}` : 'Signed out')
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// Get ID token for API calls
|
|
197
|
+
const unsubscribe = onAuthChange((user) => { /* ... */ })
|
|
128
198
|
const token = await getIdToken()
|
|
129
199
|
```
|
|
130
200
|
|
|
@@ -133,100 +203,147 @@ const token = await getIdToken()
|
|
|
133
203
|
```ts
|
|
134
204
|
import { isRealUser, isRealUserServer } from '@prmichaelsen/agentbase-core/lib/auth'
|
|
135
205
|
|
|
136
|
-
// Client-side: works with any { isAnonymous?: boolean }
|
|
137
206
|
if (isRealUser(user)) { /* non-anonymous */ }
|
|
138
|
-
|
|
139
|
-
// Server-side: typed for AuthUser
|
|
140
|
-
if (isRealUserServer(authUser)) { /* non-anonymous */ }
|
|
207
|
+
if (isRealUserServer(authUser)) { /* non-anonymous, typed for AuthUser */ }
|
|
141
208
|
```
|
|
142
209
|
|
|
143
|
-
##
|
|
210
|
+
## Client SDK
|
|
144
211
|
|
|
145
|
-
|
|
212
|
+
Full REST client for agentbase.me with 17 service classes, compound workflows, and OAuth support.
|
|
213
|
+
|
|
214
|
+
### Setup
|
|
146
215
|
|
|
147
216
|
```ts
|
|
148
|
-
import {
|
|
217
|
+
import { HttpClient, AuthSvc, MemoriesSvc, OAuthClient } from '@prmichaelsen/agentbase-core/client'
|
|
149
218
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
219
|
+
// With API key
|
|
220
|
+
const http = new HttpClient({
|
|
221
|
+
baseUrl: 'https://agentbase.me',
|
|
222
|
+
auth: { type: 'apiKey', key: 'your-api-key' },
|
|
223
|
+
})
|
|
153
224
|
|
|
154
|
-
|
|
155
|
-
|
|
225
|
+
// With OAuth bearer token
|
|
226
|
+
const http = new HttpClient({
|
|
227
|
+
baseUrl: 'https://agentbase.me',
|
|
228
|
+
auth: { type: 'bearer', token: () => oauthClient.getValidToken() },
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// With session cookie (browser)
|
|
232
|
+
const http = new HttpClient({
|
|
233
|
+
baseUrl: 'https://agentbase.me',
|
|
234
|
+
auth: { type: 'cookie' },
|
|
235
|
+
})
|
|
156
236
|
```
|
|
157
237
|
|
|
158
|
-
###
|
|
238
|
+
### SvcClient (1:1 REST mirror)
|
|
159
239
|
|
|
160
240
|
```ts
|
|
161
|
-
|
|
241
|
+
const memories = new MemoriesSvc(http)
|
|
242
|
+
|
|
243
|
+
// All methods return SdkResponse<T> — never throws
|
|
244
|
+
const result = await memories.search({ query: 'vacation photos', mode: 'semantic' })
|
|
245
|
+
if (result.error) {
|
|
246
|
+
console.error(result.error.message)
|
|
247
|
+
} else {
|
|
248
|
+
console.log(result.data) // { data: Memory[], total: number }
|
|
249
|
+
}
|
|
162
250
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
251
|
+
// Or use throwOnError() for cleaner async/await
|
|
252
|
+
const { data } = await memories.feed({ limit: 10 }).then(r => r.throwOnError())
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Available services: `AuthSvc`, `OAuthSvc`, `MemoriesSvc`, `ConversationsSvc`, `ProfilesSvc`, `GroupsSvc`, `DmsSvc`, `SearchSvc`, `NotificationsSvc`, `RelationshipsSvc`, `BoardsSvc`, `TokensSvc`, `IntegrationsSvc`, `SettingsSvc`, `PaymentsSvc`, `UsageSvc`, `JobsSvc`
|
|
256
|
+
|
|
257
|
+
### AppClient (compound workflows)
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
import { AppClient } from '@prmichaelsen/agentbase-core/client'
|
|
261
|
+
|
|
262
|
+
const app = new AppClient({ auth, memories, conversations, profiles, groups, dms, search, notifications })
|
|
263
|
+
|
|
264
|
+
await app.loginAndGetSession(idToken)
|
|
265
|
+
await app.searchAndFetchMemories('vacation', 5)
|
|
266
|
+
await app.createGroupAndInvite('Book Club', 'Monthly reads', ['user-1', 'user-2'])
|
|
267
|
+
await app.getFullProfile('user-123') // profile + memory count
|
|
268
|
+
await app.startDm('user-456') // find existing or create new
|
|
167
269
|
```
|
|
168
270
|
|
|
169
|
-
|
|
271
|
+
### OAuth Integration
|
|
170
272
|
|
|
171
273
|
```ts
|
|
172
|
-
import {
|
|
274
|
+
import {
|
|
275
|
+
OAuthClient, generateCodeVerifier, generateCodeChallenge,
|
|
276
|
+
buildAuthorizationUrl,
|
|
277
|
+
} from '@prmichaelsen/agentbase-core/client'
|
|
278
|
+
|
|
279
|
+
// 1. Generate PKCE params
|
|
280
|
+
const verifier = generateCodeVerifier()
|
|
281
|
+
const challenge = await generateCodeChallenge(verifier)
|
|
282
|
+
|
|
283
|
+
// 2. Build authorization URL
|
|
284
|
+
const url = buildAuthorizationUrl('https://agentbase.me', {
|
|
285
|
+
clientId: 'your-client-id',
|
|
286
|
+
redirectUri: 'http://localhost:3000/callback',
|
|
287
|
+
scope: 'read write',
|
|
288
|
+
codeChallenge: challenge,
|
|
289
|
+
})
|
|
173
290
|
|
|
174
|
-
//
|
|
175
|
-
|
|
291
|
+
// 3. After redirect, exchange code for tokens
|
|
292
|
+
const oauth = new OAuthClient(http, { clientId: 'your-client-id' })
|
|
293
|
+
await oauth.exchangeCode(code, redirectUri, verifier)
|
|
294
|
+
|
|
295
|
+
// 4. Get valid token (auto-refreshes if expired)
|
|
296
|
+
const token = await oauth.getValidToken()
|
|
297
|
+
|
|
298
|
+
// API token shortcut
|
|
299
|
+
await oauth.exchangeApiToken('your-api-token')
|
|
176
300
|
```
|
|
177
301
|
|
|
178
|
-
##
|
|
302
|
+
## Configuration
|
|
179
303
|
|
|
180
|
-
|
|
304
|
+
Centralized environment variable loading and validation.
|
|
181
305
|
|
|
182
306
|
```ts
|
|
183
|
-
import {
|
|
307
|
+
import { loadConfig, validateConfig } from '@prmichaelsen/agentbase-core/config'
|
|
184
308
|
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
limit: 100,
|
|
188
|
-
period: 60,
|
|
189
|
-
keyPrefix: 'api',
|
|
190
|
-
})
|
|
309
|
+
const config = loadConfig() // reads from process.env
|
|
310
|
+
validateConfig(config, { requireFirebaseAdmin: true }) // throws ValidationError if missing
|
|
191
311
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
312
|
+
// Or pass custom env
|
|
313
|
+
const config = loadConfig({ FIREBASE_PROJECT_ID: 'my-project', ... })
|
|
195
314
|
```
|
|
196
315
|
|
|
197
|
-
##
|
|
316
|
+
## Logger
|
|
317
|
+
|
|
318
|
+
Structured logger with automatic sensitive data redaction.
|
|
198
319
|
|
|
199
320
|
```ts
|
|
200
|
-
import {
|
|
321
|
+
import { createLogger, authLogger, apiLogger } from '@prmichaelsen/agentbase-core/lib'
|
|
201
322
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
generateUUID() // "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5"
|
|
323
|
+
const logger = createLogger('MyService')
|
|
324
|
+
logger.info('Request', { userId: 'abc', apiKey: 'secret' })
|
|
325
|
+
// Output: [MyService] Request { userId: 'abc', apiKey: '[REDACTED]' }
|
|
206
326
|
```
|
|
207
327
|
|
|
208
|
-
|
|
328
|
+
### Sanitization Utilities
|
|
209
329
|
|
|
210
330
|
```ts
|
|
211
|
-
import
|
|
331
|
+
import { sanitizeToken, sanitizeEmail, sanitizeUserId, sanitizeObject } from '@prmichaelsen/agentbase-core/lib'
|
|
212
332
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
photoURL: string | null
|
|
218
|
-
emailVerified: boolean
|
|
219
|
-
isAnonymous: boolean
|
|
220
|
-
}
|
|
333
|
+
sanitizeToken('abc123...') // "a1b2c3d4..."
|
|
334
|
+
sanitizeEmail('john@x.com') // "jo***@x.com"
|
|
335
|
+
sanitizeObject({ password: 'secret', name: 'ok' }) // { password: '[REDACTED]', name: 'ok' }
|
|
336
|
+
```
|
|
221
337
|
|
|
222
|
-
|
|
223
|
-
user: AuthUser
|
|
224
|
-
}
|
|
338
|
+
## Types
|
|
225
339
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
340
|
+
```ts
|
|
341
|
+
import type { AuthUser, ServerSession, Result, UserId, EmailAddress } from '@prmichaelsen/agentbase-core/types'
|
|
342
|
+
import { toUserId, toEmailAddress, toTimestamp } from '@prmichaelsen/agentbase-core/types'
|
|
343
|
+
|
|
344
|
+
// Branded primitives prevent mixing IDs
|
|
345
|
+
const uid: UserId = toUserId('firebase-uid')
|
|
346
|
+
const email: EmailAddress = toEmailAddress('user@example.com')
|
|
230
347
|
```
|
|
231
348
|
|
|
232
349
|
## License
|