@dontcode2/backend 0.1.0 → 0.1.1
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 +261 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +196 -3
- package/dist/index.d.ts +196 -3
- package/dist/index.js +253 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -4,11 +4,16 @@ interface TransportConfig {
|
|
|
4
4
|
apiKey?: string;
|
|
5
5
|
/** Gateway origin, already normalized (no trailing slash). */
|
|
6
6
|
baseUrl: string;
|
|
7
|
+
/** Per-request timeout in ms. Defaults to `DEFAULT_TIMEOUT_MS`; `0` (or any
|
|
8
|
+
* non-positive value) disables it. */
|
|
9
|
+
timeoutMs?: number;
|
|
7
10
|
}
|
|
8
11
|
interface RequestOptions {
|
|
9
12
|
/** End-user access token, sent as `X-Access-Token` (separate from the
|
|
10
13
|
* project API key). Required by signed-in auth calls. */
|
|
11
14
|
accessToken?: string;
|
|
15
|
+
/** Override the client's timeout for this one call (ms). `0` disables it. */
|
|
16
|
+
timeoutMs?: number;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* The single place network requests are made. Everything else in the SDK is a
|
|
@@ -20,6 +25,15 @@ declare class Transport {
|
|
|
20
25
|
constructor(config: TransportConfig);
|
|
21
26
|
private headers;
|
|
22
27
|
private url;
|
|
28
|
+
private timeout;
|
|
29
|
+
/**
|
|
30
|
+
* One fetch, with a timeout that turns "hung socket" into a fast, typed
|
|
31
|
+
* failure. A timeout surfaces as `DontCodeError` with status 408 / code
|
|
32
|
+
* `Timeout`; any other transport failure (DNS, refused, offline) as status
|
|
33
|
+
* 0 / code `NetworkError`. Both are distinct from a real `401`, so an auth
|
|
34
|
+
* guard can tell "backend is down" apart from "user is signed out".
|
|
35
|
+
*/
|
|
36
|
+
private send;
|
|
23
37
|
/** POST a JSON body and parse the JSON response. */
|
|
24
38
|
json<T>(path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
|
|
25
39
|
/** PUT a multipart form (file uploads). The runtime sets the boundary. */
|
|
@@ -188,6 +202,107 @@ interface TemporaryUrlResult {
|
|
|
188
202
|
/** Bytes the SDK can turn into an upload body. */
|
|
189
203
|
type UploadBody = Blob | ArrayBuffer | ArrayBufferView | string;
|
|
190
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Session helpers, framework-agnostic by design. They never touch a request or
|
|
207
|
+
* response object; they take a token (or a cookie header) and return plain
|
|
208
|
+
* data, so they slot into any framework's guard (Next middleware, SvelteKit
|
|
209
|
+
* hooks, Express, a worker) without an adapter.
|
|
210
|
+
*
|
|
211
|
+
* The point of the module: an auth guard must not make a network round-trip on
|
|
212
|
+
* every navigation, or a slow gateway stalls the page and a swallowed timeout
|
|
213
|
+
* reads as "signed out". So there are two modes:
|
|
214
|
+
*
|
|
215
|
+
* - optimistic — decode the token locally (no signature check, no network)
|
|
216
|
+
* and trust its claims for routing. Instant. Used for the common gate.
|
|
217
|
+
* - verified — call the gateway's `me` once, cache the result for a short
|
|
218
|
+
* TTL, and hard-timeout the request. Used for sensitive actions.
|
|
219
|
+
*
|
|
220
|
+
* The trade-offs (no signature verification, revocation lag) are documented on
|
|
221
|
+
* `getSession` and in the public BYOC docs; read them before choosing a mode.
|
|
222
|
+
*/
|
|
223
|
+
/** A JWT payload decoded WITHOUT verifying its signature. Trust accordingly. */
|
|
224
|
+
interface DecodedSession {
|
|
225
|
+
/** Subject — the user id. */
|
|
226
|
+
sub: string;
|
|
227
|
+
email?: string;
|
|
228
|
+
role?: string;
|
|
229
|
+
claims?: Record<string, unknown>;
|
|
230
|
+
/** Expiry, seconds since the epoch (standard JWT `exp`). */
|
|
231
|
+
exp?: number;
|
|
232
|
+
/** Issued-at, seconds since the epoch (standard JWT `iat`). */
|
|
233
|
+
iat?: number;
|
|
234
|
+
[key: string]: unknown;
|
|
235
|
+
}
|
|
236
|
+
type SessionStatus =
|
|
237
|
+
/** A usable session: a present, unexpired token (verified or optimistic). */
|
|
238
|
+
'active'
|
|
239
|
+
/** The token is present but past its `exp`. */
|
|
240
|
+
| 'expired'
|
|
241
|
+
/** No token, or an unparseable one. */
|
|
242
|
+
| 'anonymous'
|
|
243
|
+
/** Verified mode could not reach the gateway (timeout/network/5xx). The
|
|
244
|
+
* optimistically-decoded `user` is still returned so the caller can choose
|
|
245
|
+
* to fail open during an outage instead of logging everyone out. */
|
|
246
|
+
| 'unavailable';
|
|
247
|
+
interface SessionResult {
|
|
248
|
+
status: SessionStatus;
|
|
249
|
+
/** The signed-in user, or `null` when anonymous/expired. In `verified` mode
|
|
250
|
+
* this came from the gateway; in `optimistic` (or `unavailable`) it was
|
|
251
|
+
* decoded from the token's own claims. */
|
|
252
|
+
user: CurrentUser | null;
|
|
253
|
+
/** True only when `user` was confirmed by a gateway `me` call this request
|
|
254
|
+
* (or from a fresh cache entry of one). False for optimistic decodes. */
|
|
255
|
+
verified: boolean;
|
|
256
|
+
/** The token's `exp` (seconds since epoch), when present. */
|
|
257
|
+
expiresAt?: number;
|
|
258
|
+
}
|
|
259
|
+
interface GetSessionInput {
|
|
260
|
+
accessToken: string;
|
|
261
|
+
/** `optimistic` (default): decode locally, zero network. `verified`: confirm
|
|
262
|
+
* against the gateway with caching + a hard timeout. */
|
|
263
|
+
mode?: 'optimistic' | 'verified';
|
|
264
|
+
}
|
|
265
|
+
/** A place to cache verified sessions. Swap the default in-memory store for a
|
|
266
|
+
* shared one (Redis, KV) when running multiple instances. */
|
|
267
|
+
interface SessionCache {
|
|
268
|
+
get(token: string): SessionResult | undefined;
|
|
269
|
+
set(token: string, value: SessionResult, ttlMs: number): void;
|
|
270
|
+
delete?(token: string): void;
|
|
271
|
+
}
|
|
272
|
+
interface SessionOptions {
|
|
273
|
+
/** Cache for verified sessions. Defaults to a per-process `InMemorySessionCache`. */
|
|
274
|
+
cache?: SessionCache;
|
|
275
|
+
/** How long a verified session stays cached. Default 60_000 (60s). Keep it
|
|
276
|
+
* short: a cached session can outlive a server-side revocation by up to
|
|
277
|
+
* this long. */
|
|
278
|
+
ttlMs?: number;
|
|
279
|
+
/** Timeout for the `me` call made by `verified` mode (ms). Default 5_000. */
|
|
280
|
+
verifyTimeoutMs?: number;
|
|
281
|
+
}
|
|
282
|
+
/** Default cache: a `Map` with per-entry TTL. Lives for the life of the process
|
|
283
|
+
* (and is shared across requests on a reused serverless instance). */
|
|
284
|
+
declare class InMemorySessionCache implements SessionCache {
|
|
285
|
+
private readonly store;
|
|
286
|
+
get(token: string): SessionResult | undefined;
|
|
287
|
+
set(token: string, value: SessionResult, ttlMs: number): void;
|
|
288
|
+
delete(token: string): void;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Decode a JWT access token's payload WITHOUT verifying its signature, or
|
|
292
|
+
* return `null` if it is not a parseable JWT. This is deliberately cheap and
|
|
293
|
+
* offline; it is not proof the token is genuine. DontCode tokens are signed
|
|
294
|
+
* with a secret the gateway never shares, so the only authority on a token is
|
|
295
|
+
* the gateway's `me` endpoint — use `getSession({ mode: 'verified' })` when you
|
|
296
|
+
* need that authority.
|
|
297
|
+
*/
|
|
298
|
+
declare function decodeAccessToken(token: string): DecodedSession | null;
|
|
299
|
+
/** True when a token (or already-decoded payload) is past its `exp`. A token
|
|
300
|
+
* with no `exp` is treated as not expired (the caller cannot prove otherwise
|
|
301
|
+
* offline). `skewSeconds` widens the window to absorb clock drift. */
|
|
302
|
+
declare function isSessionExpired(input: string | DecodedSession | null, opts?: {
|
|
303
|
+
skewSeconds?: number;
|
|
304
|
+
}): boolean;
|
|
305
|
+
|
|
191
306
|
/**
|
|
192
307
|
* MFA is per-user and opt-in. `enroll`/`enrollConfirm`/`disable` act as the
|
|
193
308
|
* signed-in user, so they need the end-user access token. `challenge` does
|
|
@@ -221,7 +336,8 @@ declare class MfaApi {
|
|
|
221
336
|
declare class AuthApi {
|
|
222
337
|
private readonly transport;
|
|
223
338
|
readonly mfa: MfaApi;
|
|
224
|
-
|
|
339
|
+
private readonly sessions;
|
|
340
|
+
constructor(transport: Transport, sessionOptions?: SessionOptions);
|
|
225
341
|
/** Create an account. If the project requires email verification the
|
|
226
342
|
* response has `verification_required: true` and NO tokens; collect a
|
|
227
343
|
* code and call `verifyEmail`, then `login`. */
|
|
@@ -230,10 +346,39 @@ declare class AuthApi {
|
|
|
230
346
|
* challenge (finish via `mfa.challenge`); otherwise `tokens` is your
|
|
231
347
|
* session. A 403 `EmailNotVerified` means the email step isn't done. */
|
|
232
348
|
login(input: LoginInput): Promise<LoginResult>;
|
|
233
|
-
/** Resolve the signed-in user from their access token, or `{ user: null }`.
|
|
349
|
+
/** Resolve the signed-in user from their access token, or `{ user: null }`.
|
|
350
|
+
* This is a network round-trip; for a per-navigation guard prefer
|
|
351
|
+
* `getSession`, which can answer offline and caches verified results. */
|
|
234
352
|
me(input: {
|
|
235
353
|
accessToken: string;
|
|
354
|
+
timeoutMs?: number;
|
|
236
355
|
}): Promise<MeResult>;
|
|
356
|
+
/**
|
|
357
|
+
* Resolve an access token into a session for a route guard, the one call
|
|
358
|
+
* that replaces "hit `me` on every navigation". Two modes:
|
|
359
|
+
*
|
|
360
|
+
* - `'optimistic'` (default): decode the token locally and trust its
|
|
361
|
+
* claims. Zero network, zero stall. The right default for gating page
|
|
362
|
+
* loads. It does NOT verify the signature and will not notice a
|
|
363
|
+
* server-side revocation until the token's own `exp`.
|
|
364
|
+
* - `'verified'`: confirm against the gateway's `me`, cached for a short
|
|
365
|
+
* TTL with a hard timeout. Use it before sensitive actions. On a
|
|
366
|
+
* timeout/outage it returns `status: 'unavailable'` with the optimistic
|
|
367
|
+
* user, so you choose whether to fail open rather than the SDK guessing.
|
|
368
|
+
*
|
|
369
|
+
* See the BYOC docs ("Sessions") for the full reasoning and best practices.
|
|
370
|
+
*/
|
|
371
|
+
getSession(input: GetSessionInput): Promise<SessionResult>;
|
|
372
|
+
/** Read the access token from a `Cookie` request header and resolve it, in
|
|
373
|
+
* one call. `name` defaults to `dc_access_token`. Returns the anonymous
|
|
374
|
+
* session when no cookie is present. */
|
|
375
|
+
sessionFromCookies(cookieHeader: string | null | undefined, options?: {
|
|
376
|
+
mode?: GetSessionInput['mode'];
|
|
377
|
+
cookieName?: string;
|
|
378
|
+
}): Promise<SessionResult>;
|
|
379
|
+
/** Decode an access token's claims locally without a network call or any
|
|
380
|
+
* signature check. Convenience re-export of `decodeAccessToken`. */
|
|
381
|
+
decodeToken(token: string): DecodedSession | null;
|
|
237
382
|
/** Confirm the 6-digit code emailed at signup. */
|
|
238
383
|
verifyEmail(input: VerifyEmailInput): Promise<SimpleResult>;
|
|
239
384
|
forgotPassword(input: ForgotPasswordInput): Promise<SimpleResult>;
|
|
@@ -339,6 +484,12 @@ interface DontCodeClientOptions {
|
|
|
339
484
|
/** Gateway origin. Defaults to `process.env.DONTCODE_API_URL`, then to
|
|
340
485
|
* `https://backend.dontcode.co`. */
|
|
341
486
|
baseUrl?: string;
|
|
487
|
+
/** Per-request network timeout in ms. Defaults to 10_000; `0` disables it.
|
|
488
|
+
* Without one, a slow gateway can hang a request for the full socket
|
|
489
|
+
* timeout, the worst case for an auth guard. */
|
|
490
|
+
timeoutMs?: number;
|
|
491
|
+
/** Caching + timeout policy for `auth.getSession` / `auth.sessionFromCookies`. */
|
|
492
|
+
session?: SessionOptions;
|
|
342
493
|
}
|
|
343
494
|
interface DontCodeClient {
|
|
344
495
|
auth: AuthApi;
|
|
@@ -367,6 +518,11 @@ declare function dontcode(options?: DontCodeClientOptions): DontCodeClient;
|
|
|
367
518
|
* Note: many "one more step" auth states (signup needing email verification,
|
|
368
519
|
* login returning `mfa_required`) are 2xx successes, NOT errors; inspect the
|
|
369
520
|
* resolved value for those. Errors are reserved for actual failures.
|
|
521
|
+
*
|
|
522
|
+
* Transport failures (no HTTP response at all) also surface as a DontCodeError
|
|
523
|
+
* so callers have one error type: a timeout is status 408 / code `Timeout`, and
|
|
524
|
+
* any other network failure is status 0 / code `NetworkError`. Neither is a
|
|
525
|
+
* `401`, so a guard can distinguish "backend unavailable" from "signed out".
|
|
370
526
|
*/
|
|
371
527
|
interface DontCodeErrorBody {
|
|
372
528
|
error?: string;
|
|
@@ -392,4 +548,41 @@ declare class DontCodeError extends Error {
|
|
|
392
548
|
/** Cross-bundle-safe check; works even if two copies of the SDK are loaded. */
|
|
393
549
|
declare function isDontCodeError(err: unknown): err is DontCodeError;
|
|
394
550
|
|
|
395
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Cookie helpers, framework-agnostic by design. They return strings: a
|
|
553
|
+
* `Set-Cookie` header value to write, or a parsed token to read. Your framework
|
|
554
|
+
* applies them (`headers.append('Set-Cookie', …)`, SvelteKit `cookies.set`, a
|
|
555
|
+
* Next `Response` cookie, etc.). The SDK never owns a request or response.
|
|
556
|
+
*
|
|
557
|
+
* Defaults match how DontCode's own apps store the session: an httpOnly cookie
|
|
558
|
+
* so JavaScript can't read the token, `Secure`, `SameSite=Lax`, path `/`, and a
|
|
559
|
+
* 7-day max age. Cross-site setups (your app and the gateway on different sites)
|
|
560
|
+
* need `sameSite: 'none'`, which forces `Secure` on.
|
|
561
|
+
*/
|
|
562
|
+
/** Default cookie name for the end-user access token. */
|
|
563
|
+
declare const DEFAULT_SESSION_COOKIE_NAME = "dc_access_token";
|
|
564
|
+
interface SessionCookieOptions {
|
|
565
|
+
/** Cookie name. Default `dc_access_token`. */
|
|
566
|
+
name?: string;
|
|
567
|
+
/** Lifetime in seconds. Default one week. Pass the token's `ExpiresIn` to
|
|
568
|
+
* keep the cookie and the token in lockstep. */
|
|
569
|
+
maxAge?: number;
|
|
570
|
+
/** Default `/`. */
|
|
571
|
+
path?: string;
|
|
572
|
+
domain?: string;
|
|
573
|
+
/** Default `true`. */
|
|
574
|
+
secure?: boolean;
|
|
575
|
+
/** Default `true`. Keep the token unreadable from client JavaScript. */
|
|
576
|
+
httpOnly?: boolean;
|
|
577
|
+
/** Default `'lax'`. Use `'none'` for cross-site (it forces `Secure`). */
|
|
578
|
+
sameSite?: 'lax' | 'strict' | 'none';
|
|
579
|
+
}
|
|
580
|
+
/** Build a `Set-Cookie` value that stores the access token. */
|
|
581
|
+
declare function serializeSessionCookie(token: string, options?: SessionCookieOptions): string;
|
|
582
|
+
/** Build a `Set-Cookie` value that clears the access token (logout). */
|
|
583
|
+
declare function clearSessionCookie(options?: SessionCookieOptions): string;
|
|
584
|
+
/** Read the access token out of a `Cookie` request header, or `null`. Pass the
|
|
585
|
+
* raw header string (`name=value; name2=value2`). */
|
|
586
|
+
declare function readSessionToken(cookieHeader: string | null | undefined, name?: string): string | null;
|
|
587
|
+
|
|
588
|
+
export { AuthApi, type AuthTokens, BucketClient, type CurrentUser, DEFAULT_SESSION_COOKIE_NAME, type DbClient, type DecodedSession, type DeleteInput, type DontCodeClient, type DontCodeClientOptions, DontCodeError, type DontCodeErrorBody, type DownloadResult, type ForgotPasswordInput, type GetSessionInput, InMemorySessionCache, type ListResult, type LoginInput, type LoginResult, type MeResult, MfaApi, type MfaChallengeInput, type MfaDisableInput, type MfaEnrollConfirmInput, type MfaEnrollResult, type MigrateInput, type MigrateResult, type OrderByClause, type PresignResult, PublicBucketClient, type QueryOptions, type ResetPasswordInput, type SessionCache, type SessionCookieOptions, type SessionOptions, type SessionResult, type SessionStatus, type SignupInput, type SignupResult, type SimpleResult, type StorageBucket, type StorageClient, type StorageObject, TableQuery, type TemporaryUrlResult, type UpdateInput, type UploadBody, type VerifyEmailInput, type WhereClause, type WhereOperator, clearSessionCookie, createStorage, decodeAccessToken, dontcode, isDontCodeError, isSessionExpired, readSessionToken, serializeSessionCookie };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,11 +4,16 @@ interface TransportConfig {
|
|
|
4
4
|
apiKey?: string;
|
|
5
5
|
/** Gateway origin, already normalized (no trailing slash). */
|
|
6
6
|
baseUrl: string;
|
|
7
|
+
/** Per-request timeout in ms. Defaults to `DEFAULT_TIMEOUT_MS`; `0` (or any
|
|
8
|
+
* non-positive value) disables it. */
|
|
9
|
+
timeoutMs?: number;
|
|
7
10
|
}
|
|
8
11
|
interface RequestOptions {
|
|
9
12
|
/** End-user access token, sent as `X-Access-Token` (separate from the
|
|
10
13
|
* project API key). Required by signed-in auth calls. */
|
|
11
14
|
accessToken?: string;
|
|
15
|
+
/** Override the client's timeout for this one call (ms). `0` disables it. */
|
|
16
|
+
timeoutMs?: number;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* The single place network requests are made. Everything else in the SDK is a
|
|
@@ -20,6 +25,15 @@ declare class Transport {
|
|
|
20
25
|
constructor(config: TransportConfig);
|
|
21
26
|
private headers;
|
|
22
27
|
private url;
|
|
28
|
+
private timeout;
|
|
29
|
+
/**
|
|
30
|
+
* One fetch, with a timeout that turns "hung socket" into a fast, typed
|
|
31
|
+
* failure. A timeout surfaces as `DontCodeError` with status 408 / code
|
|
32
|
+
* `Timeout`; any other transport failure (DNS, refused, offline) as status
|
|
33
|
+
* 0 / code `NetworkError`. Both are distinct from a real `401`, so an auth
|
|
34
|
+
* guard can tell "backend is down" apart from "user is signed out".
|
|
35
|
+
*/
|
|
36
|
+
private send;
|
|
23
37
|
/** POST a JSON body and parse the JSON response. */
|
|
24
38
|
json<T>(path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
|
|
25
39
|
/** PUT a multipart form (file uploads). The runtime sets the boundary. */
|
|
@@ -188,6 +202,107 @@ interface TemporaryUrlResult {
|
|
|
188
202
|
/** Bytes the SDK can turn into an upload body. */
|
|
189
203
|
type UploadBody = Blob | ArrayBuffer | ArrayBufferView | string;
|
|
190
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Session helpers, framework-agnostic by design. They never touch a request or
|
|
207
|
+
* response object; they take a token (or a cookie header) and return plain
|
|
208
|
+
* data, so they slot into any framework's guard (Next middleware, SvelteKit
|
|
209
|
+
* hooks, Express, a worker) without an adapter.
|
|
210
|
+
*
|
|
211
|
+
* The point of the module: an auth guard must not make a network round-trip on
|
|
212
|
+
* every navigation, or a slow gateway stalls the page and a swallowed timeout
|
|
213
|
+
* reads as "signed out". So there are two modes:
|
|
214
|
+
*
|
|
215
|
+
* - optimistic — decode the token locally (no signature check, no network)
|
|
216
|
+
* and trust its claims for routing. Instant. Used for the common gate.
|
|
217
|
+
* - verified — call the gateway's `me` once, cache the result for a short
|
|
218
|
+
* TTL, and hard-timeout the request. Used for sensitive actions.
|
|
219
|
+
*
|
|
220
|
+
* The trade-offs (no signature verification, revocation lag) are documented on
|
|
221
|
+
* `getSession` and in the public BYOC docs; read them before choosing a mode.
|
|
222
|
+
*/
|
|
223
|
+
/** A JWT payload decoded WITHOUT verifying its signature. Trust accordingly. */
|
|
224
|
+
interface DecodedSession {
|
|
225
|
+
/** Subject — the user id. */
|
|
226
|
+
sub: string;
|
|
227
|
+
email?: string;
|
|
228
|
+
role?: string;
|
|
229
|
+
claims?: Record<string, unknown>;
|
|
230
|
+
/** Expiry, seconds since the epoch (standard JWT `exp`). */
|
|
231
|
+
exp?: number;
|
|
232
|
+
/** Issued-at, seconds since the epoch (standard JWT `iat`). */
|
|
233
|
+
iat?: number;
|
|
234
|
+
[key: string]: unknown;
|
|
235
|
+
}
|
|
236
|
+
type SessionStatus =
|
|
237
|
+
/** A usable session: a present, unexpired token (verified or optimistic). */
|
|
238
|
+
'active'
|
|
239
|
+
/** The token is present but past its `exp`. */
|
|
240
|
+
| 'expired'
|
|
241
|
+
/** No token, or an unparseable one. */
|
|
242
|
+
| 'anonymous'
|
|
243
|
+
/** Verified mode could not reach the gateway (timeout/network/5xx). The
|
|
244
|
+
* optimistically-decoded `user` is still returned so the caller can choose
|
|
245
|
+
* to fail open during an outage instead of logging everyone out. */
|
|
246
|
+
| 'unavailable';
|
|
247
|
+
interface SessionResult {
|
|
248
|
+
status: SessionStatus;
|
|
249
|
+
/** The signed-in user, or `null` when anonymous/expired. In `verified` mode
|
|
250
|
+
* this came from the gateway; in `optimistic` (or `unavailable`) it was
|
|
251
|
+
* decoded from the token's own claims. */
|
|
252
|
+
user: CurrentUser | null;
|
|
253
|
+
/** True only when `user` was confirmed by a gateway `me` call this request
|
|
254
|
+
* (or from a fresh cache entry of one). False for optimistic decodes. */
|
|
255
|
+
verified: boolean;
|
|
256
|
+
/** The token's `exp` (seconds since epoch), when present. */
|
|
257
|
+
expiresAt?: number;
|
|
258
|
+
}
|
|
259
|
+
interface GetSessionInput {
|
|
260
|
+
accessToken: string;
|
|
261
|
+
/** `optimistic` (default): decode locally, zero network. `verified`: confirm
|
|
262
|
+
* against the gateway with caching + a hard timeout. */
|
|
263
|
+
mode?: 'optimistic' | 'verified';
|
|
264
|
+
}
|
|
265
|
+
/** A place to cache verified sessions. Swap the default in-memory store for a
|
|
266
|
+
* shared one (Redis, KV) when running multiple instances. */
|
|
267
|
+
interface SessionCache {
|
|
268
|
+
get(token: string): SessionResult | undefined;
|
|
269
|
+
set(token: string, value: SessionResult, ttlMs: number): void;
|
|
270
|
+
delete?(token: string): void;
|
|
271
|
+
}
|
|
272
|
+
interface SessionOptions {
|
|
273
|
+
/** Cache for verified sessions. Defaults to a per-process `InMemorySessionCache`. */
|
|
274
|
+
cache?: SessionCache;
|
|
275
|
+
/** How long a verified session stays cached. Default 60_000 (60s). Keep it
|
|
276
|
+
* short: a cached session can outlive a server-side revocation by up to
|
|
277
|
+
* this long. */
|
|
278
|
+
ttlMs?: number;
|
|
279
|
+
/** Timeout for the `me` call made by `verified` mode (ms). Default 5_000. */
|
|
280
|
+
verifyTimeoutMs?: number;
|
|
281
|
+
}
|
|
282
|
+
/** Default cache: a `Map` with per-entry TTL. Lives for the life of the process
|
|
283
|
+
* (and is shared across requests on a reused serverless instance). */
|
|
284
|
+
declare class InMemorySessionCache implements SessionCache {
|
|
285
|
+
private readonly store;
|
|
286
|
+
get(token: string): SessionResult | undefined;
|
|
287
|
+
set(token: string, value: SessionResult, ttlMs: number): void;
|
|
288
|
+
delete(token: string): void;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Decode a JWT access token's payload WITHOUT verifying its signature, or
|
|
292
|
+
* return `null` if it is not a parseable JWT. This is deliberately cheap and
|
|
293
|
+
* offline; it is not proof the token is genuine. DontCode tokens are signed
|
|
294
|
+
* with a secret the gateway never shares, so the only authority on a token is
|
|
295
|
+
* the gateway's `me` endpoint — use `getSession({ mode: 'verified' })` when you
|
|
296
|
+
* need that authority.
|
|
297
|
+
*/
|
|
298
|
+
declare function decodeAccessToken(token: string): DecodedSession | null;
|
|
299
|
+
/** True when a token (or already-decoded payload) is past its `exp`. A token
|
|
300
|
+
* with no `exp` is treated as not expired (the caller cannot prove otherwise
|
|
301
|
+
* offline). `skewSeconds` widens the window to absorb clock drift. */
|
|
302
|
+
declare function isSessionExpired(input: string | DecodedSession | null, opts?: {
|
|
303
|
+
skewSeconds?: number;
|
|
304
|
+
}): boolean;
|
|
305
|
+
|
|
191
306
|
/**
|
|
192
307
|
* MFA is per-user and opt-in. `enroll`/`enrollConfirm`/`disable` act as the
|
|
193
308
|
* signed-in user, so they need the end-user access token. `challenge` does
|
|
@@ -221,7 +336,8 @@ declare class MfaApi {
|
|
|
221
336
|
declare class AuthApi {
|
|
222
337
|
private readonly transport;
|
|
223
338
|
readonly mfa: MfaApi;
|
|
224
|
-
|
|
339
|
+
private readonly sessions;
|
|
340
|
+
constructor(transport: Transport, sessionOptions?: SessionOptions);
|
|
225
341
|
/** Create an account. If the project requires email verification the
|
|
226
342
|
* response has `verification_required: true` and NO tokens; collect a
|
|
227
343
|
* code and call `verifyEmail`, then `login`. */
|
|
@@ -230,10 +346,39 @@ declare class AuthApi {
|
|
|
230
346
|
* challenge (finish via `mfa.challenge`); otherwise `tokens` is your
|
|
231
347
|
* session. A 403 `EmailNotVerified` means the email step isn't done. */
|
|
232
348
|
login(input: LoginInput): Promise<LoginResult>;
|
|
233
|
-
/** Resolve the signed-in user from their access token, or `{ user: null }`.
|
|
349
|
+
/** Resolve the signed-in user from their access token, or `{ user: null }`.
|
|
350
|
+
* This is a network round-trip; for a per-navigation guard prefer
|
|
351
|
+
* `getSession`, which can answer offline and caches verified results. */
|
|
234
352
|
me(input: {
|
|
235
353
|
accessToken: string;
|
|
354
|
+
timeoutMs?: number;
|
|
236
355
|
}): Promise<MeResult>;
|
|
356
|
+
/**
|
|
357
|
+
* Resolve an access token into a session for a route guard, the one call
|
|
358
|
+
* that replaces "hit `me` on every navigation". Two modes:
|
|
359
|
+
*
|
|
360
|
+
* - `'optimistic'` (default): decode the token locally and trust its
|
|
361
|
+
* claims. Zero network, zero stall. The right default for gating page
|
|
362
|
+
* loads. It does NOT verify the signature and will not notice a
|
|
363
|
+
* server-side revocation until the token's own `exp`.
|
|
364
|
+
* - `'verified'`: confirm against the gateway's `me`, cached for a short
|
|
365
|
+
* TTL with a hard timeout. Use it before sensitive actions. On a
|
|
366
|
+
* timeout/outage it returns `status: 'unavailable'` with the optimistic
|
|
367
|
+
* user, so you choose whether to fail open rather than the SDK guessing.
|
|
368
|
+
*
|
|
369
|
+
* See the BYOC docs ("Sessions") for the full reasoning and best practices.
|
|
370
|
+
*/
|
|
371
|
+
getSession(input: GetSessionInput): Promise<SessionResult>;
|
|
372
|
+
/** Read the access token from a `Cookie` request header and resolve it, in
|
|
373
|
+
* one call. `name` defaults to `dc_access_token`. Returns the anonymous
|
|
374
|
+
* session when no cookie is present. */
|
|
375
|
+
sessionFromCookies(cookieHeader: string | null | undefined, options?: {
|
|
376
|
+
mode?: GetSessionInput['mode'];
|
|
377
|
+
cookieName?: string;
|
|
378
|
+
}): Promise<SessionResult>;
|
|
379
|
+
/** Decode an access token's claims locally without a network call or any
|
|
380
|
+
* signature check. Convenience re-export of `decodeAccessToken`. */
|
|
381
|
+
decodeToken(token: string): DecodedSession | null;
|
|
237
382
|
/** Confirm the 6-digit code emailed at signup. */
|
|
238
383
|
verifyEmail(input: VerifyEmailInput): Promise<SimpleResult>;
|
|
239
384
|
forgotPassword(input: ForgotPasswordInput): Promise<SimpleResult>;
|
|
@@ -339,6 +484,12 @@ interface DontCodeClientOptions {
|
|
|
339
484
|
/** Gateway origin. Defaults to `process.env.DONTCODE_API_URL`, then to
|
|
340
485
|
* `https://backend.dontcode.co`. */
|
|
341
486
|
baseUrl?: string;
|
|
487
|
+
/** Per-request network timeout in ms. Defaults to 10_000; `0` disables it.
|
|
488
|
+
* Without one, a slow gateway can hang a request for the full socket
|
|
489
|
+
* timeout, the worst case for an auth guard. */
|
|
490
|
+
timeoutMs?: number;
|
|
491
|
+
/** Caching + timeout policy for `auth.getSession` / `auth.sessionFromCookies`. */
|
|
492
|
+
session?: SessionOptions;
|
|
342
493
|
}
|
|
343
494
|
interface DontCodeClient {
|
|
344
495
|
auth: AuthApi;
|
|
@@ -367,6 +518,11 @@ declare function dontcode(options?: DontCodeClientOptions): DontCodeClient;
|
|
|
367
518
|
* Note: many "one more step" auth states (signup needing email verification,
|
|
368
519
|
* login returning `mfa_required`) are 2xx successes, NOT errors; inspect the
|
|
369
520
|
* resolved value for those. Errors are reserved for actual failures.
|
|
521
|
+
*
|
|
522
|
+
* Transport failures (no HTTP response at all) also surface as a DontCodeError
|
|
523
|
+
* so callers have one error type: a timeout is status 408 / code `Timeout`, and
|
|
524
|
+
* any other network failure is status 0 / code `NetworkError`. Neither is a
|
|
525
|
+
* `401`, so a guard can distinguish "backend unavailable" from "signed out".
|
|
370
526
|
*/
|
|
371
527
|
interface DontCodeErrorBody {
|
|
372
528
|
error?: string;
|
|
@@ -392,4 +548,41 @@ declare class DontCodeError extends Error {
|
|
|
392
548
|
/** Cross-bundle-safe check; works even if two copies of the SDK are loaded. */
|
|
393
549
|
declare function isDontCodeError(err: unknown): err is DontCodeError;
|
|
394
550
|
|
|
395
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Cookie helpers, framework-agnostic by design. They return strings: a
|
|
553
|
+
* `Set-Cookie` header value to write, or a parsed token to read. Your framework
|
|
554
|
+
* applies them (`headers.append('Set-Cookie', …)`, SvelteKit `cookies.set`, a
|
|
555
|
+
* Next `Response` cookie, etc.). The SDK never owns a request or response.
|
|
556
|
+
*
|
|
557
|
+
* Defaults match how DontCode's own apps store the session: an httpOnly cookie
|
|
558
|
+
* so JavaScript can't read the token, `Secure`, `SameSite=Lax`, path `/`, and a
|
|
559
|
+
* 7-day max age. Cross-site setups (your app and the gateway on different sites)
|
|
560
|
+
* need `sameSite: 'none'`, which forces `Secure` on.
|
|
561
|
+
*/
|
|
562
|
+
/** Default cookie name for the end-user access token. */
|
|
563
|
+
declare const DEFAULT_SESSION_COOKIE_NAME = "dc_access_token";
|
|
564
|
+
interface SessionCookieOptions {
|
|
565
|
+
/** Cookie name. Default `dc_access_token`. */
|
|
566
|
+
name?: string;
|
|
567
|
+
/** Lifetime in seconds. Default one week. Pass the token's `ExpiresIn` to
|
|
568
|
+
* keep the cookie and the token in lockstep. */
|
|
569
|
+
maxAge?: number;
|
|
570
|
+
/** Default `/`. */
|
|
571
|
+
path?: string;
|
|
572
|
+
domain?: string;
|
|
573
|
+
/** Default `true`. */
|
|
574
|
+
secure?: boolean;
|
|
575
|
+
/** Default `true`. Keep the token unreadable from client JavaScript. */
|
|
576
|
+
httpOnly?: boolean;
|
|
577
|
+
/** Default `'lax'`. Use `'none'` for cross-site (it forces `Secure`). */
|
|
578
|
+
sameSite?: 'lax' | 'strict' | 'none';
|
|
579
|
+
}
|
|
580
|
+
/** Build a `Set-Cookie` value that stores the access token. */
|
|
581
|
+
declare function serializeSessionCookie(token: string, options?: SessionCookieOptions): string;
|
|
582
|
+
/** Build a `Set-Cookie` value that clears the access token (logout). */
|
|
583
|
+
declare function clearSessionCookie(options?: SessionCookieOptions): string;
|
|
584
|
+
/** Read the access token out of a `Cookie` request header, or `null`. Pass the
|
|
585
|
+
* raw header string (`name=value; name2=value2`). */
|
|
586
|
+
declare function readSessionToken(cookieHeader: string | null | undefined, name?: string): string | null;
|
|
587
|
+
|
|
588
|
+
export { AuthApi, type AuthTokens, BucketClient, type CurrentUser, DEFAULT_SESSION_COOKIE_NAME, type DbClient, type DecodedSession, type DeleteInput, type DontCodeClient, type DontCodeClientOptions, DontCodeError, type DontCodeErrorBody, type DownloadResult, type ForgotPasswordInput, type GetSessionInput, InMemorySessionCache, type ListResult, type LoginInput, type LoginResult, type MeResult, MfaApi, type MfaChallengeInput, type MfaDisableInput, type MfaEnrollConfirmInput, type MfaEnrollResult, type MigrateInput, type MigrateResult, type OrderByClause, type PresignResult, PublicBucketClient, type QueryOptions, type ResetPasswordInput, type SessionCache, type SessionCookieOptions, type SessionOptions, type SessionResult, type SessionStatus, type SignupInput, type SignupResult, type SimpleResult, type StorageBucket, type StorageClient, type StorageObject, TableQuery, type TemporaryUrlResult, type UpdateInput, type UploadBody, type VerifyEmailInput, type WhereClause, type WhereOperator, clearSessionCookie, createStorage, decodeAccessToken, dontcode, isDontCodeError, isSessionExpired, readSessionToken, serializeSessionCookie };
|