@dontcode2/backend 0.1.1 → 0.2.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.
Files changed (53) hide show
  1. package/README.md +94 -0
  2. package/dist/auth-device.d.ts +43 -0
  3. package/dist/auth.d.ts +102 -0
  4. package/dist/chunk-2OGEV57K.js +850 -0
  5. package/dist/chunk-2OGEV57K.js.map +1 -0
  6. package/dist/chunk-CAYYXFFZ.js +568 -0
  7. package/dist/chunk-CAYYXFFZ.js.map +1 -0
  8. package/dist/chunk-HSPHQ6OU.js +448 -0
  9. package/dist/chunk-HSPHQ6OU.js.map +1 -0
  10. package/dist/cli.cjs +1062 -0
  11. package/dist/cli.cjs.map +1 -0
  12. package/dist/cli.d.ts +2 -0
  13. package/dist/cli.js +95 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/client.d.ts +36 -0
  16. package/dist/cookies.d.ts +36 -0
  17. package/dist/credentials.d.ts +36 -0
  18. package/dist/db.d.ts +48 -0
  19. package/dist/errors.d.ts +38 -0
  20. package/dist/http.d.ts +48 -0
  21. package/dist/index.cjs +11 -0
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.ts +13 -588
  24. package/dist/index.js +18 -536
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp/index.cjs +972 -0
  27. package/dist/mcp/index.cjs.map +1 -0
  28. package/dist/mcp/index.d.ts +1 -0
  29. package/dist/mcp/index.js +10 -0
  30. package/dist/mcp/index.js.map +1 -0
  31. package/dist/mcp/server.d.ts +6 -0
  32. package/dist/mock/cli.cjs +956 -0
  33. package/dist/mock/cli.cjs.map +1 -0
  34. package/dist/mock/cli.d.ts +2 -0
  35. package/dist/mock/cli.js +90 -0
  36. package/dist/mock/cli.js.map +1 -0
  37. package/dist/mock/db-query.d.ts +67 -0
  38. package/dist/mock/index.cjs +886 -0
  39. package/dist/mock/index.cjs.map +1 -0
  40. package/dist/mock/index.d.ts +19 -0
  41. package/dist/mock/index.js +7 -0
  42. package/dist/mock/index.js.map +1 -0
  43. package/dist/mock/server.d.ts +36 -0
  44. package/dist/node.cjs +1016 -0
  45. package/dist/node.cjs.map +1 -0
  46. package/dist/node.d.ts +8 -0
  47. package/dist/node.js +28 -0
  48. package/dist/node.js.map +1 -0
  49. package/dist/session.d.ts +115 -0
  50. package/dist/storage.d.ts +46 -0
  51. package/dist/types.d.ts +160 -0
  52. package/package.json +32 -2
  53. package/dist/index.d.cts +0 -588
