@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/README.md CHANGED
@@ -45,6 +45,100 @@ const client = dontcode({
45
45
  If no key is set in either place, requests fail naturally with the gateway's
46
46
  `401 Missing API key`.
47
47
 
48
+ ## Local development (the mock gateway)
49
+
50
+ You don't need the hosted backend to build against this SDK. Because the SDK is a
51
+ thin proxy over a fixed wire protocol, the package ships a local server that speaks
52
+ that same protocol — auth, database, and storage — so you can develop fully offline:
53
+
54
+ ```bash
55
+ npx dontcode-mock # http://localhost:4000, state persisted to ./.dontcode-mock
56
+ ```
57
+
58
+ Then point your app at it — no code changes, just config:
59
+
60
+ ```bash
61
+ DONTCODE_API_URL=http://localhost:4000
62
+ DONTCODE_API_KEY=dc_local_dev # any dc_… value is accepted by default
63
+ ```
64
+
65
+ Apply your schema the same way you would in production, then use the client normally:
66
+
67
+ ```ts
68
+ const client = dontcode() // reads the env vars above
69
+ await client.db.migrate({ sql: 'CREATE TABLE IF NOT EXISTS notes (id serial primary key, body text);' })
70
+ await client.db.notes.insert({ body: 'hello from the mock' })
71
+ ```
72
+
73
+ How faithful is it? The database runs your real DDL and the SDK's real structured
74
+ queries against in-process Postgres ([PGlite](https://pglite.dev)), including the
75
+ `409` conflict signal; auth issues real JWT-shaped tokens that `decodeAccessToken`
76
+ and `getSession` read exactly as in production; storage stores real files and serves
77
+ them over the same server. It is a **development tool** — passwords are stored in
78
+ plaintext, tokens are unsigned, and there is no rate limiting — so never expose it
79
+ to an untrusted network.
80
+
81
+ PGlite ships as an optional dependency, so `npx dontcode-mock` works out of the box.
82
+ (If your install skipped optional deps, add it: `pnpm add -D @electric-sql/pglite`.)
83
+
84
+ **Useful flags:** `--port <n>`, `--data-dir <dir>`, `--ephemeral` (in-memory, starts
85
+ empty each run — ideal for tests), `--api-key <key>` (require exactly that key).
86
+ Run `dontcode-mock --help` for the full list.
87
+
88
+ You can also drive it programmatically — handy for integration tests that need a
89
+ clean backend per run:
90
+
91
+ ```ts
92
+ import { startMockServer } from '@dontcode2/backend/mock'
93
+ import { dontcode } from '@dontcode2/backend'
94
+
95
+ const mock = await startMockServer({ dataDir: null }) // ephemeral
96
+ const client = dontcode({ baseUrl: mock.url, apiKey: 'dc_test' })
97
+ // … exercise the client …
98
+ await mock.close()
99
+ ```
100
+
101
+ ## MCP server (Claude Code and other AI tools)
102
+
103
+ This package ships an MCP server so an AI agent can work on a DontCode project
104
+ directly: sign in from the terminal, query and update the database, run
105
+ migrations, and manage files. It runs over stdio, so the tool launches it for
106
+ you.
107
+
108
+ ```jsonc
109
+ // .mcp.json (Claude Code)
110
+ {
111
+ "mcpServers": {
112
+ "dontcode": {
113
+ "command": "npx",
114
+ "args": ["-y", "-p", "@dontcode2/backend", "dontcode", "mcp"]
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ On first use the agent calls the `auth_login` tool, which opens your browser.
121
+ You confirm a short code, pick a project, and approve; the browser hands a
122
+ short-lived, project-scoped token back to the terminal (cached under
123
+ `~/.dontcode`). The token is bound to your user, and the gateway enforces your
124
+ project role on every request, so the agent can never do more than you can.
125
+
126
+ CLI equivalents:
127
+
128
+ ```bash
129
+ npx -p @dontcode2/backend dontcode login # browser sign-in
130
+ npx -p @dontcode2/backend dontcode status # project + role + capabilities
131
+ npx -p @dontcode2/backend dontcode logout # forget the cached token
132
+ ```
133
+
134
+ For non-interactive use (CI), set `DONTCODE_API_KEY` to a `dc_` project key and
135
+ skip `login`. Set `DONTCODE_API_URL` to target a non-default gateway.
136
+
137
+ Tools: `auth_login`, `auth_wait`, `auth_status`, `auth_logout`, `db_query`,
138
+ `db_insert`, `db_update`, `db_delete`, `db_migrate`, `storage_list`,
139
+ `storage_get_url`, `storage_temporary_url`, `storage_upload`, `storage_remove`,
140
+ `storage_move`. Writes and deletes are annotated so the agent confirms first.
141
+
48
142
  ## Auth
49
143
 
50
144
  The API key (`Authorization: Bearer dc_…`) identifies your **project** and is sent on
@@ -0,0 +1,43 @@
1
+ import { type StoredCredential } from './credentials';
2
+ export interface DeviceStartResponse {
3
+ device_code: string;
4
+ user_code: string;
5
+ verification_uri: string;
6
+ verification_uri_complete: string;
7
+ interval: number;
8
+ expires_in: number;
9
+ }
10
+ export interface DeviceTokenResponse {
11
+ access_token: string;
12
+ token_type: string;
13
+ expires_in: number;
14
+ project_id: string;
15
+ }
16
+ export declare function startDeviceAuth(baseUrl: string, clientName?: string): Promise<DeviceStartResponse>;
17
+ export interface PollOptions {
18
+ onPending?: () => void;
19
+ /** Stop polling after this many ms (throws code `WaitTimeout`), so a caller
20
+ * like an MCP tool can poll in bounded slices instead of blocking for the
21
+ * full 10-minute window. Defaults to the request's own expiry. */
22
+ maxWaitMs?: number;
23
+ }
24
+ /**
25
+ * Poll until the request is approved (token), denied/expired (throws), or the
26
+ * wait budget closes (throws 408). Honors the server's interval and `slow_down`.
27
+ */
28
+ export declare function pollDeviceToken(baseUrl: string, start: DeviceStartResponse, opts?: PollOptions): Promise<DeviceTokenResponse>;
29
+ /** Best-effort: open the verification URL in the user's browser. */
30
+ export declare function openBrowser(url: string): Promise<void>;
31
+ export interface LoginOptions {
32
+ baseUrl: string;
33
+ clientName?: string;
34
+ /** Open the browser automatically. Default true. */
35
+ open?: boolean;
36
+ /** Where human-facing prompts go. Default: no-op. */
37
+ log?: (message: string) => void;
38
+ }
39
+ /**
40
+ * Run the full device flow and cache the resulting credential. Returns the
41
+ * stored credential (token, project, expiry).
42
+ */
43
+ export declare function login(options: LoginOptions): Promise<StoredCredential>;
package/dist/auth.d.ts ADDED
@@ -0,0 +1,102 @@
1
+ import { Transport } from './http';
2
+ import { type DecodedSession, type GetSessionInput, type SessionOptions, type SessionResult } from './session';
3
+ import type { ForgotPasswordInput, LoginInput, LoginResult, MeResult, MfaChallengeInput, MfaDisableInput, MfaEnrollConfirmInput, MfaEnrollResult, ResetPasswordInput, SignupInput, SignupResult, SimpleResult, VerifyEmailInput } from './types';
4
+ /** Shape of `GET /api/v1/info`: validates the credential and reports what it
5
+ * can do. For device tokens, capabilities follow the signed-in user's role. */
6
+ export interface InfoResult {
7
+ project: {
8
+ id: string;
9
+ name: string | null;
10
+ };
11
+ credential: {
12
+ type: 'api_key' | 'device';
13
+ role: string | null;
14
+ user_id: string | null;
15
+ };
16
+ capabilities: Record<string, boolean>;
17
+ }
18
+ /**
19
+ * MFA is per-user and opt-in. `enroll`/`enrollConfirm`/`disable` act as the
20
+ * signed-in user, so they need the end-user access token. `challenge` does
21
+ * not; it completes a login that returned `mfa_required`, exchanging the
22
+ * short-lived challenge token for real session tokens.
23
+ */
24
+ export declare class MfaApi {
25
+ private readonly transport;
26
+ constructor(transport: Transport);
27
+ /** Complete an MFA login. Pass the `challenge_token` from `login`, plus
28
+ * either the authenticator `code` or a `recoveryCode`. */
29
+ challenge(input: MfaChallengeInput): Promise<LoginResult>;
30
+ /** Begin enrollment. Render the returned `otpauth_url` as a QR code.
31
+ * Enrollment stays pending until `enrollConfirm`. */
32
+ enroll(input: {
33
+ accessToken: string;
34
+ }): Promise<MfaEnrollResult>;
35
+ /** Confirm enrollment with the first authenticator code. The returned
36
+ * `recovery_codes` are shown once and never again. */
37
+ enrollConfirm(input: MfaEnrollConfirmInput): Promise<SimpleResult>;
38
+ /** Turn MFA off. Proves possession of the second factor via `code` or
39
+ * `recoveryCode`. */
40
+ disable(input: MfaDisableInput): Promise<SimpleResult>;
41
+ }
42
+ /**
43
+ * Fronts DontCode Auth with the same shapes as the gateway. Two behaviours are
44
+ * project settings (not API flags) and your code must handle both states:
45
+ * email verification (signup may not return tokens) and MFA (login may be two
46
+ * steps). Branch on the resolved value; never assume one round-trip.
47
+ */
48
+ export declare class AuthApi {
49
+ private readonly transport;
50
+ readonly mfa: MfaApi;
51
+ private readonly sessions;
52
+ constructor(transport: Transport, sessionOptions?: SessionOptions);
53
+ /** Create an account. If the project requires email verification the
54
+ * response has `verification_required: true` and NO tokens; collect a
55
+ * code and call `verifyEmail`, then `login`. */
56
+ signup(input: SignupInput): Promise<SignupResult>;
57
+ /** Authenticate. Branch on `mfa_required`: when true you hold only a
58
+ * challenge (finish via `mfa.challenge`); otherwise `tokens` is your
59
+ * session. A 403 `EmailNotVerified` means the email step isn't done. */
60
+ login(input: LoginInput): Promise<LoginResult>;
61
+ /** Validate the current credential (API key or device token) and report the
62
+ * project, the caller's role, and which capabilities that role grants.
63
+ * Backs the MCP "is my session still good" check. */
64
+ info(): Promise<InfoResult>;
65
+ /** Resolve the signed-in user from their access token, or `{ user: null }`.
66
+ * This is a network round-trip; for a per-navigation guard prefer
67
+ * `getSession`, which can answer offline and caches verified results. */
68
+ me(input: {
69
+ accessToken: string;
70
+ timeoutMs?: number;
71
+ }): Promise<MeResult>;
72
+ /**
73
+ * Resolve an access token into a session for a route guard, the one call
74
+ * that replaces "hit `me` on every navigation". Two modes:
75
+ *
76
+ * - `'optimistic'` (default): decode the token locally and trust its
77
+ * claims. Zero network, zero stall. The right default for gating page
78
+ * loads. It does NOT verify the signature and will not notice a
79
+ * server-side revocation until the token's own `exp`.
80
+ * - `'verified'`: confirm against the gateway's `me`, cached for a short
81
+ * TTL with a hard timeout. Use it before sensitive actions. On a
82
+ * timeout/outage it returns `status: 'unavailable'` with the optimistic
83
+ * user, so you choose whether to fail open rather than the SDK guessing.
84
+ *
85
+ * See the BYOC docs ("Sessions") for the full reasoning and best practices.
86
+ */
87
+ getSession(input: GetSessionInput): Promise<SessionResult>;
88
+ /** Read the access token from a `Cookie` request header and resolve it, in
89
+ * one call. `name` defaults to `dc_access_token`. Returns the anonymous
90
+ * session when no cookie is present. */
91
+ sessionFromCookies(cookieHeader: string | null | undefined, options?: {
92
+ mode?: GetSessionInput['mode'];
93
+ cookieName?: string;
94
+ }): Promise<SessionResult>;
95
+ /** Decode an access token's claims locally without a network call or any
96
+ * signature check. Convenience re-export of `decodeAccessToken`. */
97
+ decodeToken(token: string): DecodedSession | null;
98
+ /** Confirm the 6-digit code emailed at signup. */
99
+ verifyEmail(input: VerifyEmailInput): Promise<SimpleResult>;
100
+ forgotPassword(input: ForgotPasswordInput): Promise<SimpleResult>;
101
+ resetPassword(input: ResetPasswordInput): Promise<SimpleResult>;
102
+ }