@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
@@ -0,0 +1,568 @@
1
+ // src/cookies.ts
2
+ var DEFAULT_SESSION_COOKIE_NAME = "dc_access_token";
3
+ var DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 7;
4
+ function serialize(name, value, options, maxAge) {
5
+ const sameSite = options.sameSite ?? "lax";
6
+ const secure = sameSite === "none" ? true : options.secure ?? true;
7
+ const httpOnly = options.httpOnly ?? true;
8
+ const path = options.path ?? "/";
9
+ const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${path}`, `Max-Age=${maxAge}`];
10
+ if (options.domain) parts.push(`Domain=${options.domain}`);
11
+ parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
12
+ if (httpOnly) parts.push("HttpOnly");
13
+ if (secure) parts.push("Secure");
14
+ return parts.join("; ");
15
+ }
16
+ function serializeSessionCookie(token, options = {}) {
17
+ const name = options.name ?? DEFAULT_SESSION_COOKIE_NAME;
18
+ const maxAge = options.maxAge ?? DEFAULT_MAX_AGE_SECONDS;
19
+ return serialize(name, token, options, maxAge);
20
+ }
21
+ function clearSessionCookie(options = {}) {
22
+ const name = options.name ?? DEFAULT_SESSION_COOKIE_NAME;
23
+ return serialize(name, "", options, 0);
24
+ }
25
+ function readSessionToken(cookieHeader, name = DEFAULT_SESSION_COOKIE_NAME) {
26
+ if (!cookieHeader) return null;
27
+ for (const pair of cookieHeader.split(";")) {
28
+ const eq = pair.indexOf("=");
29
+ if (eq === -1) continue;
30
+ if (pair.slice(0, eq).trim() !== name) continue;
31
+ const raw = pair.slice(eq + 1).trim();
32
+ if (!raw) return null;
33
+ try {
34
+ return decodeURIComponent(raw);
35
+ } catch {
36
+ return raw;
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+
42
+ // src/errors.ts
43
+ var DontCodeError = class extends Error {
44
+ constructor(status, body) {
45
+ const message = typeof body?.error === "string" && body.error.length > 0 ? body.error : `DontCode request failed with status ${status}`;
46
+ super(message);
47
+ this.name = "DontCodeError";
48
+ this.status = status;
49
+ this.code = typeof body?.code === "string" ? body.code : void 0;
50
+ this.body = body ?? {};
51
+ }
52
+ /** True when the request was rejected by the per-key rate limiter. */
53
+ get rateLimited() {
54
+ return this.status === 429;
55
+ }
56
+ };
57
+ function isDontCodeError(err) {
58
+ if (err instanceof DontCodeError) return true;
59
+ return typeof err === "object" && err !== null && err.name === "DontCodeError";
60
+ }
61
+
62
+ // src/session.ts
63
+ var DEFAULT_TTL_MS = 6e4;
64
+ var DEFAULT_VERIFY_TIMEOUT_MS = 5e3;
65
+ var InMemorySessionCache = class {
66
+ constructor() {
67
+ this.store = /* @__PURE__ */ new Map();
68
+ }
69
+ get(token) {
70
+ const hit = this.store.get(token);
71
+ if (!hit) return void 0;
72
+ if (Date.now() >= hit.expiresAtMs) {
73
+ this.store.delete(token);
74
+ return void 0;
75
+ }
76
+ return hit.value;
77
+ }
78
+ set(token, value, ttlMs) {
79
+ this.store.set(token, { value, expiresAtMs: Date.now() + ttlMs });
80
+ }
81
+ delete(token) {
82
+ this.store.delete(token);
83
+ }
84
+ };
85
+ function base64UrlDecode(segment) {
86
+ const base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
87
+ const padded = base64.length % 4 === 0 ? base64 : base64 + "=".repeat(4 - base64.length % 4);
88
+ if (typeof atob === "function") {
89
+ const binary = atob(padded);
90
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
91
+ return new TextDecoder().decode(bytes);
92
+ }
93
+ return Buffer.from(padded, "base64").toString("utf8");
94
+ }
95
+ function decodeAccessToken(token) {
96
+ if (!token || typeof token !== "string") return null;
97
+ const parts = token.split(".");
98
+ if (parts.length < 2) return null;
99
+ try {
100
+ const payload = JSON.parse(base64UrlDecode(parts[1]));
101
+ if (!payload || typeof payload.sub !== "string") return null;
102
+ return payload;
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+ function isSessionExpired(input, opts = {}) {
108
+ const decoded = typeof input === "string" ? decodeAccessToken(input) : input;
109
+ if (!decoded || typeof decoded.exp !== "number") return false;
110
+ const nowSeconds = Date.now() / 1e3;
111
+ return nowSeconds >= decoded.exp - (opts.skewSeconds ?? 0);
112
+ }
113
+ function userFromClaims(decoded) {
114
+ return {
115
+ id: decoded.sub,
116
+ email: typeof decoded.email === "string" ? decoded.email : "",
117
+ role: decoded.role,
118
+ claims: decoded.claims
119
+ };
120
+ }
121
+ var SessionVerifier = class {
122
+ constructor(auth, options = {}) {
123
+ this.auth = auth;
124
+ this.cache = options.cache ?? new InMemorySessionCache();
125
+ this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
126
+ this.verifyTimeoutMs = options.verifyTimeoutMs ?? DEFAULT_VERIFY_TIMEOUT_MS;
127
+ }
128
+ async getSession({ accessToken, mode = "optimistic" }) {
129
+ const decoded = decodeAccessToken(accessToken);
130
+ if (!decoded) return { status: "anonymous", user: null, verified: false };
131
+ if (isSessionExpired(decoded)) {
132
+ return { status: "expired", user: null, verified: false, expiresAt: decoded.exp };
133
+ }
134
+ const optimistic = {
135
+ status: "active",
136
+ user: userFromClaims(decoded),
137
+ verified: false,
138
+ expiresAt: decoded.exp
139
+ };
140
+ if (mode === "optimistic") return optimistic;
141
+ const cached = this.cache.get(accessToken);
142
+ if (cached) return cached;
143
+ try {
144
+ const { user } = await this.auth.me({
145
+ accessToken,
146
+ timeoutMs: this.verifyTimeoutMs
147
+ });
148
+ const result = user ? { status: "active", user, verified: true, expiresAt: decoded.exp } : { status: "anonymous", user: null, verified: true };
149
+ this.cache.set(accessToken, result, this.ttlMs);
150
+ return result;
151
+ } catch (err) {
152
+ if (isDontCodeError(err) && err.status === 401) {
153
+ return { status: "anonymous", user: null, verified: true };
154
+ }
155
+ return { ...optimistic, status: "unavailable" };
156
+ }
157
+ }
158
+ };
159
+
160
+ // src/auth.ts
161
+ var AUTH_BASE = "/api/v1/auth";
162
+ var MfaApi = class {
163
+ constructor(transport) {
164
+ this.transport = transport;
165
+ }
166
+ /** Complete an MFA login. Pass the `challenge_token` from `login`, plus
167
+ * either the authenticator `code` or a `recoveryCode`. */
168
+ challenge(input) {
169
+ return this.transport.json(`${AUTH_BASE}/mfa/challenge`, {
170
+ challenge_token: input.challengeToken,
171
+ code: input.code,
172
+ recovery_code: input.recoveryCode
173
+ });
174
+ }
175
+ /** Begin enrollment. Render the returned `otpauth_url` as a QR code.
176
+ * Enrollment stays pending until `enrollConfirm`. */
177
+ enroll(input) {
178
+ return this.transport.json(
179
+ `${AUTH_BASE}/mfa/enroll`,
180
+ {},
181
+ { accessToken: input.accessToken }
182
+ );
183
+ }
184
+ /** Confirm enrollment with the first authenticator code. The returned
185
+ * `recovery_codes` are shown once and never again. */
186
+ enrollConfirm(input) {
187
+ return this.transport.json(
188
+ `${AUTH_BASE}/mfa/enroll/confirm`,
189
+ { code: input.code },
190
+ { accessToken: input.accessToken }
191
+ );
192
+ }
193
+ /** Turn MFA off. Proves possession of the second factor via `code` or
194
+ * `recoveryCode`. */
195
+ disable(input) {
196
+ return this.transport.json(
197
+ `${AUTH_BASE}/mfa/disable`,
198
+ { code: input.code, recovery_code: input.recoveryCode },
199
+ { accessToken: input.accessToken }
200
+ );
201
+ }
202
+ };
203
+ var AuthApi = class {
204
+ constructor(transport, sessionOptions) {
205
+ this.transport = transport;
206
+ this.mfa = new MfaApi(transport);
207
+ this.sessions = new SessionVerifier(this, sessionOptions);
208
+ }
209
+ /** Create an account. If the project requires email verification the
210
+ * response has `verification_required: true` and NO tokens; collect a
211
+ * code and call `verifyEmail`, then `login`. */
212
+ signup(input) {
213
+ return this.transport.json(`${AUTH_BASE}/signup`, {
214
+ email: input.email,
215
+ password: input.password,
216
+ name: input.name,
217
+ role: input.role
218
+ });
219
+ }
220
+ /** Authenticate. Branch on `mfa_required`: when true you hold only a
221
+ * challenge (finish via `mfa.challenge`); otherwise `tokens` is your
222
+ * session. A 403 `EmailNotVerified` means the email step isn't done. */
223
+ login(input) {
224
+ return this.transport.json(`${AUTH_BASE}/login`, {
225
+ email: input.email,
226
+ password: input.password
227
+ });
228
+ }
229
+ /** Validate the current credential (API key or device token) and report the
230
+ * project, the caller's role, and which capabilities that role grants.
231
+ * Backs the MCP "is my session still good" check. */
232
+ info() {
233
+ return this.transport.get("/api/v1/info");
234
+ }
235
+ /** Resolve the signed-in user from their access token, or `{ user: null }`.
236
+ * This is a network round-trip; for a per-navigation guard prefer
237
+ * `getSession`, which can answer offline and caches verified results. */
238
+ me(input) {
239
+ return this.transport.json(
240
+ `${AUTH_BASE}/me`,
241
+ {},
242
+ { accessToken: input.accessToken, timeoutMs: input.timeoutMs }
243
+ );
244
+ }
245
+ /**
246
+ * Resolve an access token into a session for a route guard, the one call
247
+ * that replaces "hit `me` on every navigation". Two modes:
248
+ *
249
+ * - `'optimistic'` (default): decode the token locally and trust its
250
+ * claims. Zero network, zero stall. The right default for gating page
251
+ * loads. It does NOT verify the signature and will not notice a
252
+ * server-side revocation until the token's own `exp`.
253
+ * - `'verified'`: confirm against the gateway's `me`, cached for a short
254
+ * TTL with a hard timeout. Use it before sensitive actions. On a
255
+ * timeout/outage it returns `status: 'unavailable'` with the optimistic
256
+ * user, so you choose whether to fail open rather than the SDK guessing.
257
+ *
258
+ * See the BYOC docs ("Sessions") for the full reasoning and best practices.
259
+ */
260
+ getSession(input) {
261
+ return this.sessions.getSession(input);
262
+ }
263
+ /** Read the access token from a `Cookie` request header and resolve it, in
264
+ * one call. `name` defaults to `dc_access_token`. Returns the anonymous
265
+ * session when no cookie is present. */
266
+ sessionFromCookies(cookieHeader, options = {}) {
267
+ const token = readSessionToken(cookieHeader, options.cookieName);
268
+ if (!token) return Promise.resolve({ status: "anonymous", user: null, verified: false });
269
+ return this.sessions.getSession({ accessToken: token, mode: options.mode });
270
+ }
271
+ /** Decode an access token's claims locally without a network call or any
272
+ * signature check. Convenience re-export of `decodeAccessToken`. */
273
+ decodeToken(token) {
274
+ return decodeAccessToken(token);
275
+ }
276
+ /** Confirm the 6-digit code emailed at signup. */
277
+ verifyEmail(input) {
278
+ return this.transport.json(`${AUTH_BASE}/verify-email`, {
279
+ code: input.code,
280
+ email: input.email
281
+ });
282
+ }
283
+ forgotPassword(input) {
284
+ return this.transport.json(`${AUTH_BASE}/forgot-password`, {
285
+ email: input.email
286
+ });
287
+ }
288
+ resetPassword(input) {
289
+ return this.transport.json(`${AUTH_BASE}/reset-password`, {
290
+ code: input.code,
291
+ password: input.password,
292
+ email: input.email
293
+ });
294
+ }
295
+ };
296
+
297
+ // src/db.ts
298
+ var DB_PATH = "/api/v1/db";
299
+ var MIGRATE_PATH = "/api/v1/db/migrate";
300
+ var TableQuery = class {
301
+ constructor(transport, tableName) {
302
+ this.transport = transport;
303
+ this.tableName = tableName;
304
+ }
305
+ async run(operation, options) {
306
+ const res = await this.transport.json(DB_PATH, {
307
+ operation,
308
+ tableName: this.tableName,
309
+ options
310
+ });
311
+ return res.data;
312
+ }
313
+ /** Rows matching the query (max 1000 per call). */
314
+ find(options = {}) {
315
+ return this.run("find", options);
316
+ }
317
+ /** Alias of `find`. */
318
+ findMany(options = {}) {
319
+ return this.run("findMany", options);
320
+ }
321
+ /** The first matching row, or `null`. */
322
+ findFirst(options = {}) {
323
+ return this.run("findFirst", options);
324
+ }
325
+ /** Alias of `findFirst`. */
326
+ findOne(options = {}) {
327
+ return this.run("findOne", options);
328
+ }
329
+ /** Insert one row. Returns `{ id }`. Unique/FK conflicts throw a 409
330
+ * DontCodeError, the supported idempotency signal. */
331
+ insert(data) {
332
+ return this.run("insert", { data });
333
+ }
334
+ /** Update rows matching `where`. Returns `{ count }`. */
335
+ update(input) {
336
+ return this.run("update", { where: input.where, data: input.data });
337
+ }
338
+ /** Delete rows matching `where`. Returns `{ count }`. */
339
+ delete(input) {
340
+ return this.run("delete", { where: input.where });
341
+ }
342
+ /** Count matching rows. */
343
+ count(options = {}) {
344
+ return this.run("count", options);
345
+ }
346
+ };
347
+ function createDb(transport) {
348
+ const table = (tableName) => new TableQuery(transport, tableName);
349
+ const migrate = (input) => transport.json(MIGRATE_PATH, { sql: input.sql });
350
+ return new Proxy(table, {
351
+ get(target, prop, receiver) {
352
+ if (prop === "migrate") return migrate;
353
+ if (typeof prop !== "string" || prop === "then" || prop in target) {
354
+ return Reflect.get(target, prop, receiver);
355
+ }
356
+ return new TableQuery(transport, prop);
357
+ },
358
+ apply(_target, _thisArg, args) {
359
+ return table(args[0]);
360
+ }
361
+ });
362
+ }
363
+
364
+ // src/storage.ts
365
+ var STORAGE_PATH = "/api/v1/storage";
366
+ var DEFAULT_CONTENT_TYPE = "application/octet-stream";
367
+ function toBlob(body, contentType) {
368
+ if (body instanceof Blob) return body;
369
+ if (typeof body === "string") return new Blob([body], { type: contentType });
370
+ if (body instanceof ArrayBuffer) return new Blob([body], { type: contentType });
371
+ if (ArrayBuffer.isView(body)) {
372
+ return new Blob([body], { type: contentType });
373
+ }
374
+ throw new TypeError("upload expects a Blob, ArrayBuffer, typed array, or string");
375
+ }
376
+ function fileName(path) {
377
+ return path.split("/").filter(Boolean).pop() ?? path;
378
+ }
379
+ var BucketClient = class {
380
+ constructor(transport, bucket) {
381
+ this.transport = transport;
382
+ this.bucket = bucket;
383
+ }
384
+ op(operation, params = {}) {
385
+ return this.transport.json(STORAGE_PATH, { operation, bucket: this.bucket, ...params });
386
+ }
387
+ /** List objects under `prefix`. */
388
+ list(prefix) {
389
+ return this.op("list", { prefix });
390
+ }
391
+ /** Delete one or more objects. Returns `{ deleted }`. */
392
+ remove(paths) {
393
+ return this.op("remove", { paths });
394
+ }
395
+ /** Move/rename an object within the bucket. */
396
+ move(from, to) {
397
+ return this.op("move", { from, to });
398
+ }
399
+ createFolder(path) {
400
+ return this.op("createFolder", { path });
401
+ }
402
+ /** Download an object inline (≤ 8 MB). Use `getTemporaryUrl` for larger files. */
403
+ download(path) {
404
+ return this.op("download", { path });
405
+ }
406
+ /** A short-lived signed URL (default 300s, max 7 days). */
407
+ getTemporaryUrl(path, expiresIn) {
408
+ return this.op("getTemporaryUrl", { path, expiresIn });
409
+ }
410
+ /** A presigned PUT URL for direct, large uploads (≤ no inline limit). */
411
+ presignUpload(path, contentType) {
412
+ return this.op("presignUpload", { path, contentType });
413
+ }
414
+ /** Upload bytes directly (≤ 100 MB). For larger files, `presignUpload`
415
+ * then PUT to the returned URL yourself. */
416
+ upload(path, body, contentType = DEFAULT_CONTENT_TYPE) {
417
+ const form = new FormData();
418
+ form.append("file", toBlob(body, contentType), fileName(path));
419
+ form.append("bucket", this.bucket);
420
+ form.append("path", path);
421
+ form.append("contentType", contentType);
422
+ return this.transport.multipart(STORAGE_PATH, form);
423
+ }
424
+ };
425
+ var PublicBucketClient = class extends BucketClient {
426
+ constructor(transport) {
427
+ super(transport, "public");
428
+ }
429
+ /** The permanent public URL for an object. */
430
+ getUrl(path) {
431
+ return this.op("getUrl", { path });
432
+ }
433
+ };
434
+ function createStorage(transport) {
435
+ return {
436
+ public: new PublicBucketClient(transport),
437
+ private: new BucketClient(transport, "private")
438
+ };
439
+ }
440
+
441
+ // src/http.ts
442
+ var DEFAULT_TIMEOUT_MS = 1e4;
443
+ var Transport = class {
444
+ constructor(config) {
445
+ this.config = config;
446
+ }
447
+ headers(opts) {
448
+ const headers = {};
449
+ if (this.config.apiKey) headers["Authorization"] = `Bearer ${this.config.apiKey}`;
450
+ if (opts?.accessToken) headers["X-Access-Token"] = opts.accessToken;
451
+ return headers;
452
+ }
453
+ url(path) {
454
+ return `${this.config.baseUrl}${path}`;
455
+ }
456
+ timeout(opts) {
457
+ const value = opts?.timeoutMs ?? this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
458
+ return value > 0 ? value : 0;
459
+ }
460
+ /**
461
+ * One fetch, with a timeout that turns "hung socket" into a fast, typed
462
+ * failure. A timeout surfaces as `DontCodeError` with status 408 / code
463
+ * `Timeout`; any other transport failure (DNS, refused, offline) as status
464
+ * 0 / code `NetworkError`. Both are distinct from a real `401`, so an auth
465
+ * guard can tell "backend is down" apart from "user is signed out".
466
+ */
467
+ async send(path, init, opts) {
468
+ const timeoutMs = this.timeout(opts);
469
+ const controller = timeoutMs > 0 ? new AbortController() : void 0;
470
+ const timer = controller ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
471
+ try {
472
+ return await fetch(this.url(path), { ...init, signal: controller?.signal });
473
+ } catch (err) {
474
+ if (controller?.signal.aborted) {
475
+ throw new DontCodeError(408, {
476
+ error: `Request to ${path} timed out after ${timeoutMs}ms`,
477
+ code: "Timeout"
478
+ });
479
+ }
480
+ throw new DontCodeError(0, {
481
+ error: err instanceof Error ? err.message : "Network request failed",
482
+ code: "NetworkError"
483
+ });
484
+ } finally {
485
+ if (timer) clearTimeout(timer);
486
+ }
487
+ }
488
+ /** GET and parse the JSON response. */
489
+ async get(path, opts) {
490
+ const res = await this.send(path, { method: "GET", headers: this.headers(opts) }, opts);
491
+ return this.parse(res);
492
+ }
493
+ /** POST a JSON body and parse the JSON response. */
494
+ async json(path, body, opts) {
495
+ const res = await this.send(
496
+ path,
497
+ {
498
+ method: "POST",
499
+ headers: { ...this.headers(opts), "Content-Type": "application/json" },
500
+ body: JSON.stringify(body ?? {})
501
+ },
502
+ opts
503
+ );
504
+ return this.parse(res);
505
+ }
506
+ /** PUT a multipart form (file uploads). The runtime sets the boundary. */
507
+ async multipart(path, form, opts) {
508
+ const res = await this.send(path, { method: "PUT", headers: this.headers(opts), body: form }, opts);
509
+ return this.parse(res);
510
+ }
511
+ async parse(res) {
512
+ const raw = await res.text();
513
+ let data = null;
514
+ if (raw) {
515
+ try {
516
+ data = JSON.parse(raw);
517
+ } catch {
518
+ data = { error: raw };
519
+ }
520
+ }
521
+ if (!res.ok) {
522
+ const body = data && typeof data === "object" ? data : { error: res.statusText || "Request failed" };
523
+ throw new DontCodeError(res.status, body);
524
+ }
525
+ return data;
526
+ }
527
+ };
528
+
529
+ // src/client.ts
530
+ var DEFAULT_BASE_URL = "https://backend.dontcode.co";
531
+ function fromEnv(name) {
532
+ if (typeof process === "undefined" || !process.env) return void 0;
533
+ return process.env[name];
534
+ }
535
+ function dontcode(options = {}) {
536
+ const apiKey = options.apiKey ?? fromEnv("DONTCODE_API_KEY");
537
+ const baseUrl = (options.baseUrl ?? fromEnv("DONTCODE_API_URL") ?? DEFAULT_BASE_URL).replace(
538
+ /\/+$/,
539
+ ""
540
+ );
541
+ const transport = new Transport({ apiKey, baseUrl, timeoutMs: options.timeoutMs });
542
+ return {
543
+ auth: new AuthApi(transport, options.session),
544
+ db: createDb(transport),
545
+ storage: createStorage(transport)
546
+ };
547
+ }
548
+
549
+ export {
550
+ DEFAULT_SESSION_COOKIE_NAME,
551
+ serializeSessionCookie,
552
+ clearSessionCookie,
553
+ readSessionToken,
554
+ DontCodeError,
555
+ isDontCodeError,
556
+ InMemorySessionCache,
557
+ decodeAccessToken,
558
+ isSessionExpired,
559
+ MfaApi,
560
+ AuthApi,
561
+ TableQuery,
562
+ Transport,
563
+ BucketClient,
564
+ PublicBucketClient,
565
+ createStorage,
566
+ dontcode
567
+ };
568
+ //# sourceMappingURL=chunk-CAYYXFFZ.js.map