@stacknet/userutils 0.6.0 → 0.6.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/dist/components/index.cjs +2 -2
- package/dist/components/index.d.cts +24 -3
- package/dist/components/index.d.ts +24 -3
- package/dist/components/index.js +2 -2
- package/dist/hooks/index.d.cts +1 -2
- package/dist/hooks/index.d.ts +1 -2
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -2
- package/dist/types/index.d.cts +92 -3
- package/dist/types/index.d.ts +92 -3
- package/package.json +1 -1
- package/dist/config-CLzVWDrU.d.cts +0 -177
- package/dist/config-xNca5ufB.d.ts +0 -177
- package/dist/server/index.d.cts +0 -359
- package/dist/server/index.d.ts +0 -359
package/dist/server/index.d.cts
DELETED
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { S as Session } from '../auth-c1d7Eji2.cjs';
|
|
2
|
-
import { e as ServerConfig, I as IPExtractorConfig } from '../config-CLzVWDrU.cjs';
|
|
3
|
-
export { f as decodeJWTPayload, g as extractIP, h as generateToken, m as maybeRefreshJWT, s as signJWT, v as verifyJWT, i as verifyJWTSignature } from '../config-CLzVWDrU.cjs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Server-only session type that includes the JWT.
|
|
7
|
-
* NEVER export this from the client bundle.
|
|
8
|
-
*/
|
|
9
|
-
interface ServerSession extends Session {
|
|
10
|
-
jwt: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** Rate limiter interface — implement with Redis, Upstash, or use the in-memory default */
|
|
14
|
-
interface RateLimiter {
|
|
15
|
-
check(key: string): Promise<{
|
|
16
|
-
allowed: boolean;
|
|
17
|
-
remaining: number;
|
|
18
|
-
retryAfter?: number;
|
|
19
|
-
}>;
|
|
20
|
-
}
|
|
21
|
-
/** Replay store interface — for preventing JWT re-sign replay attacks */
|
|
22
|
-
interface ReplayStore {
|
|
23
|
-
has(key: string): Promise<boolean>;
|
|
24
|
-
set(key: string, ttlSeconds: number): Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* In-memory rate limiter with sliding window.
|
|
28
|
-
*
|
|
29
|
-
* Safe default for single-process deployments. For multi-process or
|
|
30
|
-
* distributed environments, provide a Redis-backed RateLimiter instead.
|
|
31
|
-
*/
|
|
32
|
-
declare function createInMemoryRateLimiter(opts: {
|
|
33
|
-
maxRequests: number;
|
|
34
|
-
windowMs: number;
|
|
35
|
-
}): RateLimiter;
|
|
36
|
-
/** In-memory replay store (single-process, entries auto-expire) */
|
|
37
|
-
declare function createInMemoryReplayStore(): ReplayStore;
|
|
38
|
-
|
|
39
|
-
interface AuthCallbackOptions {
|
|
40
|
-
rateLimiter?: RateLimiter;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Factory: POST handler for auth callback (login completion).
|
|
44
|
-
*
|
|
45
|
-
* Accepts wallet signature verification or OTP results from client,
|
|
46
|
-
* validates with StackNet, sets HttpOnly JWT cookie + public session cookie + CSRF cookie.
|
|
47
|
-
*/
|
|
48
|
-
declare function createAuthCallback(config: ServerConfig, opts?: AuthCallbackOptions): (request: Request) => Promise<Response>;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Factory: POST handler for logout.
|
|
52
|
-
* Revokes session with StackNet and clears all auth cookies.
|
|
53
|
-
*/
|
|
54
|
-
declare function createLogoutHandler(config: Pick<ServerConfig, 'stacknetUrl' | 'secureCookies' | 'cookieDomain'> & {
|
|
55
|
-
/**
|
|
56
|
-
* HMAC secret used to verify the JWT signature before extracting the
|
|
57
|
-
* sessionId for upstream revocation. STRONGLY RECOMMENDED.
|
|
58
|
-
*
|
|
59
|
-
* Without this, the handler skips upstream revocation entirely and only
|
|
60
|
-
* clears cookies — because trusting an unverified JWT for the sessionId
|
|
61
|
-
* would let an attacker plant a forged cookie and trigger DELETE on
|
|
62
|
-
* another user's session.
|
|
63
|
-
*/
|
|
64
|
-
authSecret?: string;
|
|
65
|
-
}): (request: Request) => Promise<Response>;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Factory: GET handler for session validation.
|
|
69
|
-
* Reads HttpOnly JWT cookie, validates, returns public session info.
|
|
70
|
-
* Transparently refreshes JWT if close to expiry.
|
|
71
|
-
*/
|
|
72
|
-
declare function createSessionHandler(config: Pick<ServerConfig, 'authSecret' | 'jwtExpiry' | 'secureCookies' | 'cookieDomain' | 'sessionMaxAge'>): (request: Request) => Promise<Response>;
|
|
73
|
-
|
|
74
|
-
interface OTPHandlerConfig extends Pick<ServerConfig, 'authSecret' | 'secureCookies' | 'cookieDomain' | 'sessionMaxAge' | 'jwtExpiry'> {
|
|
75
|
-
/** The OTP secret to validate against */
|
|
76
|
-
otpSecret: string;
|
|
77
|
-
/** Rate limiter (default: 5 attempts per 5 min per IP) */
|
|
78
|
-
rateLimiter?: RateLimiter;
|
|
79
|
-
/** How to extract the real client IP for rate-limit keys. Defaults to
|
|
80
|
-
* `{ trustedProxyCount: 1 }`. Set `trustedProxyCount: 0` if the handler
|
|
81
|
-
* is exposed directly (no proxy in front). */
|
|
82
|
-
ipConfig?: IPExtractorConfig;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Factory: POST handler for OTP verification.
|
|
86
|
-
* Validates OTP code, creates session JWT, sets HttpOnly cookie.
|
|
87
|
-
*/
|
|
88
|
-
declare function createOTPHandler(config: OTPHandlerConfig): (request: Request) => Promise<Response>;
|
|
89
|
-
|
|
90
|
-
interface OAuthHandlerConfig {
|
|
91
|
-
rateLimiter?: RateLimiter;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Factory: OAuth flow handlers.
|
|
95
|
-
*
|
|
96
|
-
* Returns two handlers:
|
|
97
|
-
* - GET /api/auth/oauth/[provider] — Starts OAuth flow, returns redirect URL
|
|
98
|
-
* - POST /api/auth/oauth/[provider]/callback — Handles OAuth callback, sets cookies
|
|
99
|
-
*/
|
|
100
|
-
declare function createOAuthHandlers(config: ServerConfig, opts?: OAuthHandlerConfig): {
|
|
101
|
-
startFlow: (request: Request) => Promise<Response>;
|
|
102
|
-
handleCallback: (request: Request) => Promise<Response>;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
interface GoogleOneTapHandlerConfig {
|
|
106
|
-
rateLimiter?: RateLimiter;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Factory: POST handler for Google One Tap credential verification.
|
|
110
|
-
*
|
|
111
|
-
* Receives the Google JWT credential from the client, verifies it with
|
|
112
|
-
* Google's tokeninfo endpoint, then creates a StackNet session.
|
|
113
|
-
*/
|
|
114
|
-
declare function createGoogleOneTapHandler(config: ServerConfig, opts?: GoogleOneTapHandlerConfig): (request: Request) => Promise<Response>;
|
|
115
|
-
|
|
116
|
-
interface BillingProxyConfig extends Pick<ServerConfig, 'authSecret' | 'stacknetUrl' | 'stackId' | 'stacknetJwtSecret' | 'secureCookies' | 'cookieDomain' | 'sessionMaxAge' | 'jwtExpiry'> {
|
|
117
|
-
/** Rate limiter for mutations (default: 20/min per user) */
|
|
118
|
-
rateLimiter?: RateLimiter;
|
|
119
|
-
/**
|
|
120
|
-
* Canonical absolute origin (e.g. "https://app.example.com") used when
|
|
121
|
-
* constructing Stripe success/cancel URLs. STRONGLY RECOMMENDED.
|
|
122
|
-
*
|
|
123
|
-
* Without this, the origin is derived from the request URL — which is
|
|
124
|
-
* populated from the `Host` header. If the app is deployed behind a
|
|
125
|
-
* proxy that does not validate / rewrite `Host`, an attacker can send
|
|
126
|
-
* `Host: evil.example` and the post-checkout redirect will point there.
|
|
127
|
-
* Stripe's dashboard allowlist catches most cases, but we should not
|
|
128
|
-
* depend on that alone.
|
|
129
|
-
*
|
|
130
|
-
* Must be a full http(s) origin with no path. Factory throws on
|
|
131
|
-
* malformed input so misconfigurations surface at boot, not at runtime.
|
|
132
|
-
*/
|
|
133
|
-
canonicalOrigin?: string;
|
|
134
|
-
}
|
|
135
|
-
type Handler = (request: Request) => Promise<Response>;
|
|
136
|
-
/**
|
|
137
|
-
* Factory: creates all billing route handlers that proxy to StackNet.
|
|
138
|
-
*
|
|
139
|
-
* All POST handlers validate CSRF tokens. All handlers validate the JWT cookie
|
|
140
|
-
* and transparently refresh if close to expiry.
|
|
141
|
-
*/
|
|
142
|
-
declare function createBillingProxy(config: BillingProxyConfig): {
|
|
143
|
-
plans: {
|
|
144
|
-
GET: Handler;
|
|
145
|
-
};
|
|
146
|
-
subscription: {
|
|
147
|
-
GET: Handler;
|
|
148
|
-
};
|
|
149
|
-
subscribe: {
|
|
150
|
-
POST: Handler;
|
|
151
|
-
};
|
|
152
|
-
cancel: {
|
|
153
|
-
POST: Handler;
|
|
154
|
-
};
|
|
155
|
-
usage: {
|
|
156
|
-
GET: Handler;
|
|
157
|
-
};
|
|
158
|
-
history: {
|
|
159
|
-
GET: Handler;
|
|
160
|
-
};
|
|
161
|
-
prepaid: {
|
|
162
|
-
POST: Handler;
|
|
163
|
-
};
|
|
164
|
-
verifyPrepaid: {
|
|
165
|
-
POST: Handler;
|
|
166
|
-
};
|
|
167
|
-
verifySession: {
|
|
168
|
-
POST: Handler;
|
|
169
|
-
};
|
|
170
|
-
subscribeSol: {
|
|
171
|
-
POST: Handler;
|
|
172
|
-
};
|
|
173
|
-
prepaidSol: {
|
|
174
|
-
POST: Handler;
|
|
175
|
-
};
|
|
176
|
-
topup: {
|
|
177
|
-
POST: Handler;
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Factory: POST handler for Stripe webhooks.
|
|
183
|
-
* Forwards raw body + stripe-signature to StackNet for verification and processing.
|
|
184
|
-
*/
|
|
185
|
-
declare function createWebhookHandler(config: Pick<ServerConfig, 'stacknetUrl' | 'stackId'>): (request: Request) => Promise<Response>;
|
|
186
|
-
|
|
187
|
-
interface CSRFConfig {
|
|
188
|
-
/** Cookie name (default: '__csrf') */
|
|
189
|
-
cookieName?: string;
|
|
190
|
-
/** Header name (default: 'x-csrf-token') */
|
|
191
|
-
headerName?: string;
|
|
192
|
-
/** Token length in bytes (default: 32) */
|
|
193
|
-
tokenLength?: number;
|
|
194
|
-
/** Use Secure flag on cookie (default: true) */
|
|
195
|
-
secure?: boolean;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Create CSRF protection using the double-submit cookie pattern.
|
|
199
|
-
*
|
|
200
|
-
* 1. Server sets a non-HttpOnly cookie with a random token
|
|
201
|
-
* 2. Client reads the cookie and sends the token in a header on mutations
|
|
202
|
-
* 3. Server validates cookie === header (attacker can't read cookie cross-origin)
|
|
203
|
-
*/
|
|
204
|
-
declare function createCSRFProtection(config?: CSRFConfig): {
|
|
205
|
-
/**
|
|
206
|
-
* Generate a CSRF token and add Set-Cookie header to a response.
|
|
207
|
-
* Call this on auth callback (login) to establish the CSRF cookie.
|
|
208
|
-
*/
|
|
209
|
-
generateToken(headers: Headers): string;
|
|
210
|
-
/**
|
|
211
|
-
* Validate a request's CSRF token (cookie vs header).
|
|
212
|
-
* Returns true if valid, false if not.
|
|
213
|
-
*/
|
|
214
|
-
validateRequest(request: Request): {
|
|
215
|
-
valid: boolean;
|
|
216
|
-
error?: string;
|
|
217
|
-
};
|
|
218
|
-
/** Cookie name for client-side reading */
|
|
219
|
-
cookieName: string;
|
|
220
|
-
/** Header name for client-side sending */
|
|
221
|
-
headerName: string;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
/** Standard security response headers */
|
|
225
|
-
declare function securityHeaders(): Record<string, string>;
|
|
226
|
-
/**
|
|
227
|
-
* Wrap a request handler to add security headers to the response.
|
|
228
|
-
*/
|
|
229
|
-
declare function withSecurityHeaders(handler: (request: Request) => Promise<Response> | Response): (request: Request) => Promise<Response>;
|
|
230
|
-
/**
|
|
231
|
-
* Generate security headers config for Next.js next.config.ts.
|
|
232
|
-
*
|
|
233
|
-
* Usage in next.config.ts:
|
|
234
|
-
* ```ts
|
|
235
|
-
* import { nextSecurityHeaders } from '@stacknet/userutils/server';
|
|
236
|
-
* export default { headers: () => [{ source: '/(.*)', headers: nextSecurityHeaders() }] };
|
|
237
|
-
* ```
|
|
238
|
-
*/
|
|
239
|
-
declare function nextSecurityHeaders(): Array<{
|
|
240
|
-
key: string;
|
|
241
|
-
value: string;
|
|
242
|
-
}>;
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Re-sign a JWT using StackNet's HMAC-SHA256 scheme.
|
|
246
|
-
*
|
|
247
|
-
* Geoff apps sign JWTs with AUTH_SECRET. StackNet validates with JWT_SECRET.
|
|
248
|
-
* This function re-signs using the StackNet secret so the backend resolves
|
|
249
|
-
* the correct per-user identity.
|
|
250
|
-
*/
|
|
251
|
-
declare function resignForStackNet(jwt: string, stacknetJwtSecret: string): string | null;
|
|
252
|
-
/**
|
|
253
|
-
* Build headers for proxying a user-scoped request to StackNet.
|
|
254
|
-
* Re-signs the JWT so StackNet recognises the user's identity.
|
|
255
|
-
*
|
|
256
|
-
* Refuses to interpolate any value that doesn't match the compact JWT
|
|
257
|
-
* format (header.body.signature, base64url segments only) to prevent
|
|
258
|
-
* header injection.
|
|
259
|
-
*/
|
|
260
|
-
declare function buildStackNetHeaders(jwt: string, stacknetJwtSecret: string): Record<string, string>;
|
|
261
|
-
/**
|
|
262
|
-
* Extract JWT from a request's cookies or Authorization header.
|
|
263
|
-
*/
|
|
264
|
-
declare function extractJwt(request: Request): string | null;
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Server-side proxy helpers for StackNet preview codes.
|
|
268
|
-
*
|
|
269
|
-
* Preview codes are admin-minted 6-digit access credentials with a
|
|
270
|
-
* per-code token budget. Only the pinned admin global id (enforced
|
|
271
|
-
* by StackNet's state machine) can mint / list / revoke codes.
|
|
272
|
-
*
|
|
273
|
-
* These helpers wrap `fetch` against the StackNet HTTP layer with
|
|
274
|
-
* re-signed JWT cookies (same pattern as `buildStackNetHeaders`).
|
|
275
|
-
* Admin-console API routes are expected to call them; the raw
|
|
276
|
-
* endpoints are NOT exposed in the client bundle.
|
|
277
|
-
*/
|
|
278
|
-
interface PreviewCode {
|
|
279
|
-
code: string;
|
|
280
|
-
createdBy: string;
|
|
281
|
-
tokenBudget: number;
|
|
282
|
-
tokensUsed: number;
|
|
283
|
-
tokensRemaining: number;
|
|
284
|
-
createdAt: number;
|
|
285
|
-
expiresAt: number | null;
|
|
286
|
-
revoked: boolean;
|
|
287
|
-
/** Optional human-readable label (e.g. "Tester: Alice"). Absent on
|
|
288
|
-
* codes minted before the name field shipped. */
|
|
289
|
-
name?: string | null;
|
|
290
|
-
}
|
|
291
|
-
interface MintPreviewCodeOptions {
|
|
292
|
-
/** Token budget for the new code. Must be > 0. */
|
|
293
|
-
tokenBudget: number;
|
|
294
|
-
/** Optional explicit 6-digit code string. Server generates one
|
|
295
|
-
* if omitted. */
|
|
296
|
-
code?: string;
|
|
297
|
-
/** Optional Unix-ms expiry. */
|
|
298
|
-
expiresAt?: number;
|
|
299
|
-
/** Optional human-readable label for the code. Shown in the admin
|
|
300
|
-
* list so the operator can tell codes apart. */
|
|
301
|
-
name?: string;
|
|
302
|
-
}
|
|
303
|
-
interface PreviewCodesProxyConfig {
|
|
304
|
-
/** StackNet base URL (no trailing slash). */
|
|
305
|
-
stacknetBaseUrl: string;
|
|
306
|
-
/** Shared HMAC secret for re-signing the caller's JWT. */
|
|
307
|
-
stacknetJwtSecret: string;
|
|
308
|
-
/** Caller's StackAuth JWT (user identity). */
|
|
309
|
-
jwt: string;
|
|
310
|
-
}
|
|
311
|
-
/** Admin-only: mint a new preview code. Returns the new code row. */
|
|
312
|
-
declare function mintPreviewCode(cfg: PreviewCodesProxyConfig, options: MintPreviewCodeOptions): Promise<{
|
|
313
|
-
minted: boolean;
|
|
314
|
-
code: PreviewCode;
|
|
315
|
-
} | {
|
|
316
|
-
error: string;
|
|
317
|
-
status: number;
|
|
318
|
-
}>;
|
|
319
|
-
/** Admin-only: list every preview code in the system. */
|
|
320
|
-
declare function listPreviewCodes(cfg: PreviewCodesProxyConfig): Promise<PreviewCode[] | {
|
|
321
|
-
error: string;
|
|
322
|
-
status: number;
|
|
323
|
-
}>;
|
|
324
|
-
/** Public: read a code's balance + status. Used by auth middleware. */
|
|
325
|
-
declare function getPreviewCode(stacknetBaseUrl: string, code: string): Promise<PreviewCode | null>;
|
|
326
|
-
/** Admin-only: revoke a preview code. */
|
|
327
|
-
declare function revokePreviewCode(cfg: PreviewCodesProxyConfig, code: string): Promise<{
|
|
328
|
-
revoked: boolean;
|
|
329
|
-
code: PreviewCode;
|
|
330
|
-
} | {
|
|
331
|
-
error: string;
|
|
332
|
-
status: number;
|
|
333
|
-
}>;
|
|
334
|
-
/** Internal: debit tokens from a preview code. Called by the metering
|
|
335
|
-
* layer after inference completes. */
|
|
336
|
-
declare function redeemPreviewCode(stacknetBaseUrl: string, code: string, tokens: number): Promise<{
|
|
337
|
-
redeemed: boolean;
|
|
338
|
-
code: string;
|
|
339
|
-
tokensUsed: number;
|
|
340
|
-
tokensRemaining: number;
|
|
341
|
-
} | {
|
|
342
|
-
error: string;
|
|
343
|
-
status: number;
|
|
344
|
-
}>;
|
|
345
|
-
/** Allowlist of admin global ids that can mint / revoke preview
|
|
346
|
-
* codes. Mirrors PREVIEW_CODE_ADMIN_GLOBAL_IDS in the Rust state
|
|
347
|
-
* machine — must stay in sync. Admin-console UI and API route guards
|
|
348
|
-
* should call `isPreviewCodeAdmin(currentUser.userId)` instead of
|
|
349
|
-
* comparing against a single constant so every entry is accepted. */
|
|
350
|
-
declare const PREVIEW_CODE_ADMIN_GLOBAL_IDS: readonly string[];
|
|
351
|
-
/** Returns true if the given global id is in the preview-code admin
|
|
352
|
-
* allowlist. */
|
|
353
|
-
declare function isPreviewCodeAdmin(globalId: string | null | undefined): boolean;
|
|
354
|
-
/** Back-compat alias for callers that only need a single canonical
|
|
355
|
-
* admin id for display/logging. Don't use for gating — use
|
|
356
|
-
* `isPreviewCodeAdmin()` to accept every entry in the allowlist. */
|
|
357
|
-
declare const PREVIEW_CODE_ADMIN_GLOBAL_ID: string;
|
|
358
|
-
|
|
359
|
-
export { type AuthCallbackOptions, type BillingProxyConfig, type CSRFConfig, type GoogleOneTapHandlerConfig, IPExtractorConfig, type MintPreviewCodeOptions, type OAuthHandlerConfig, type OTPHandlerConfig, PREVIEW_CODE_ADMIN_GLOBAL_ID, PREVIEW_CODE_ADMIN_GLOBAL_IDS, type PreviewCode, type PreviewCodesProxyConfig, type RateLimiter, type ReplayStore, ServerConfig, type ServerSession, buildStackNetHeaders, createAuthCallback, createBillingProxy, createCSRFProtection, createGoogleOneTapHandler, createInMemoryRateLimiter, createInMemoryReplayStore, createLogoutHandler, createOAuthHandlers, createOTPHandler, createSessionHandler, createWebhookHandler, extractJwt, getPreviewCode, isPreviewCodeAdmin, listPreviewCodes, mintPreviewCode, nextSecurityHeaders, redeemPreviewCode, resignForStackNet, revokePreviewCode, securityHeaders, withSecurityHeaders };
|