package/dist/index.d.cts DELETED
@@ -1,588 +0,0 @@
1
- interface TransportConfig {
2
- /** Project API key. When absent, no Authorization header is sent and the
3
- * gateway responds with its own "Missing API key" 401. */
4
- apiKey?: string;
5
- /** Gateway origin, already normalized (no trailing slash). */
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;
10
- }
11
- interface RequestOptions {
12
- /** End-user access token, sent as `X-Access-Token` (separate from the
13
- * project API key). Required by signed-in auth calls. */
14
- accessToken?: string;
15
- /** Override the client's timeout for this one call (ms). `0` disables it. */
16
- timeoutMs?: number;
17
- }
18
- /**
19
- * The single place network requests are made. Everything else in the SDK is a
20
- * typed shape around `json()` / `multipart()`. No retries, no caching, just a
21
- * faithful proxy of the v1 gateway.
22
- */
23
- declare class Transport {
24
- private readonly config;
25
- constructor(config: TransportConfig);
26
- private headers;
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;
37
- /** POST a JSON body and parse the JSON response. */
38
- json<T>(path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
39
- /** PUT a multipart form (file uploads). The runtime sets the boundary. */
40
- multipart<T>(path: string, form: FormData, opts?: RequestOptions): Promise<T>;
41
- private parse;
42
- }
43
-
44
- /**
45
- * Wire shapes for the v1 gateway. These mirror the platform contract; they are
46
- * intentionally loose where the platform is (claims, tokens) and additive-only.
47
- */
48
- interface WhereOperator {
49
- equals?: unknown;
50
- not?: unknown;
51
- gt?: unknown;
52
- gte?: unknown;
53
- lt?: unknown;
54
- lte?: unknown;
55
- in?: unknown[];
56
- notIn?: unknown[];
57
- contains?: string;
58
- startsWith?: string;
59
- endsWith?: string;
60
- mode?: 'default' | 'insensitive';
61
- }
62
- interface WhereClause {
63
- [key: string]: unknown;
64
- AND?: WhereClause[];
65
- OR?: WhereClause[];
66
- NOT?: WhereClause;
67
- }
68
- type OrderByClause = Record<string, 'asc' | 'desc'>;
69
- /** Options accepted by read operations (`find`, `findFirst`, `count`). */
70
- interface QueryOptions {
71
- where?: WhereClause;
72
- select?: string[];
73
- orderBy?: OrderByClause;
74
- limit?: number;
75
- offset?: number;
76
- }
77
- interface UpdateInput {
78
- where: WhereClause;
79
- data: Record<string, unknown>;
80
- }
81
- interface DeleteInput {
82
- where: WhereClause;
83
- }
84
- interface MigrateInput {
85
- sql: string;
86
- }
87
- interface MigrateResult {
88
- success: boolean;
89
- executedStatements?: number;
90
- warnings?: string[];
91
- error?: string;
92
- }
93
- interface SignupInput {
94
- email: string;
95
- password: string;
96
- name?: string;
97
- role?: string;
98
- }
99
- interface SignupResult {
100
- success: boolean;
101
- userId?: string;
102
- verified?: boolean;
103
- verification_required?: boolean;
104
- message?: string;
105
- }
106
- interface LoginInput {
107
- email: string;
108
- password: string;
109
- }
110
- interface AuthTokens {
111
- AccessToken: string;
112
- ExpiresIn: number;
113
- }
114
- interface LoginResult {
115
- success: boolean;
116
- userId?: string;
117
- mfa_offered?: boolean;
118
- mfa_enabled?: boolean;
119
- tokens?: AuthTokens;
120
- /** When true the caller holds a challenge, NOT a session; finish via mfa.challenge. */
121
- mfa_required?: boolean;
122
- challenge_token?: string;
123
- challenge_expires_in?: number;
124
- }
125
- interface VerifyEmailInput {
126
- code: string;
127
- /** Accepted but ignored; the code alone resolves the user. */
128
- email?: string;
129
- }
130
- interface ForgotPasswordInput {
131
- email: string;
132
- }
133
- interface ResetPasswordInput {
134
- code: string;
135
- password: string;
136
- email?: string;
137
- }
138
- interface CurrentUser {
139
- id: string;
140
- email: string;
141
- role?: string;
142
- claims?: Record<string, unknown>;
143
- }
144
- interface MeResult {
145
- user: CurrentUser | null;
146
- }
147
- interface MfaChallengeInput {
148
- challengeToken: string;
149
- code?: string;
150
- recoveryCode?: string;
151
- }
152
- interface MfaEnrollResult {
153
- success: boolean;
154
- secret?: string;
155
- otpauth_url?: string;
156
- }
157
- interface MfaEnrollConfirmInput {
158
- accessToken: string;
159
- code: string;
160
- }
161
- interface MfaDisableInput {
162
- accessToken: string;
163
- code?: string;
164
- recoveryCode?: string;
165
- }
166
- interface SimpleResult {
167
- success: boolean;
168
- message?: string;
169
- [key: string]: unknown;
170
- }
171
- type StorageBucket = 'public' | 'private';
172
- interface StorageObject {
173
- key: string;
174
- name: string;
175
- size: number;
176
- contentType: string;
177
- lastModified: string;
178
- isFolder: boolean;
179
- }
180
- interface ListResult {
181
- objects: StorageObject[];
182
- folders: string[];
183
- prefix: string;
184
- truncated: boolean;
185
- continuationToken: string | null;
186
- }
187
- interface DownloadResult {
188
- /** base64-encoded file contents (inline downloads are capped at 8 MB). */
189
- body: string;
190
- contentType: string;
191
- size: number;
192
- }
193
- interface PresignResult {
194
- url: string;
195
- key: string;
196
- expiresIn: number;
197
- }
198
- interface TemporaryUrlResult {
199
- url: string;
200
- expiresIn: number;
201
- }
202
- /** Bytes the SDK can turn into an upload body. */
203
- type UploadBody = Blob | ArrayBuffer | ArrayBufferView | string;
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
-
306
- /**
307
- * MFA is per-user and opt-in. `enroll`/`enrollConfirm`/`disable` act as the
308
- * signed-in user, so they need the end-user access token. `challenge` does
309
- * not; it completes a login that returned `mfa_required`, exchanging the
310
- * short-lived challenge token for real session tokens.
311
- */
312
- declare class MfaApi {
313
- private readonly transport;
314
- constructor(transport: Transport);
315
- /** Complete an MFA login. Pass the `challenge_token` from `login`, plus
316
- * either the authenticator `code` or a `recoveryCode`. */
317
- challenge(input: MfaChallengeInput): Promise<LoginResult>;
318
- /** Begin enrollment. Render the returned `otpauth_url` as a QR code.
319
- * Enrollment stays pending until `enrollConfirm`. */
320
- enroll(input: {
321
- accessToken: string;
322
- }): Promise<MfaEnrollResult>;
323
- /** Confirm enrollment with the first authenticator code. The returned
324
- * `recovery_codes` are shown once and never again. */
325
- enrollConfirm(input: MfaEnrollConfirmInput): Promise<SimpleResult>;
326
- /** Turn MFA off. Proves possession of the second factor via `code` or
327
- * `recoveryCode`. */
328
- disable(input: MfaDisableInput): Promise<SimpleResult>;
329
- }
330
- /**
331
- * Fronts DontCode Auth with the same shapes as the gateway. Two behaviours are
332
- * project settings (not API flags) and your code must handle both states:
333
- * email verification (signup may not return tokens) and MFA (login may be two
334
- * steps). Branch on the resolved value; never assume one round-trip.
335
- */
336
- declare class AuthApi {
337
- private readonly transport;
338
- readonly mfa: MfaApi;
339
- private readonly sessions;
340
- constructor(transport: Transport, sessionOptions?: SessionOptions);
341
- /** Create an account. If the project requires email verification the
342
- * response has `verification_required: true` and NO tokens; collect a
343
- * code and call `verifyEmail`, then `login`. */
344
- signup(input: SignupInput): Promise<SignupResult>;
345
- /** Authenticate. Branch on `mfa_required`: when true you hold only a
346
- * challenge (finish via `mfa.challenge`); otherwise `tokens` is your
347
- * session. A 403 `EmailNotVerified` means the email step isn't done. */
348
- login(input: LoginInput): Promise<LoginResult>;
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. */
352
- me(input: {
353
- accessToken: string;
354
- timeoutMs?: number;
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;
382
- /** Confirm the 6-digit code emailed at signup. */
383
- verifyEmail(input: VerifyEmailInput): Promise<SimpleResult>;
384
- forgotPassword(input: ForgotPasswordInput): Promise<SimpleResult>;
385
- resetPassword(input: ResetPasswordInput): Promise<SimpleResult>;
386
- }
387
-
388
- /**
389
- * A handle to one table. Structured queries only; there is no raw-SQL escape
390
- * hatch (schema changes go through `db.migrate`). `update` and `delete`
391
- * require a `where` clause server-side, so the types make it mandatory.
392
- */
393
- declare class TableQuery {
394
- private readonly transport;
395
- private readonly tableName;
396
- constructor(transport: Transport, tableName: string);
397
- private run;
398
- /** Rows matching the query (max 1000 per call). */
399
- find<T = Record<string, unknown>>(options?: QueryOptions): Promise<T[]>;
400
- /** Alias of `find`. */
401
- findMany<T = Record<string, unknown>>(options?: QueryOptions): Promise<T[]>;
402
- /** The first matching row, or `null`. */
403
- findFirst<T = Record<string, unknown>>(options?: QueryOptions): Promise<T | null>;
404
- /** Alias of `findFirst`. */
405
- findOne<T = Record<string, unknown>>(options?: QueryOptions): Promise<T | null>;
406
- /** Insert one row. Returns `{ id }`. Unique/FK conflicts throw a 409
407
- * DontCodeError, the supported idempotency signal. */
408
- insert(data: Record<string, unknown>): Promise<{
409
- id: unknown;
410
- }>;
411
- /** Update rows matching `where`. Returns `{ count }`. */
412
- update(input: UpdateInput): Promise<{
413
- count: number;
414
- }>;
415
- /** Delete rows matching `where`. Returns `{ count }`. */
416
- delete(input: DeleteInput): Promise<{
417
- count: number;
418
- }>;
419
- /** Count matching rows. */
420
- count(options?: Pick<QueryOptions, 'where'>): Promise<number>;
421
- }
422
- /**
423
- * `db.users.find()` and `db('users').find()` both work; the bracket/callable
424
- * form is there for table names that aren't valid identifiers. `db.migrate()`
425
- * applies schema DDL (the one place migrations enter from outside).
426
- */
427
- type DbClient = {
428
- readonly [tableName: string]: TableQuery;
429
- } & {
430
- (tableName: string): TableQuery;
431
- migrate(input: MigrateInput): Promise<MigrateResult>;
432
- };
433
-
434
- /** Operations available on both buckets. */
435
- declare class BucketClient {
436
- protected readonly transport: Transport;
437
- protected readonly bucket: StorageBucket;
438
- constructor(transport: Transport, bucket: StorageBucket);
439
- protected op<T>(operation: string, params?: Record<string, unknown>): Promise<T>;
440
- /** List objects under `prefix`. */
441
- list(prefix?: string): Promise<ListResult>;
442
- /** Delete one or more objects. Returns `{ deleted }`. */
443
- remove(paths: string[]): Promise<{
444
- deleted: number;
445
- }>;
446
- /** Move/rename an object within the bucket. */
447
- move(from: string, to: string): Promise<{
448
- object: StorageObject;
449
- }>;
450
- createFolder(path: string): Promise<{
451
- created: string;
452
- }>;
453
- /** Download an object inline (≤ 8 MB). Use `getTemporaryUrl` for larger files. */
454
- download(path: string): Promise<DownloadResult>;
455
- /** A short-lived signed URL (default 300s, max 7 days). */
456
- getTemporaryUrl(path: string, expiresIn?: number): Promise<TemporaryUrlResult>;
457
- /** A presigned PUT URL for direct, large uploads (≤ no inline limit). */
458
- presignUpload(path: string, contentType?: string): Promise<PresignResult>;
459
- /** Upload bytes directly (≤ 100 MB). For larger files, `presignUpload`
460
- * then PUT to the returned URL yourself. */
461
- upload(path: string, body: UploadBody, contentType?: string): Promise<{
462
- object: StorageObject;
463
- }>;
464
- }
465
- /** The public bucket additionally exposes stable public URLs. */
466
- declare class PublicBucketClient extends BucketClient {
467
- constructor(transport: Transport);
468
- /** The permanent public URL for an object. */
469
- getUrl(path: string): Promise<{
470
- url: string;
471
- }>;
472
- }
473
- interface StorageClient {
474
- public: PublicBucketClient;
475
- private: BucketClient;
476
- }
477
- declare function createStorage(transport: Transport): StorageClient;
478
-
479
- interface DontCodeClientOptions {
480
- /** Project API key (`dc_…`). Defaults to `process.env.DONTCODE_API_KEY`.
481
- * If neither is set, requests fail naturally with the gateway's
482
- * "Missing API key" 401. */
483
- apiKey?: string;
484
- /** Gateway origin. Defaults to `process.env.DONTCODE_API_URL`, then to
485
- * `https://backend.dontcode.co`. */
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;
493
- }
494
- interface DontCodeClient {
495
- auth: AuthApi;
496
- db: DbClient;
497
- storage: StorageClient;
498
- }
499
- /**
500
- * Create a DontCode backend client. A thin, typed proxy over the v1 HTTP
501
- * gateway: auth, database, and storage. The API key scopes every request to
502
- * a single project; there is nothing else to configure.
503
- *
504
- * ```ts
505
- * import { dontcode } from '@dontcode2/backend'
506
- * const client = dontcode() // reads DONTCODE_API_KEY
507
- * await client.auth.signup({ email, password, role: 'editor' })
508
- * ```
509
- */
510
- declare function dontcode(options?: DontCodeClientOptions): DontCodeClient;
511
-
512
- /**
513
- * Every non-2xx response from the gateway surfaces as a DontCodeError. The
514
- * platform's error envelope is `{ error, ... }`, sometimes with a machine
515
- * `code` (e.g. `EmailNotVerified`, `ChallengeExpired`, `MfaNotOffered`) or
516
- * rate-limit fields. We preserve the whole body so callers can branch on it.
517
- *
518
- * Note: many "one more step" auth states (signup needing email verification,
519
- * login returning `mfa_required`) are 2xx successes, NOT errors; inspect the
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".
526
- */
527
- interface DontCodeErrorBody {
528
- error?: string;
529
- /** Stable machine code, when the platform sends one. */
530
- code?: string;
531
- /** Present on 429 responses. */
532
- rate_limit?: boolean;
533
- /** Seconds until the rate limit resets, on 429 responses. */
534
- timeleft?: number;
535
- [key: string]: unknown;
536
- }
537
- declare class DontCodeError extends Error {
538
- /** HTTP status code of the failing response. */
539
- readonly status: number;
540
- /** Stable machine code, when present (e.g. `EmailNotVerified`). */
541
- readonly code?: string;
542
- /** The raw parsed response body. */
543
- readonly body: DontCodeErrorBody;
544
- constructor(status: number, body: DontCodeErrorBody);
545
- /** True when the request was rejected by the per-key rate limiter. */
546
- get rateLimited(): boolean;
547
- }
548
- /** Cross-bundle-safe check; works even if two copies of the SDK are loaded. */
549
- declare function isDontCodeError(err: unknown): err is DontCodeError;
550
-
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 };