@neondatabase/neon-js 0.1.0-beta.9 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms.txt ADDED
@@ -0,0 +1,416 @@
1
+ # @neondatabase/neon-js
2
+
3
+ > The official TypeScript SDK for Neon - unified client combining authentication and PostgreSQL database querying with automatic token management.
4
+
5
+ `@neondatabase/neon-js` brings together Neon Auth and Neon Data API in a single client. It provides a familiar interface for authentication and type-safe database queries with PostgREST.
6
+
7
+ ## When to Use This Package
8
+
9
+ | Use Case | Package |
10
+ |----------|---------|
11
+ | Auth + Database (most apps) | `@neondatabase/neon-js` |
12
+ | Auth only (no database) | `@neondatabase/auth` |
13
+ | Database only (external auth) | `@neondatabase/postgrest-js` |
14
+ | Pre-built UI components | Add `@neondatabase/auth-ui` |
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @neondatabase/neon-js
20
+ ```
21
+
22
+ ## Environment Variables
23
+
24
+ ```bash
25
+ # React/Vite
26
+ VITE_NEON_AUTH_URL=https://your-project.neon.tech/auth
27
+ VITE_NEON_DATA_API_URL=https://your-project.neon.tech/rest/v1
28
+
29
+ # Next.js
30
+ NEON_AUTH_BASE_URL=https://your-project.neon.tech
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { createClient } from '@neondatabase/neon-js';
37
+
38
+ const client = createClient<Database>({
39
+ auth: {
40
+ url: import.meta.env.VITE_NEON_AUTH_URL,
41
+ },
42
+ dataApi: {
43
+ url: import.meta.env.VITE_NEON_DATA_API_URL,
44
+ },
45
+ });
46
+
47
+ // Authenticate
48
+ await client.auth.signIn.email({
49
+ email: 'user@example.com',
50
+ password: 'secure-password',
51
+ });
52
+
53
+ // Query database (token automatically injected)
54
+ const { data: users } = await client
55
+ .from('users')
56
+ .select('*')
57
+ .eq('status', 'active');
58
+ ```
59
+
60
+ ## Authentication
61
+
62
+ ### Sign Up & Sign In
63
+
64
+ ```typescript
65
+ // Sign up
66
+ await client.auth.signUp.email({
67
+ email: 'user@example.com',
68
+ password: 'secure-password',
69
+ name: 'John Doe',
70
+ });
71
+
72
+ // Sign in with email
73
+ await client.auth.signIn.email({
74
+ email: 'user@example.com',
75
+ password: 'secure-password',
76
+ });
77
+
78
+ // Sign in with OAuth
79
+ await client.auth.signIn.social({
80
+ provider: 'google',
81
+ callbackURL: '/dashboard',
82
+ });
83
+
84
+ // Get session
85
+ const session = await client.auth.getSession();
86
+
87
+ // Sign out
88
+ await client.auth.signOut();
89
+ ```
90
+
91
+ ### Adapters
92
+
93
+ **Critical:** Adapters are factory functions - must call with `()`.
94
+
95
+ ```typescript
96
+ // SupabaseAuthAdapter - Supabase-compatible API
97
+ import { createClient, SupabaseAuthAdapter } from '@neondatabase/neon-js';
98
+
99
+ const client = createClient<Database>({
100
+ auth: {
101
+ adapter: SupabaseAuthAdapter(), // Must call with ()
102
+ url: import.meta.env.VITE_NEON_AUTH_URL,
103
+ },
104
+ dataApi: {
105
+ url: import.meta.env.VITE_NEON_DATA_API_URL,
106
+ },
107
+ });
108
+
109
+ await client.auth.signInWithPassword({ email, password });
110
+ const { data: session } = await client.auth.getSession();
111
+ ```
112
+
113
+ ```typescript
114
+ // BetterAuthVanillaAdapter - Direct Better Auth API
115
+ import { createClient, BetterAuthVanillaAdapter } from '@neondatabase/neon-js';
116
+
117
+ const client = createClient<Database>({
118
+ auth: {
119
+ adapter: BetterAuthVanillaAdapter(),
120
+ url: import.meta.env.VITE_NEON_AUTH_URL,
121
+ },
122
+ dataApi: {
123
+ url: import.meta.env.VITE_NEON_DATA_API_URL,
124
+ },
125
+ });
126
+
127
+ await client.auth.signIn.email({ email, password });
128
+ const session = await client.auth.getSession();
129
+ ```
130
+
131
+ ```typescript
132
+ // BetterAuthReactAdapter - React hooks (MUST use subpath import)
133
+ import { createClient } from '@neondatabase/neon-js';
134
+ import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react/adapters';
135
+
136
+ const client = createClient<Database>({
137
+ auth: {
138
+ adapter: BetterAuthReactAdapter(),
139
+ url: import.meta.env.VITE_NEON_AUTH_URL,
140
+ },
141
+ dataApi: {
142
+ url: import.meta.env.VITE_NEON_DATA_API_URL,
143
+ },
144
+ });
145
+
146
+ function MyComponent() {
147
+ const session = client.auth.useSession();
148
+ if (session.isPending) return <div>Loading...</div>;
149
+ return <div>Hello, {session.data?.user.name}</div>;
150
+ }
151
+ ```
152
+
153
+ ### Anonymous Access
154
+
155
+ Enable RLS-based data access for unauthenticated users:
156
+
157
+ ```typescript
158
+ const client = createClient<Database>({
159
+ auth: {
160
+ url: import.meta.env.VITE_NEON_AUTH_URL,
161
+ allowAnonymous: true, // Enable anonymous data access via RLS
162
+ },
163
+ dataApi: {
164
+ url: import.meta.env.VITE_NEON_DATA_API_URL,
165
+ },
166
+ });
167
+
168
+ // Works without signing in - uses anonymous token for RLS
169
+ const { data: publicItems } = await client.from('public_items').select();
170
+ ```
171
+
172
+ **Required SQL setup:**
173
+
174
+ ```sql
175
+ -- Enable RLS on table
176
+ ALTER TABLE public.public_items ENABLE ROW LEVEL SECURITY;
177
+
178
+ -- Allow anonymous read access
179
+ CREATE POLICY "anonymous_read" ON public.public_items
180
+ FOR SELECT TO anonymous USING (true);
181
+
182
+ -- Grant permissions to roles
183
+ GRANT SELECT ON public.public_items TO anonymous;
184
+ GRANT SELECT, INSERT, UPDATE, DELETE ON public.public_items TO authenticated;
185
+ ```
186
+
187
+ ## Next.js Integration
188
+
189
+ See [@neondatabase/auth/NEXT-JS.md](https://github.com/neondatabase/neon-js/blob/main/packages/auth/NEXT-JS.md) for full guide.
190
+
191
+ **Environment variables:**
192
+
193
+ ```bash
194
+ NEON_AUTH_BASE_URL=https://your-project.neon.tech
195
+ NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long
196
+ ```
197
+
198
+ **Quick setup:**
199
+
200
+ ```typescript
201
+ // lib/auth/server.ts - Unified server instance
202
+ import { createNeonAuth } from '@neondatabase/neon-js/auth/next/server';
203
+
204
+ export const auth = createNeonAuth({
205
+ baseUrl: process.env.NEON_AUTH_BASE_URL!,
206
+ cookies: {
207
+ secret: process.env.NEON_AUTH_COOKIE_SECRET!,
208
+ sessionDataTtl: 300, // Optional: session data cache TTL in seconds (default: 300 = 5 min)
209
+ domain: '.example.com', // Optional: for cross-subdomain cookies
210
+ },
211
+ });
212
+
213
+ // app/api/auth/[...path]/route.ts - API handler
214
+ import { auth } from '@/lib/auth/server';
215
+ export const { GET, POST } = auth.handler();
216
+
217
+ // middleware.ts - Route protection
218
+ import { auth } from '@/lib/auth/server';
219
+ export default auth.middleware({ loginUrl: '/auth/sign-in' });
220
+
221
+ // lib/auth/client.ts - Client-side auth
222
+ "use client"
223
+ import { createAuthClient } from '@neondatabase/neon-js/auth/next';
224
+ export const authClient = createAuthClient();
225
+
226
+ // Server Components
227
+ import { auth } from '@/lib/auth/server';
228
+ // Server components using `auth` methods must be rendered dynamically
229
+ export const dynamic = 'force-dynamic';
230
+ const { data: session } = await auth.getSession();
231
+
232
+ // Server Actions
233
+ import { auth } from '@/lib/auth/server';
234
+ await auth.signIn.email({ email, password });
235
+ ```
236
+
237
+ ## Database Querying
238
+
239
+ ### SELECT
240
+
241
+ ```typescript
242
+ // Simple select
243
+ const { data } = await client.from('users').select('id, name, email');
244
+
245
+ // With filters
246
+ const { data } = await client
247
+ .from('posts')
248
+ .select('*')
249
+ .eq('status', 'published')
250
+ .gt('views', 100)
251
+ .order('created_at', { ascending: false })
252
+ .limit(10);
253
+
254
+ // Joins
255
+ const { data } = await client
256
+ .from('posts')
257
+ .select(`
258
+ id,
259
+ title,
260
+ author:users(name, email)
261
+ `)
262
+ .eq('status', 'published');
263
+ ```
264
+
265
+ ### INSERT
266
+
267
+ ```typescript
268
+ // Single row
269
+ const { data } = await client
270
+ .from('users')
271
+ .insert({ name: 'Alice', email: 'alice@example.com' })
272
+ .select();
273
+
274
+ // Multiple rows
275
+ const { data } = await client
276
+ .from('users')
277
+ .insert([
278
+ { name: 'Bob', email: 'bob@example.com' },
279
+ { name: 'Carol', email: 'carol@example.com' },
280
+ ])
281
+ .select();
282
+ ```
283
+
284
+ ### UPDATE
285
+
286
+ ```typescript
287
+ const { data } = await client
288
+ .from('users')
289
+ .update({ status: 'inactive' })
290
+ .eq('last_login', null)
291
+ .select();
292
+ ```
293
+
294
+ ### DELETE
295
+
296
+ ```typescript
297
+ const { data } = await client
298
+ .from('users')
299
+ .delete()
300
+ .eq('status', 'deleted')
301
+ .select();
302
+ ```
303
+
304
+ ### RPC (Stored Procedures)
305
+
306
+ ```typescript
307
+ const { data } = await client.rpc('get_user_stats', {
308
+ user_id: 123,
309
+ start_date: '2024-01-01',
310
+ });
311
+ ```
312
+
313
+ ## Error Handling
314
+
315
+ ```typescript
316
+ import { AuthRequiredError } from '@neondatabase/neon-js';
317
+
318
+ try {
319
+ const { data } = await client.from('posts').select();
320
+ } catch (error) {
321
+ if (error instanceof AuthRequiredError) {
322
+ // User not authenticated - redirect to login
323
+ window.location.href = '/login';
324
+ }
325
+ // Handle PostgREST errors
326
+ if (error.code === 'PGRST301') {
327
+ // Row-level security violation - check RLS policies
328
+ }
329
+ if (error.code === '42501') {
330
+ // Permission denied - check GRANT statements
331
+ }
332
+ }
333
+ ```
334
+
335
+ ## TypeScript
336
+
337
+ Generate types from your database schema:
338
+
339
+ ```bash
340
+ npx @neondatabase/neon-js gen-types --db-url "postgresql://user:pass@host/db"
341
+ ```
342
+
343
+ Use generated types:
344
+
345
+ ```typescript
346
+ import type { Database } from './types/database';
347
+
348
+ const client = createClient<Database>({
349
+ auth: { url: process.env.NEON_AUTH_URL! },
350
+ dataApi: { url: process.env.NEON_DATA_API_URL! },
351
+ });
352
+
353
+ // Fully typed queries with autocomplete
354
+ const { data } = await client
355
+ .from('users')
356
+ .select('id, name, email')
357
+ .eq('status', 'active');
358
+ ```
359
+
360
+ ## Configuration
361
+
362
+ ```typescript
363
+ const client = createClient({
364
+ auth: {
365
+ url: 'https://your-auth-server.neon.tech/auth',
366
+ allowAnonymous: true,
367
+ },
368
+ dataApi: {
369
+ url: 'https://your-data-api.neon.tech/rest/v1',
370
+ options: {
371
+ db: { schema: 'public' },
372
+ global: { headers: { 'X-Custom-Header': 'value' } },
373
+ },
374
+ },
375
+ });
376
+ ```
377
+
378
+ ## CSS for UI Components
379
+
380
+ ```css
381
+ /* Without Tailwind - pre-built bundle (~47KB) */
382
+ @import '@neondatabase/neon-js/ui/css';
383
+
384
+ /* With Tailwind CSS v4 - theme tokens only (~2KB) */
385
+ @import 'tailwindcss';
386
+ @import '@neondatabase/neon-js/ui/tailwind';
387
+ ```
388
+
389
+ **Rule:** Never import both - causes duplicate styles.
390
+
391
+ ## Critical Rules
392
+
393
+ 1. **Adapters are factories** - Call them: `SupabaseAuthAdapter()` not `SupabaseAuthAdapter`
394
+ 2. **React adapter import path** - Must use subpath: `@neondatabase/neon-js/auth/react/adapters`
395
+ 3. **CSS choice** - Pick ONE: `/ui/css` OR `/ui/tailwind`, never both
396
+ 4. **Anonymous access requires RLS** - Must configure database policies and grants
397
+ 5. **Type generation** - Run CLI after schema changes to keep types in sync
398
+
399
+ ## Troubleshooting
400
+
401
+ | Error | Cause | Fix |
402
+ |-------|-------|-----|
403
+ | `AuthRequiredError` | No session when querying | Sign in first or enable `allowAnonymous` |
404
+ | `permission denied for table` | RLS blocking access | Add RLS policy + GRANT for role |
405
+ | `adapter is not a function` | Missing `()` on adapter | Use `SupabaseAuthAdapter()` not `SupabaseAuthAdapter` |
406
+ | OAuth popup blocked | Browser blocking popup | User must allow popups for domain |
407
+ | `PGRST301` | JWT expired or invalid | Session expired - re-authenticate |
408
+ | Cross-tab sync not working | Node.js environment | BroadcastChannel is browser-only feature |
409
+ | Session always null | Cookies blocked | Check browser settings, try non-incognito |
410
+
411
+ ## Optional
412
+
413
+ - [CLI Tool](https://github.com/neondatabase/neon-js/tree/main/packages/neon-js#cli-tool): Generate TypeScript types from database
414
+ - [PostgREST Documentation](https://postgrest.org): Query syntax reference
415
+ - [Better Auth Documentation](https://www.better-auth.com/docs): Authentication library docs
416
+ - [Next.js Integration Guide](https://github.com/neondatabase/neon-js/blob/main/packages/auth/NEXT-JS.md): Full Next.js setup
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neondatabase/neon-js",
3
- "version": "0.1.0-beta.9",
3
+ "version": "0.2.0-beta.1",
4
4
  "description": "TypeScript SDK for Neon Auth and Data API - authentication and PostgreSQL querying",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -18,13 +18,13 @@
18
18
  "supabase",
19
19
  "data-api"
20
20
  ],
21
- "homepage": "https://github.com/neondatabase-labs/neon-js/tree/main/packages/neon-js#readme",
21
+ "homepage": "https://github.com/neondatabase/neon-js/tree/main/packages/neon-js#readme",
22
22
  "bugs": {
23
- "url": "https://github.com/neondatabase-labs/neon-js/issues"
23
+ "url": "https://github.com/neondatabase/neon-js/issues"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
27
- "url": "git+https://github.com/neondatabase-labs/neon-js.git",
27
+ "url": "git+https://github.com/neondatabase/neon-js.git",
28
28
  "directory": "packages/neon-js"
29
29
  },
30
30
  "funding": {
@@ -83,6 +83,10 @@
83
83
  "types": "./dist/auth/next/index.d.mts",
84
84
  "default": "./dist/auth/next/index.mjs"
85
85
  },
86
+ "./auth/next/server": {
87
+ "types": "./dist/auth/next/server/index.d.mts",
88
+ "default": "./dist/auth/next/server/index.mjs"
89
+ },
86
90
  "./ui/css": {
87
91
  "types": "./dist/ui/css.d.ts",
88
92
  "default": "./dist/ui/css.css"
@@ -92,7 +96,8 @@
92
96
  }
93
97
  },
94
98
  "files": [
95
- "dist"
99
+ "dist",
100
+ "llms.txt"
96
101
  ],
97
102
  "publishConfig": {
98
103
  "access": "public"
@@ -102,9 +107,9 @@
102
107
  "dev": "tsdown --watch",
103
108
  "test": "vitest",
104
109
  "test:node": "node --run test",
105
- "test:ci": "vitest run",
110
+ "test:ci": "vitest run --typecheck --passWithNoTests",
106
111
  "typecheck": "tsc --noEmit",
107
- "test:types": "tsc --noEmit",
112
+ "test:types": "vitest --typecheck.only --run",
108
113
  "release": "bun run build && bumpp --tag 'neon-js-v%s' && bun publish --tag latest",
109
114
  "lint": "eslint .",
110
115
  "clean": "rm -rf node_modules dist"
@@ -113,8 +118,8 @@
113
118
  "msw": "2.6.8"
114
119
  },
115
120
  "dependencies": {
116
- "@neondatabase/postgrest-js": "0.1.0-alpha.1",
117
- "@neondatabase/auth": "0.1.0-beta.9",
121
+ "@neondatabase/auth": "0.2.0-beta.1",
122
+ "@neondatabase/postgrest-js": "0.1.0-alpha.2",
118
123
  "@supabase/postgres-meta": "0.93.1",
119
124
  "meow": "14.0.0",
120
125
  "zod": "4.1.12"