@dontcode2/backend 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -0
- package/dist/index.cjs +373 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +395 -0
- package/dist/index.d.ts +395 -0
- package/dist/index.js +338 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// src/auth.ts
|
|
2
|
+
var AUTH_BASE = "/api/v1/auth";
|
|
3
|
+
var MfaApi = class {
|
|
4
|
+
constructor(transport) {
|
|
5
|
+
this.transport = transport;
|
|
6
|
+
}
|
|
7
|
+
/** Complete an MFA login. Pass the `challenge_token` from `login`, plus
|
|
8
|
+
* either the authenticator `code` or a `recoveryCode`. */
|
|
9
|
+
challenge(input) {
|
|
10
|
+
return this.transport.json(`${AUTH_BASE}/mfa/challenge`, {
|
|
11
|
+
challenge_token: input.challengeToken,
|
|
12
|
+
code: input.code,
|
|
13
|
+
recovery_code: input.recoveryCode
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/** Begin enrollment. Render the returned `otpauth_url` as a QR code.
|
|
17
|
+
* Enrollment stays pending until `enrollConfirm`. */
|
|
18
|
+
enroll(input) {
|
|
19
|
+
return this.transport.json(
|
|
20
|
+
`${AUTH_BASE}/mfa/enroll`,
|
|
21
|
+
{},
|
|
22
|
+
{ accessToken: input.accessToken }
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
/** Confirm enrollment with the first authenticator code. The returned
|
|
26
|
+
* `recovery_codes` are shown once and never again. */
|
|
27
|
+
enrollConfirm(input) {
|
|
28
|
+
return this.transport.json(
|
|
29
|
+
`${AUTH_BASE}/mfa/enroll/confirm`,
|
|
30
|
+
{ code: input.code },
|
|
31
|
+
{ accessToken: input.accessToken }
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
/** Turn MFA off. Proves possession of the second factor via `code` or
|
|
35
|
+
* `recoveryCode`. */
|
|
36
|
+
disable(input) {
|
|
37
|
+
return this.transport.json(
|
|
38
|
+
`${AUTH_BASE}/mfa/disable`,
|
|
39
|
+
{ code: input.code, recovery_code: input.recoveryCode },
|
|
40
|
+
{ accessToken: input.accessToken }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var AuthApi = class {
|
|
45
|
+
constructor(transport) {
|
|
46
|
+
this.transport = transport;
|
|
47
|
+
this.mfa = new MfaApi(transport);
|
|
48
|
+
}
|
|
49
|
+
/** Create an account. If the project requires email verification the
|
|
50
|
+
* response has `verification_required: true` and NO tokens; collect a
|
|
51
|
+
* code and call `verifyEmail`, then `login`. */
|
|
52
|
+
signup(input) {
|
|
53
|
+
return this.transport.json(`${AUTH_BASE}/signup`, {
|
|
54
|
+
email: input.email,
|
|
55
|
+
password: input.password,
|
|
56
|
+
name: input.name,
|
|
57
|
+
role: input.role
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/** Authenticate. Branch on `mfa_required`: when true you hold only a
|
|
61
|
+
* challenge (finish via `mfa.challenge`); otherwise `tokens` is your
|
|
62
|
+
* session. A 403 `EmailNotVerified` means the email step isn't done. */
|
|
63
|
+
login(input) {
|
|
64
|
+
return this.transport.json(`${AUTH_BASE}/login`, {
|
|
65
|
+
email: input.email,
|
|
66
|
+
password: input.password
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Resolve the signed-in user from their access token, or `{ user: null }`. */
|
|
70
|
+
me(input) {
|
|
71
|
+
return this.transport.json(`${AUTH_BASE}/me`, {}, { accessToken: input.accessToken });
|
|
72
|
+
}
|
|
73
|
+
/** Confirm the 6-digit code emailed at signup. */
|
|
74
|
+
verifyEmail(input) {
|
|
75
|
+
return this.transport.json(`${AUTH_BASE}/verify-email`, {
|
|
76
|
+
code: input.code,
|
|
77
|
+
email: input.email
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
forgotPassword(input) {
|
|
81
|
+
return this.transport.json(`${AUTH_BASE}/forgot-password`, {
|
|
82
|
+
email: input.email
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
resetPassword(input) {
|
|
86
|
+
return this.transport.json(`${AUTH_BASE}/reset-password`, {
|
|
87
|
+
code: input.code,
|
|
88
|
+
password: input.password,
|
|
89
|
+
email: input.email
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/db.ts
|
|
95
|
+
var DB_PATH = "/api/v1/db";
|
|
96
|
+
var MIGRATE_PATH = "/api/v1/db/migrate";
|
|
97
|
+
var TableQuery = class {
|
|
98
|
+
constructor(transport, tableName) {
|
|
99
|
+
this.transport = transport;
|
|
100
|
+
this.tableName = tableName;
|
|
101
|
+
}
|
|
102
|
+
async run(operation, options) {
|
|
103
|
+
const res = await this.transport.json(DB_PATH, {
|
|
104
|
+
operation,
|
|
105
|
+
tableName: this.tableName,
|
|
106
|
+
options
|
|
107
|
+
});
|
|
108
|
+
return res.data;
|
|
109
|
+
}
|
|
110
|
+
/** Rows matching the query (max 1000 per call). */
|
|
111
|
+
find(options = {}) {
|
|
112
|
+
return this.run("find", options);
|
|
113
|
+
}
|
|
114
|
+
/** Alias of `find`. */
|
|
115
|
+
findMany(options = {}) {
|
|
116
|
+
return this.run("findMany", options);
|
|
117
|
+
}
|
|
118
|
+
/** The first matching row, or `null`. */
|
|
119
|
+
findFirst(options = {}) {
|
|
120
|
+
return this.run("findFirst", options);
|
|
121
|
+
}
|
|
122
|
+
/** Alias of `findFirst`. */
|
|
123
|
+
findOne(options = {}) {
|
|
124
|
+
return this.run("findOne", options);
|
|
125
|
+
}
|
|
126
|
+
/** Insert one row. Returns `{ id }`. Unique/FK conflicts throw a 409
|
|
127
|
+
* DontCodeError, the supported idempotency signal. */
|
|
128
|
+
insert(data) {
|
|
129
|
+
return this.run("insert", { data });
|
|
130
|
+
}
|
|
131
|
+
/** Update rows matching `where`. Returns `{ count }`. */
|
|
132
|
+
update(input) {
|
|
133
|
+
return this.run("update", { where: input.where, data: input.data });
|
|
134
|
+
}
|
|
135
|
+
/** Delete rows matching `where`. Returns `{ count }`. */
|
|
136
|
+
delete(input) {
|
|
137
|
+
return this.run("delete", { where: input.where });
|
|
138
|
+
}
|
|
139
|
+
/** Count matching rows. */
|
|
140
|
+
count(options = {}) {
|
|
141
|
+
return this.run("count", options);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
function createDb(transport) {
|
|
145
|
+
const table = (tableName) => new TableQuery(transport, tableName);
|
|
146
|
+
const migrate = (input) => transport.json(MIGRATE_PATH, { sql: input.sql });
|
|
147
|
+
return new Proxy(table, {
|
|
148
|
+
get(target, prop, receiver) {
|
|
149
|
+
if (prop === "migrate") return migrate;
|
|
150
|
+
if (typeof prop !== "string" || prop === "then" || prop in target) {
|
|
151
|
+
return Reflect.get(target, prop, receiver);
|
|
152
|
+
}
|
|
153
|
+
return new TableQuery(transport, prop);
|
|
154
|
+
},
|
|
155
|
+
apply(_target, _thisArg, args) {
|
|
156
|
+
return table(args[0]);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/errors.ts
|
|
162
|
+
var DontCodeError = class extends Error {
|
|
163
|
+
constructor(status, body) {
|
|
164
|
+
const message = typeof body?.error === "string" && body.error.length > 0 ? body.error : `DontCode request failed with status ${status}`;
|
|
165
|
+
super(message);
|
|
166
|
+
this.name = "DontCodeError";
|
|
167
|
+
this.status = status;
|
|
168
|
+
this.code = typeof body?.code === "string" ? body.code : void 0;
|
|
169
|
+
this.body = body ?? {};
|
|
170
|
+
}
|
|
171
|
+
/** True when the request was rejected by the per-key rate limiter. */
|
|
172
|
+
get rateLimited() {
|
|
173
|
+
return this.status === 429;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
function isDontCodeError(err) {
|
|
177
|
+
if (err instanceof DontCodeError) return true;
|
|
178
|
+
return typeof err === "object" && err !== null && err.name === "DontCodeError";
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/http.ts
|
|
182
|
+
var Transport = class {
|
|
183
|
+
constructor(config) {
|
|
184
|
+
this.config = config;
|
|
185
|
+
}
|
|
186
|
+
headers(opts) {
|
|
187
|
+
const headers = {};
|
|
188
|
+
if (this.config.apiKey) headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
189
|
+
if (opts?.accessToken) headers["X-Access-Token"] = opts.accessToken;
|
|
190
|
+
return headers;
|
|
191
|
+
}
|
|
192
|
+
url(path) {
|
|
193
|
+
return `${this.config.baseUrl}${path}`;
|
|
194
|
+
}
|
|
195
|
+
/** POST a JSON body and parse the JSON response. */
|
|
196
|
+
async json(path, body, opts) {
|
|
197
|
+
const res = await fetch(this.url(path), {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: { ...this.headers(opts), "Content-Type": "application/json" },
|
|
200
|
+
body: JSON.stringify(body ?? {})
|
|
201
|
+
});
|
|
202
|
+
return this.parse(res);
|
|
203
|
+
}
|
|
204
|
+
/** PUT a multipart form (file uploads). The runtime sets the boundary. */
|
|
205
|
+
async multipart(path, form, opts) {
|
|
206
|
+
const res = await fetch(this.url(path), {
|
|
207
|
+
method: "PUT",
|
|
208
|
+
headers: this.headers(opts),
|
|
209
|
+
body: form
|
|
210
|
+
});
|
|
211
|
+
return this.parse(res);
|
|
212
|
+
}
|
|
213
|
+
async parse(res) {
|
|
214
|
+
const raw = await res.text();
|
|
215
|
+
let data = null;
|
|
216
|
+
if (raw) {
|
|
217
|
+
try {
|
|
218
|
+
data = JSON.parse(raw);
|
|
219
|
+
} catch {
|
|
220
|
+
data = { error: raw };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!res.ok) {
|
|
224
|
+
const body = data && typeof data === "object" ? data : { error: res.statusText || "Request failed" };
|
|
225
|
+
throw new DontCodeError(res.status, body);
|
|
226
|
+
}
|
|
227
|
+
return data;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// src/storage.ts
|
|
232
|
+
var STORAGE_PATH = "/api/v1/storage";
|
|
233
|
+
var DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
|
234
|
+
function toBlob(body, contentType) {
|
|
235
|
+
if (body instanceof Blob) return body;
|
|
236
|
+
if (typeof body === "string") return new Blob([body], { type: contentType });
|
|
237
|
+
if (body instanceof ArrayBuffer) return new Blob([body], { type: contentType });
|
|
238
|
+
if (ArrayBuffer.isView(body)) {
|
|
239
|
+
return new Blob([body], { type: contentType });
|
|
240
|
+
}
|
|
241
|
+
throw new TypeError("upload expects a Blob, ArrayBuffer, typed array, or string");
|
|
242
|
+
}
|
|
243
|
+
function fileName(path) {
|
|
244
|
+
return path.split("/").filter(Boolean).pop() ?? path;
|
|
245
|
+
}
|
|
246
|
+
var BucketClient = class {
|
|
247
|
+
constructor(transport, bucket) {
|
|
248
|
+
this.transport = transport;
|
|
249
|
+
this.bucket = bucket;
|
|
250
|
+
}
|
|
251
|
+
op(operation, params = {}) {
|
|
252
|
+
return this.transport.json(STORAGE_PATH, { operation, bucket: this.bucket, ...params });
|
|
253
|
+
}
|
|
254
|
+
/** List objects under `prefix`. */
|
|
255
|
+
list(prefix) {
|
|
256
|
+
return this.op("list", { prefix });
|
|
257
|
+
}
|
|
258
|
+
/** Delete one or more objects. Returns `{ deleted }`. */
|
|
259
|
+
remove(paths) {
|
|
260
|
+
return this.op("remove", { paths });
|
|
261
|
+
}
|
|
262
|
+
/** Move/rename an object within the bucket. */
|
|
263
|
+
move(from, to) {
|
|
264
|
+
return this.op("move", { from, to });
|
|
265
|
+
}
|
|
266
|
+
createFolder(path) {
|
|
267
|
+
return this.op("createFolder", { path });
|
|
268
|
+
}
|
|
269
|
+
/** Download an object inline (≤ 8 MB). Use `getTemporaryUrl` for larger files. */
|
|
270
|
+
download(path) {
|
|
271
|
+
return this.op("download", { path });
|
|
272
|
+
}
|
|
273
|
+
/** A short-lived signed URL (default 300s, max 7 days). */
|
|
274
|
+
getTemporaryUrl(path, expiresIn) {
|
|
275
|
+
return this.op("getTemporaryUrl", { path, expiresIn });
|
|
276
|
+
}
|
|
277
|
+
/** A presigned PUT URL for direct, large uploads (≤ no inline limit). */
|
|
278
|
+
presignUpload(path, contentType) {
|
|
279
|
+
return this.op("presignUpload", { path, contentType });
|
|
280
|
+
}
|
|
281
|
+
/** Upload bytes directly (≤ 100 MB). For larger files, `presignUpload`
|
|
282
|
+
* then PUT to the returned URL yourself. */
|
|
283
|
+
upload(path, body, contentType = DEFAULT_CONTENT_TYPE) {
|
|
284
|
+
const form = new FormData();
|
|
285
|
+
form.append("file", toBlob(body, contentType), fileName(path));
|
|
286
|
+
form.append("bucket", this.bucket);
|
|
287
|
+
form.append("path", path);
|
|
288
|
+
form.append("contentType", contentType);
|
|
289
|
+
return this.transport.multipart(STORAGE_PATH, form);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var PublicBucketClient = class extends BucketClient {
|
|
293
|
+
constructor(transport) {
|
|
294
|
+
super(transport, "public");
|
|
295
|
+
}
|
|
296
|
+
/** The permanent public URL for an object. */
|
|
297
|
+
getUrl(path) {
|
|
298
|
+
return this.op("getUrl", { path });
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
function createStorage(transport) {
|
|
302
|
+
return {
|
|
303
|
+
public: new PublicBucketClient(transport),
|
|
304
|
+
private: new BucketClient(transport, "private")
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/client.ts
|
|
309
|
+
var DEFAULT_BASE_URL = "https://backend.dontcode.co";
|
|
310
|
+
function fromEnv(name) {
|
|
311
|
+
if (typeof process === "undefined" || !process.env) return void 0;
|
|
312
|
+
return process.env[name];
|
|
313
|
+
}
|
|
314
|
+
function dontcode(options = {}) {
|
|
315
|
+
const apiKey = options.apiKey ?? fromEnv("DONTCODE_API_KEY");
|
|
316
|
+
const baseUrl = (options.baseUrl ?? fromEnv("DONTCODE_API_URL") ?? DEFAULT_BASE_URL).replace(
|
|
317
|
+
/\/+$/,
|
|
318
|
+
""
|
|
319
|
+
);
|
|
320
|
+
const transport = new Transport({ apiKey, baseUrl });
|
|
321
|
+
return {
|
|
322
|
+
auth: new AuthApi(transport),
|
|
323
|
+
db: createDb(transport),
|
|
324
|
+
storage: createStorage(transport)
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
export {
|
|
328
|
+
AuthApi,
|
|
329
|
+
BucketClient,
|
|
330
|
+
DontCodeError,
|
|
331
|
+
MfaApi,
|
|
332
|
+
PublicBucketClient,
|
|
333
|
+
TableQuery,
|
|
334
|
+
createStorage,
|
|
335
|
+
dontcode,
|
|
336
|
+
isDontCodeError
|
|
337
|
+
};
|
|
338
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts","../src/db.ts","../src/errors.ts","../src/http.ts","../src/storage.ts","../src/client.ts"],"sourcesContent":["import { Transport } from './http'\nimport type {\n ForgotPasswordInput,\n LoginInput,\n LoginResult,\n MeResult,\n MfaChallengeInput,\n MfaDisableInput,\n MfaEnrollConfirmInput,\n MfaEnrollResult,\n ResetPasswordInput,\n SignupInput,\n SignupResult,\n SimpleResult,\n VerifyEmailInput,\n} from './types'\n\nconst AUTH_BASE = '/api/v1/auth'\n\n/**\n * MFA is per-user and opt-in. `enroll`/`enrollConfirm`/`disable` act as the\n * signed-in user, so they need the end-user access token. `challenge` does\n * not; it completes a login that returned `mfa_required`, exchanging the\n * short-lived challenge token for real session tokens.\n */\nexport class MfaApi {\n constructor(private readonly transport: Transport) {}\n\n /** Complete an MFA login. Pass the `challenge_token` from `login`, plus\n * either the authenticator `code` or a `recoveryCode`. */\n challenge(input: MfaChallengeInput): Promise<LoginResult> {\n return this.transport.json<LoginResult>(`${AUTH_BASE}/mfa/challenge`, {\n challenge_token: input.challengeToken,\n code: input.code,\n recovery_code: input.recoveryCode,\n })\n }\n\n /** Begin enrollment. Render the returned `otpauth_url` as a QR code.\n * Enrollment stays pending until `enrollConfirm`. */\n enroll(input: { accessToken: string }): Promise<MfaEnrollResult> {\n return this.transport.json<MfaEnrollResult>(\n `${AUTH_BASE}/mfa/enroll`,\n {},\n { accessToken: input.accessToken }\n )\n }\n\n /** Confirm enrollment with the first authenticator code. The returned\n * `recovery_codes` are shown once and never again. */\n enrollConfirm(input: MfaEnrollConfirmInput): Promise<SimpleResult> {\n return this.transport.json<SimpleResult>(\n `${AUTH_BASE}/mfa/enroll/confirm`,\n { code: input.code },\n { accessToken: input.accessToken }\n )\n }\n\n /** Turn MFA off. Proves possession of the second factor via `code` or\n * `recoveryCode`. */\n disable(input: MfaDisableInput): Promise<SimpleResult> {\n return this.transport.json<SimpleResult>(\n `${AUTH_BASE}/mfa/disable`,\n { code: input.code, recovery_code: input.recoveryCode },\n { accessToken: input.accessToken }\n )\n }\n}\n\n/**\n * Fronts DontCode Auth with the same shapes as the gateway. Two behaviours are\n * project settings (not API flags) and your code must handle both states:\n * email verification (signup may not return tokens) and MFA (login may be two\n * steps). Branch on the resolved value; never assume one round-trip.\n */\nexport class AuthApi {\n readonly mfa: MfaApi\n\n constructor(private readonly transport: Transport) {\n this.mfa = new MfaApi(transport)\n }\n\n /** Create an account. If the project requires email verification the\n * response has `verification_required: true` and NO tokens; collect a\n * code and call `verifyEmail`, then `login`. */\n signup(input: SignupInput): Promise<SignupResult> {\n return this.transport.json<SignupResult>(`${AUTH_BASE}/signup`, {\n email: input.email,\n password: input.password,\n name: input.name,\n role: input.role,\n })\n }\n\n /** Authenticate. Branch on `mfa_required`: when true you hold only a\n * challenge (finish via `mfa.challenge`); otherwise `tokens` is your\n * session. A 403 `EmailNotVerified` means the email step isn't done. */\n login(input: LoginInput): Promise<LoginResult> {\n return this.transport.json<LoginResult>(`${AUTH_BASE}/login`, {\n email: input.email,\n password: input.password,\n })\n }\n\n /** Resolve the signed-in user from their access token, or `{ user: null }`. */\n me(input: { accessToken: string }): Promise<MeResult> {\n return this.transport.json<MeResult>(`${AUTH_BASE}/me`, {}, { accessToken: input.accessToken })\n }\n\n /** Confirm the 6-digit code emailed at signup. */\n verifyEmail(input: VerifyEmailInput): Promise<SimpleResult> {\n return this.transport.json<SimpleResult>(`${AUTH_BASE}/verify-email`, {\n code: input.code,\n email: input.email,\n })\n }\n\n forgotPassword(input: ForgotPasswordInput): Promise<SimpleResult> {\n return this.transport.json<SimpleResult>(`${AUTH_BASE}/forgot-password`, {\n email: input.email,\n })\n }\n\n resetPassword(input: ResetPasswordInput): Promise<SimpleResult> {\n return this.transport.json<SimpleResult>(`${AUTH_BASE}/reset-password`, {\n code: input.code,\n password: input.password,\n email: input.email,\n })\n }\n}\n","import { Transport } from './http'\nimport type {\n DeleteInput,\n MigrateInput,\n MigrateResult,\n QueryOptions,\n UpdateInput,\n} from './types'\n\nconst DB_PATH = '/api/v1/db'\nconst MIGRATE_PATH = '/api/v1/db/migrate'\n\n/** The gateway wraps every DB result in `{ data }`; we unwrap it. */\ninterface DbEnvelope<T> {\n data: T\n}\n\n/**\n * A handle to one table. Structured queries only; there is no raw-SQL escape\n * hatch (schema changes go through `db.migrate`). `update` and `delete`\n * require a `where` clause server-side, so the types make it mandatory.\n */\nexport class TableQuery {\n constructor(\n private readonly transport: Transport,\n private readonly tableName: string\n ) {}\n\n private async run<T>(operation: string, options: unknown): Promise<T> {\n const res = await this.transport.json<DbEnvelope<T>>(DB_PATH, {\n operation,\n tableName: this.tableName,\n options,\n })\n return res.data\n }\n\n /** Rows matching the query (max 1000 per call). */\n find<T = Record<string, unknown>>(options: QueryOptions = {}): Promise<T[]> {\n return this.run<T[]>('find', options)\n }\n\n /** Alias of `find`. */\n findMany<T = Record<string, unknown>>(options: QueryOptions = {}): Promise<T[]> {\n return this.run<T[]>('findMany', options)\n }\n\n /** The first matching row, or `null`. */\n findFirst<T = Record<string, unknown>>(options: QueryOptions = {}): Promise<T | null> {\n return this.run<T | null>('findFirst', options)\n }\n\n /** Alias of `findFirst`. */\n findOne<T = Record<string, unknown>>(options: QueryOptions = {}): Promise<T | null> {\n return this.run<T | null>('findOne', options)\n }\n\n /** Insert one row. Returns `{ id }`. Unique/FK conflicts throw a 409\n * DontCodeError, the supported idempotency signal. */\n insert(data: Record<string, unknown>): Promise<{ id: unknown }> {\n return this.run<{ id: unknown }>('insert', { data })\n }\n\n /** Update rows matching `where`. Returns `{ count }`. */\n update(input: UpdateInput): Promise<{ count: number }> {\n return this.run<{ count: number }>('update', { where: input.where, data: input.data })\n }\n\n /** Delete rows matching `where`. Returns `{ count }`. */\n delete(input: DeleteInput): Promise<{ count: number }> {\n return this.run<{ count: number }>('delete', { where: input.where })\n }\n\n /** Count matching rows. */\n count(options: Pick<QueryOptions, 'where'> = {}): Promise<number> {\n return this.run<number>('count', options)\n }\n}\n\n/**\n * `db.users.find()` and `db('users').find()` both work; the bracket/callable\n * form is there for table names that aren't valid identifiers. `db.migrate()`\n * applies schema DDL (the one place migrations enter from outside).\n */\nexport type DbClient = {\n readonly [tableName: string]: TableQuery\n} & {\n (tableName: string): TableQuery\n migrate(input: MigrateInput): Promise<MigrateResult>\n}\n\nexport function createDb(transport: Transport): DbClient {\n const table = (tableName: string): TableQuery => new TableQuery(transport, tableName)\n const migrate = (input: MigrateInput): Promise<MigrateResult> =>\n transport.json<MigrateResult>(MIGRATE_PATH, { sql: input.sql })\n\n return new Proxy(table, {\n get(target, prop, receiver) {\n if (prop === 'migrate') return migrate\n // Don't manufacture a TableQuery for symbols or promise-unwrapping\n // probes (`then`) or the function's own members.\n if (typeof prop !== 'string' || prop === 'then' || prop in target) {\n return Reflect.get(target, prop, receiver)\n }\n return new TableQuery(transport, prop)\n },\n apply(_target, _thisArg, args: [string]) {\n return table(args[0])\n },\n }) as unknown as DbClient\n}\n","/**\n * Every non-2xx response from the gateway surfaces as a DontCodeError. The\n * platform's error envelope is `{ error, ... }`, sometimes with a machine\n * `code` (e.g. `EmailNotVerified`, `ChallengeExpired`, `MfaNotOffered`) or\n * rate-limit fields. We preserve the whole body so callers can branch on it.\n *\n * Note: many \"one more step\" auth states (signup needing email verification,\n * login returning `mfa_required`) are 2xx successes, NOT errors; inspect the\n * resolved value for those. Errors are reserved for actual failures.\n */\nexport interface DontCodeErrorBody {\n error?: string\n /** Stable machine code, when the platform sends one. */\n code?: string\n /** Present on 429 responses. */\n rate_limit?: boolean\n /** Seconds until the rate limit resets, on 429 responses. */\n timeleft?: number\n [key: string]: unknown\n}\n\nexport class DontCodeError extends Error {\n /** HTTP status code of the failing response. */\n readonly status: number\n /** Stable machine code, when present (e.g. `EmailNotVerified`). */\n readonly code?: string\n /** The raw parsed response body. */\n readonly body: DontCodeErrorBody\n\n constructor(status: number, body: DontCodeErrorBody) {\n const message =\n typeof body?.error === 'string' && body.error.length > 0\n ? body.error\n : `DontCode request failed with status ${status}`\n super(message)\n this.name = 'DontCodeError'\n this.status = status\n this.code = typeof body?.code === 'string' ? body.code : undefined\n this.body = body ?? {}\n }\n\n /** True when the request was rejected by the per-key rate limiter. */\n get rateLimited(): boolean {\n return this.status === 429\n }\n}\n\n/** Cross-bundle-safe check; works even if two copies of the SDK are loaded. */\nexport function isDontCodeError(err: unknown): err is DontCodeError {\n if (err instanceof DontCodeError) return true\n return (\n typeof err === 'object' &&\n err !== null &&\n (err as { name?: unknown }).name === 'DontCodeError'\n )\n}\n","import { DontCodeError, type DontCodeErrorBody } from './errors'\n\nexport interface TransportConfig {\n /** Project API key. When absent, no Authorization header is sent and the\n * gateway responds with its own \"Missing API key\" 401. */\n apiKey?: string\n /** Gateway origin, already normalized (no trailing slash). */\n baseUrl: string\n}\n\nexport interface RequestOptions {\n /** End-user access token, sent as `X-Access-Token` (separate from the\n * project API key). Required by signed-in auth calls. */\n accessToken?: string\n}\n\n/**\n * The single place network requests are made. Everything else in the SDK is a\n * typed shape around `json()` / `multipart()`. No retries, no caching, just a\n * faithful proxy of the v1 gateway.\n */\nexport class Transport {\n constructor(private readonly config: TransportConfig) {}\n\n private headers(opts?: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = {}\n if (this.config.apiKey) headers['Authorization'] = `Bearer ${this.config.apiKey}`\n if (opts?.accessToken) headers['X-Access-Token'] = opts.accessToken\n return headers\n }\n\n private url(path: string): string {\n return `${this.config.baseUrl}${path}`\n }\n\n /** POST a JSON body and parse the JSON response. */\n async json<T>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n const res = await fetch(this.url(path), {\n method: 'POST',\n headers: { ...this.headers(opts), 'Content-Type': 'application/json' },\n body: JSON.stringify(body ?? {}),\n })\n return this.parse<T>(res)\n }\n\n /** PUT a multipart form (file uploads). The runtime sets the boundary. */\n async multipart<T>(path: string, form: FormData, opts?: RequestOptions): Promise<T> {\n const res = await fetch(this.url(path), {\n method: 'PUT',\n headers: this.headers(opts),\n body: form,\n })\n return this.parse<T>(res)\n }\n\n private async parse<T>(res: Response): Promise<T> {\n const raw = await res.text()\n let data: unknown = null\n if (raw) {\n try {\n data = JSON.parse(raw)\n } catch {\n data = { error: raw }\n }\n }\n if (!res.ok) {\n const body: DontCodeErrorBody =\n data && typeof data === 'object'\n ? (data as DontCodeErrorBody)\n : { error: res.statusText || 'Request failed' }\n throw new DontCodeError(res.status, body)\n }\n return data as T\n }\n}\n","import { Transport } from './http'\nimport type {\n DownloadResult,\n ListResult,\n PresignResult,\n StorageBucket,\n StorageObject,\n TemporaryUrlResult,\n UploadBody,\n} from './types'\n\nconst STORAGE_PATH = '/api/v1/storage'\n\nconst DEFAULT_CONTENT_TYPE = 'application/octet-stream'\n\n/** Normalize whatever the caller hands us into a Blob for multipart upload. */\nfunction toBlob(body: UploadBody, contentType: string): Blob {\n if (body instanceof Blob) return body\n if (typeof body === 'string') return new Blob([body], { type: contentType })\n if (body instanceof ArrayBuffer) return new Blob([body], { type: contentType })\n if (ArrayBuffer.isView(body)) {\n return new Blob([body as unknown as BlobPart], { type: contentType })\n }\n throw new TypeError('upload expects a Blob, ArrayBuffer, typed array, or string')\n}\n\nfunction fileName(path: string): string {\n return path.split('/').filter(Boolean).pop() ?? path\n}\n\n/** Operations available on both buckets. */\nexport class BucketClient {\n constructor(\n protected readonly transport: Transport,\n protected readonly bucket: StorageBucket\n ) {}\n\n protected op<T>(operation: string, params: Record<string, unknown> = {}): Promise<T> {\n return this.transport.json<T>(STORAGE_PATH, { operation, bucket: this.bucket, ...params })\n }\n\n /** List objects under `prefix`. */\n list(prefix?: string): Promise<ListResult> {\n return this.op<ListResult>('list', { prefix })\n }\n\n /** Delete one or more objects. Returns `{ deleted }`. */\n remove(paths: string[]): Promise<{ deleted: number }> {\n return this.op<{ deleted: number }>('remove', { paths })\n }\n\n /** Move/rename an object within the bucket. */\n move(from: string, to: string): Promise<{ object: StorageObject }> {\n return this.op<{ object: StorageObject }>('move', { from, to })\n }\n\n createFolder(path: string): Promise<{ created: string }> {\n return this.op<{ created: string }>('createFolder', { path })\n }\n\n /** Download an object inline (≤ 8 MB). Use `getTemporaryUrl` for larger files. */\n download(path: string): Promise<DownloadResult> {\n return this.op<DownloadResult>('download', { path })\n }\n\n /** A short-lived signed URL (default 300s, max 7 days). */\n getTemporaryUrl(path: string, expiresIn?: number): Promise<TemporaryUrlResult> {\n return this.op<TemporaryUrlResult>('getTemporaryUrl', { path, expiresIn })\n }\n\n /** A presigned PUT URL for direct, large uploads (≤ no inline limit). */\n presignUpload(path: string, contentType?: string): Promise<PresignResult> {\n return this.op<PresignResult>('presignUpload', { path, contentType })\n }\n\n /** Upload bytes directly (≤ 100 MB). For larger files, `presignUpload`\n * then PUT to the returned URL yourself. */\n upload(\n path: string,\n body: UploadBody,\n contentType: string = DEFAULT_CONTENT_TYPE\n ): Promise<{ object: StorageObject }> {\n const form = new FormData()\n form.append('file', toBlob(body, contentType), fileName(path))\n form.append('bucket', this.bucket)\n form.append('path', path)\n form.append('contentType', contentType)\n return this.transport.multipart<{ object: StorageObject }>(STORAGE_PATH, form)\n }\n}\n\n/** The public bucket additionally exposes stable public URLs. */\nexport class PublicBucketClient extends BucketClient {\n constructor(transport: Transport) {\n super(transport, 'public')\n }\n\n /** The permanent public URL for an object. */\n getUrl(path: string): Promise<{ url: string }> {\n return this.op<{ url: string }>('getUrl', { path })\n }\n}\n\nexport interface StorageClient {\n public: PublicBucketClient\n private: BucketClient\n}\n\nexport function createStorage(transport: Transport): StorageClient {\n return {\n public: new PublicBucketClient(transport),\n private: new BucketClient(transport, 'private'),\n }\n}\n","import { AuthApi } from './auth'\nimport { createDb, type DbClient } from './db'\nimport { Transport } from './http'\nimport { createStorage, type StorageClient } from './storage'\n\nconst DEFAULT_BASE_URL = 'https://backend.dontcode.co'\n\nexport interface DontCodeClientOptions {\n /** Project API key (`dc_…`). Defaults to `process.env.DONTCODE_API_KEY`.\n * If neither is set, requests fail naturally with the gateway's\n * \"Missing API key\" 401. */\n apiKey?: string\n /** Gateway origin. Defaults to `process.env.DONTCODE_API_URL`, then to\n * `https://backend.dontcode.co`. */\n baseUrl?: string\n}\n\nexport interface DontCodeClient {\n auth: AuthApi\n db: DbClient\n storage: StorageClient\n}\n\n/** Read an env var without assuming `process` exists (e.g. in the browser). */\nfunction fromEnv(name: string): string | undefined {\n if (typeof process === 'undefined' || !process.env) return undefined\n return process.env[name]\n}\n\n/**\n * Create a DontCode backend client. A thin, typed proxy over the v1 HTTP\n * gateway: auth, database, and storage. The API key scopes every request to\n * a single project; there is nothing else to configure.\n *\n * ```ts\n * import { dontcode } from '@dontcode2/backend'\n * const client = dontcode() // reads DONTCODE_API_KEY\n * await client.auth.signup({ email, password, role: 'editor' })\n * ```\n */\nexport function dontcode(options: DontCodeClientOptions = {}): DontCodeClient {\n const apiKey = options.apiKey ?? fromEnv('DONTCODE_API_KEY')\n const baseUrl = (options.baseUrl ?? fromEnv('DONTCODE_API_URL') ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n )\n\n const transport = new Transport({ apiKey, baseUrl })\n\n return {\n auth: new AuthApi(transport),\n db: createDb(transport),\n storage: createStorage(transport),\n }\n}\n"],"mappings":";AAiBA,IAAM,YAAY;AAQX,IAAM,SAAN,MAAa;AAAA,EAChB,YAA6B,WAAsB;AAAtB;AAAA,EAAuB;AAAA;AAAA;AAAA,EAIpD,UAAU,OAAgD;AACtD,WAAO,KAAK,UAAU,KAAkB,GAAG,SAAS,kBAAkB;AAAA,MAClE,iBAAiB,MAAM;AAAA,MACvB,MAAM,MAAM;AAAA,MACZ,eAAe,MAAM;AAAA,IACzB,CAAC;AAAA,EACL;AAAA;AAAA;AAAA,EAIA,OAAO,OAA0D;AAC7D,WAAO,KAAK,UAAU;AAAA,MAClB,GAAG,SAAS;AAAA,MACZ,CAAC;AAAA,MACD,EAAE,aAAa,MAAM,YAAY;AAAA,IACrC;AAAA,EACJ;AAAA;AAAA;AAAA,EAIA,cAAc,OAAqD;AAC/D,WAAO,KAAK,UAAU;AAAA,MAClB,GAAG,SAAS;AAAA,MACZ,EAAE,MAAM,MAAM,KAAK;AAAA,MACnB,EAAE,aAAa,MAAM,YAAY;AAAA,IACrC;AAAA,EACJ;AAAA;AAAA;AAAA,EAIA,QAAQ,OAA+C;AACnD,WAAO,KAAK,UAAU;AAAA,MAClB,GAAG,SAAS;AAAA,MACZ,EAAE,MAAM,MAAM,MAAM,eAAe,MAAM,aAAa;AAAA,MACtD,EAAE,aAAa,MAAM,YAAY;AAAA,IACrC;AAAA,EACJ;AACJ;AAQO,IAAM,UAAN,MAAc;AAAA,EAGjB,YAA6B,WAAsB;AAAtB;AACzB,SAAK,MAAM,IAAI,OAAO,SAAS;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAA2C;AAC9C,WAAO,KAAK,UAAU,KAAmB,GAAG,SAAS,WAAW;AAAA,MAC5D,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,IAChB,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAyC;AAC3C,WAAO,KAAK,UAAU,KAAkB,GAAG,SAAS,UAAU;AAAA,MAC1D,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,IACpB,CAAC;AAAA,EACL;AAAA;AAAA,EAGA,GAAG,OAAmD;AAClD,WAAO,KAAK,UAAU,KAAe,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE,aAAa,MAAM,YAAY,CAAC;AAAA,EAClG;AAAA;AAAA,EAGA,YAAY,OAAgD;AACxD,WAAO,KAAK,UAAU,KAAmB,GAAG,SAAS,iBAAiB;AAAA,MAClE,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,IACjB,CAAC;AAAA,EACL;AAAA,EAEA,eAAe,OAAmD;AAC9D,WAAO,KAAK,UAAU,KAAmB,GAAG,SAAS,oBAAoB;AAAA,MACrE,OAAO,MAAM;AAAA,IACjB,CAAC;AAAA,EACL;AAAA,EAEA,cAAc,OAAkD;AAC5D,WAAO,KAAK,UAAU,KAAmB,GAAG,SAAS,mBAAmB;AAAA,MACpE,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,IACjB,CAAC;AAAA,EACL;AACJ;;;ACzHA,IAAM,UAAU;AAChB,IAAM,eAAe;AAYd,IAAM,aAAN,MAAiB;AAAA,EACpB,YACqB,WACA,WACnB;AAFmB;AACA;AAAA,EAClB;AAAA,EAEH,MAAc,IAAO,WAAmB,SAA8B;AAClE,UAAM,MAAM,MAAM,KAAK,UAAU,KAAoB,SAAS;AAAA,MAC1D;AAAA,MACA,WAAW,KAAK;AAAA,MAChB;AAAA,IACJ,CAAC;AACD,WAAO,IAAI;AAAA,EACf;AAAA;AAAA,EAGA,KAAkC,UAAwB,CAAC,GAAiB;AACxE,WAAO,KAAK,IAAS,QAAQ,OAAO;AAAA,EACxC;AAAA;AAAA,EAGA,SAAsC,UAAwB,CAAC,GAAiB;AAC5E,WAAO,KAAK,IAAS,YAAY,OAAO;AAAA,EAC5C;AAAA;AAAA,EAGA,UAAuC,UAAwB,CAAC,GAAsB;AAClF,WAAO,KAAK,IAAc,aAAa,OAAO;AAAA,EAClD;AAAA;AAAA,EAGA,QAAqC,UAAwB,CAAC,GAAsB;AAChF,WAAO,KAAK,IAAc,WAAW,OAAO;AAAA,EAChD;AAAA;AAAA;AAAA,EAIA,OAAO,MAAyD;AAC5D,WAAO,KAAK,IAAqB,UAAU,EAAE,KAAK,CAAC;AAAA,EACvD;AAAA;AAAA,EAGA,OAAO,OAAgD;AACnD,WAAO,KAAK,IAAuB,UAAU,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC;AAAA,EACzF;AAAA;AAAA,EAGA,OAAO,OAAgD;AACnD,WAAO,KAAK,IAAuB,UAAU,EAAE,OAAO,MAAM,MAAM,CAAC;AAAA,EACvE;AAAA;AAAA,EAGA,MAAM,UAAuC,CAAC,GAAoB;AAC9D,WAAO,KAAK,IAAY,SAAS,OAAO;AAAA,EAC5C;AACJ;AAcO,SAAS,SAAS,WAAgC;AACrD,QAAM,QAAQ,CAAC,cAAkC,IAAI,WAAW,WAAW,SAAS;AACpF,QAAM,UAAU,CAAC,UACb,UAAU,KAAoB,cAAc,EAAE,KAAK,MAAM,IAAI,CAAC;AAElE,SAAO,IAAI,MAAM,OAAO;AAAA,IACpB,IAAI,QAAQ,MAAM,UAAU;AACxB,UAAI,SAAS,UAAW,QAAO;AAG/B,UAAI,OAAO,SAAS,YAAY,SAAS,UAAU,QAAQ,QAAQ;AAC/D,eAAO,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC7C;AACA,aAAO,IAAI,WAAW,WAAW,IAAI;AAAA,IACzC;AAAA,IACA,MAAM,SAAS,UAAU,MAAgB;AACrC,aAAO,MAAM,KAAK,CAAC,CAAC;AAAA,IACxB;AAAA,EACJ,CAAC;AACL;;;ACzFO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAQrC,YAAY,QAAgB,MAAyB;AACjD,UAAM,UACF,OAAO,MAAM,UAAU,YAAY,KAAK,MAAM,SAAS,IACjD,KAAK,QACL,uCAAuC,MAAM;AACvD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO,OAAO,MAAM,SAAS,WAAW,KAAK,OAAO;AACzD,SAAK,OAAO,QAAQ,CAAC;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,cAAuB;AACvB,WAAO,KAAK,WAAW;AAAA,EAC3B;AACJ;AAGO,SAAS,gBAAgB,KAAoC;AAChE,MAAI,eAAe,cAAe,QAAO;AACzC,SACI,OAAO,QAAQ,YACf,QAAQ,QACP,IAA2B,SAAS;AAE7C;;;AClCO,IAAM,YAAN,MAAgB;AAAA,EACnB,YAA6B,QAAyB;AAAzB;AAAA,EAA0B;AAAA,EAE/C,QAAQ,MAA+C;AAC3D,UAAM,UAAkC,CAAC;AACzC,QAAI,KAAK,OAAO,OAAQ,SAAQ,eAAe,IAAI,UAAU,KAAK,OAAO,MAAM;AAC/E,QAAI,MAAM,YAAa,SAAQ,gBAAgB,IAAI,KAAK;AACxD,WAAO;AAAA,EACX;AAAA,EAEQ,IAAI,MAAsB;AAC9B,WAAO,GAAG,KAAK,OAAO,OAAO,GAAG,IAAI;AAAA,EACxC;AAAA;AAAA,EAGA,MAAM,KAAQ,MAAc,MAAgB,MAAmC;AAC3E,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACpC,QAAQ;AAAA,MACR,SAAS,EAAE,GAAG,KAAK,QAAQ,IAAI,GAAG,gBAAgB,mBAAmB;AAAA,MACrE,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC;AAAA,IACnC,CAAC;AACD,WAAO,KAAK,MAAS,GAAG;AAAA,EAC5B;AAAA;AAAA,EAGA,MAAM,UAAa,MAAc,MAAgB,MAAmC;AAChF,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACpC,QAAQ;AAAA,MACR,SAAS,KAAK,QAAQ,IAAI;AAAA,MAC1B,MAAM;AAAA,IACV,CAAC;AACD,WAAO,KAAK,MAAS,GAAG;AAAA,EAC5B;AAAA,EAEA,MAAc,MAAS,KAA2B;AAC9C,UAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,QAAI,OAAgB;AACpB,QAAI,KAAK;AACL,UAAI;AACA,eAAO,KAAK,MAAM,GAAG;AAAA,MACzB,QAAQ;AACJ,eAAO,EAAE,OAAO,IAAI;AAAA,MACxB;AAAA,IACJ;AACA,QAAI,CAAC,IAAI,IAAI;AACT,YAAM,OACF,QAAQ,OAAO,SAAS,WACjB,OACD,EAAE,OAAO,IAAI,cAAc,iBAAiB;AACtD,YAAM,IAAI,cAAc,IAAI,QAAQ,IAAI;AAAA,IAC5C;AACA,WAAO;AAAA,EACX;AACJ;;;AC/DA,IAAM,eAAe;AAErB,IAAM,uBAAuB;AAG7B,SAAS,OAAO,MAAkB,aAA2B;AACzD,MAAI,gBAAgB,KAAM,QAAO;AACjC,MAAI,OAAO,SAAS,SAAU,QAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,YAAY,CAAC;AAC3E,MAAI,gBAAgB,YAAa,QAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,YAAY,CAAC;AAC9E,MAAI,YAAY,OAAO,IAAI,GAAG;AAC1B,WAAO,IAAI,KAAK,CAAC,IAA2B,GAAG,EAAE,MAAM,YAAY,CAAC;AAAA,EACxE;AACA,QAAM,IAAI,UAAU,4DAA4D;AACpF;AAEA,SAAS,SAAS,MAAsB;AACpC,SAAO,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AACpD;AAGO,IAAM,eAAN,MAAmB;AAAA,EACtB,YACuB,WACA,QACrB;AAFqB;AACA;AAAA,EACpB;AAAA,EAEO,GAAM,WAAmB,SAAkC,CAAC,GAAe;AACjF,WAAO,KAAK,UAAU,KAAQ,cAAc,EAAE,WAAW,QAAQ,KAAK,QAAQ,GAAG,OAAO,CAAC;AAAA,EAC7F;AAAA;AAAA,EAGA,KAAK,QAAsC;AACvC,WAAO,KAAK,GAAe,QAAQ,EAAE,OAAO,CAAC;AAAA,EACjD;AAAA;AAAA,EAGA,OAAO,OAA+C;AAClD,WAAO,KAAK,GAAwB,UAAU,EAAE,MAAM,CAAC;AAAA,EAC3D;AAAA;AAAA,EAGA,KAAK,MAAc,IAAgD;AAC/D,WAAO,KAAK,GAA8B,QAAQ,EAAE,MAAM,GAAG,CAAC;AAAA,EAClE;AAAA,EAEA,aAAa,MAA4C;AACrD,WAAO,KAAK,GAAwB,gBAAgB,EAAE,KAAK,CAAC;AAAA,EAChE;AAAA;AAAA,EAGA,SAAS,MAAuC;AAC5C,WAAO,KAAK,GAAmB,YAAY,EAAE,KAAK,CAAC;AAAA,EACvD;AAAA;AAAA,EAGA,gBAAgB,MAAc,WAAiD;AAC3E,WAAO,KAAK,GAAuB,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAAA,EAC7E;AAAA;AAAA,EAGA,cAAc,MAAc,aAA8C;AACtE,WAAO,KAAK,GAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA,EAIA,OACI,MACA,MACA,cAAsB,sBACY;AAClC,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,QAAQ,OAAO,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC;AAC7D,SAAK,OAAO,UAAU,KAAK,MAAM;AACjC,SAAK,OAAO,QAAQ,IAAI;AACxB,SAAK,OAAO,eAAe,WAAW;AACtC,WAAO,KAAK,UAAU,UAAqC,cAAc,IAAI;AAAA,EACjF;AACJ;AAGO,IAAM,qBAAN,cAAiC,aAAa;AAAA,EACjD,YAAY,WAAsB;AAC9B,UAAM,WAAW,QAAQ;AAAA,EAC7B;AAAA;AAAA,EAGA,OAAO,MAAwC;AAC3C,WAAO,KAAK,GAAoB,UAAU,EAAE,KAAK,CAAC;AAAA,EACtD;AACJ;AAOO,SAAS,cAAc,WAAqC;AAC/D,SAAO;AAAA,IACH,QAAQ,IAAI,mBAAmB,SAAS;AAAA,IACxC,SAAS,IAAI,aAAa,WAAW,SAAS;AAAA,EAClD;AACJ;;;AC5GA,IAAM,mBAAmB;AAmBzB,SAAS,QAAQ,MAAkC;AAC/C,MAAI,OAAO,YAAY,eAAe,CAAC,QAAQ,IAAK,QAAO;AAC3D,SAAO,QAAQ,IAAI,IAAI;AAC3B;AAaO,SAAS,SAAS,UAAiC,CAAC,GAAmB;AAC1E,QAAM,SAAS,QAAQ,UAAU,QAAQ,kBAAkB;AAC3D,QAAM,WAAW,QAAQ,WAAW,QAAQ,kBAAkB,KAAK,kBAAkB;AAAA,IACjF;AAAA,IACA;AAAA,EACJ;AAEA,QAAM,YAAY,IAAI,UAAU,EAAE,QAAQ,QAAQ,CAAC;AAEnD,SAAO;AAAA,IACH,MAAM,IAAI,QAAQ,SAAS;AAAA,IAC3B,IAAI,SAAS,SAAS;AAAA,IACtB,SAAS,cAAc,SAAS;AAAA,EACpC;AACJ;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dontcode2/backend",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Public SDK for DontCode Backend. A thin, typed proxy over the v1 HTTP gateway.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dontcode",
|
|
7
|
+
"backend",
|
|
8
|
+
"sdk",
|
|
9
|
+
"byoc",
|
|
10
|
+
"auth",
|
|
11
|
+
"database",
|
|
12
|
+
"storage"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/dontcode/backend#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/dontcode/backend/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/dontcode/backend.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"author": "dontcode",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.cjs",
|
|
26
|
+
"module": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.cjs",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": false,
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"test": "npm run build && node --test tests/*.test.mjs",
|
|
43
|
+
"prepublishOnly": "npm run build"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist"
|
|
47
|
+
],
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@trivago/prettier-plugin-sort-imports": "6.0.0",
|
|
50
|
+
"@types/node": "24.10.1",
|
|
51
|
+
"prettier": "3.6.2",
|
|
52
|
+
"prettier-plugin-tailwindcss": "0.7.1",
|
|
53
|
+
"tsup": "8.5.1",
|
|
54
|
+
"typescript": "5.9.3"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
}
|
|
59
|
+
}
|