@neon/neon-js 0.0.0 → 0.10.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/LICENSE +202 -0
- package/README.md +651 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/next/index.d.ts +2 -0
- package/dist/auth/next/index.js +2 -0
- package/dist/auth/next/server/index.d.ts +2 -0
- package/dist/auth/next/server/index.js +2 -0
- package/dist/auth/react/adapters/index.d.ts +2 -0
- package/dist/auth/react/adapters/index.js +2 -0
- package/dist/auth/react/index.d.ts +2 -0
- package/dist/auth/react/index.js +2 -0
- package/dist/auth/server/index.d.ts +2 -0
- package/dist/auth/server/index.js +2 -0
- package/dist/auth/types/index.d.ts +2 -0
- package/dist/auth/types/index.js +2 -0
- package/dist/auth/vanilla/adapters/index.d.ts +2 -0
- package/dist/auth/vanilla/adapters/index.js +2 -0
- package/dist/auth/vanilla/index.d.ts +2 -0
- package/dist/auth/vanilla/index.js +2 -0
- package/dist/client-factory.d.ts +219 -0
- package/dist/client-factory.d.ts.map +1 -0
- package/dist/client-factory.js +235 -0
- package/dist/client-factory.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/supabase/index.d.ts +50 -0
- package/dist/supabase/index.d.ts.map +1 -0
- package/dist/supabase/index.js +24 -0
- package/dist/supabase/index.js.map +1 -0
- package/llms.txt +397 -0
- package/package.json +108 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/supabase/index.ts"],"sourcesContent":["import {\n\tSupabaseAuthAdapter,\n\ttype SupabaseAuthAdapterInstance,\n\ttype SupabaseAuthAdapterOptions,\n} from \"@neon/auth/vanilla/adapters\";\nimport {\n\ttype CreateClientDataApiConfig,\n\ttype CreateClientResult,\n\tcreateClientImpl,\n} from \"../client/client-factory\";\nimport type { DeriveNeonUrls } from \"../client/derive-urls\";\nimport type { DefaultSchemaName, NeonClient } from \"../client/neon-client\";\n\n/**\n * `url` and `allowAnonymous` configure the client; every other key is forwarded to\n * `SupabaseAuthAdapter(...)`, e.g. `fetchOptions.headers.Cookie` to forward a request\n * cookie from a server.\n */\ntype SupabaseAuthConfig = SupabaseAuthAdapterOptions & {\n\t/** The auth service URL */\n\turl: string;\n\t/** Fall back to an anonymous token when there is no user session. */\n\tallowAnonymous?: boolean;\n};\n\ntype SupabaseDataApiConfig<SchemaName> = CreateClientDataApiConfig<\n\tSchemaName,\n\tSupabaseAuthAdapterInstance\n>;\n\n/** Configuration for the Supabase-compatible `createClient`. */\nexport type CreateSupabaseClientConfig<SchemaName> = {\n\tauth: SupabaseAuthConfig;\n\tdataApi: SupabaseDataApiConfig<SchemaName>;\n};\n\n/** Per-call overrides accepted alongside a single base URL. */\nexport type CreateSupabaseClientStringOptions<SchemaName> = {\n\tauth?: Partial<SupabaseAuthConfig>;\n\tdataApi?: Partial<SupabaseDataApiConfig<SchemaName>>;\n\tderiveUrls?: DeriveNeonUrls;\n};\n\n/**\n * `createClient` with the auth adapter fixed to `SupabaseAuthAdapter`, so `client.auth`\n * has the Supabase-compatible API (`signInWithPassword`, `onAuthStateChange`, ...).\n *\n * @example\n * ```typescript\n * import { createClient } from '@neon/neon-js/supabase';\n *\n * const client = createClient({\n * auth: { url: 'https://auth.example.com' },\n * dataApi: { url: 'https://data-api.example.com/rest/v1' },\n * });\n *\n * await client.auth.signInWithPassword({ email, password });\n * const { data: items } = await client.from('items').select();\n * ```\n */\n// biome-ignore lint/suspicious/noExplicitAny: `any` is the default so an unspecified Database generic stays compatible with the upstream PostgrestClient's untyped schema.\nexport function createClient<Database = any>(\n\tconfig: CreateSupabaseClientConfig<DefaultSchemaName<Database>>,\n): CreateClientResult<Database, SupabaseAuthAdapterInstance>;\n// biome-ignore lint/suspicious/noExplicitAny: `any` is the default so an unspecified Database generic stays compatible with the upstream PostgrestClient's untyped schema.\nexport function createClient<Database = any>(\n\tbaseUrl: string,\n\toptions?: CreateSupabaseClientStringOptions<DefaultSchemaName<Database>>,\n): CreateClientResult<Database, SupabaseAuthAdapterInstance>;\nexport function createClient<\n\t// biome-ignore lint/suspicious/noExplicitAny: `any` is the default so an unspecified Database generic stays compatible with the upstream PostgrestClient's untyped schema.\n\tDatabase = any,\n\tSchemaName extends string & keyof Database = DefaultSchemaName<Database>,\n>(\n\targ1: string | CreateSupabaseClientConfig<SchemaName>,\n\targ2?: CreateSupabaseClientStringOptions<SchemaName>,\n): NeonClient<Database, SchemaName, SupabaseAuthAdapterInstance> {\n\t// An `auth` block is always present here, so the implementation never takes its\n\t// external-auth branch and the result always carries `.auth`.\n\tconst client =\n\t\ttypeof arg1 === \"string\"\n\t\t\t? createClientImpl<\n\t\t\t\t\tDatabase,\n\t\t\t\t\tSchemaName,\n\t\t\t\t\tSupabaseAuthAdapterInstance\n\t\t\t\t>(arg1, { ...arg2, auth: withAdapter(arg2?.auth) })\n\t\t\t: createClientImpl<\n\t\t\t\t\tDatabase,\n\t\t\t\t\tSchemaName,\n\t\t\t\t\tSupabaseAuthAdapterInstance\n\t\t\t\t>({\n\t\t\t\t\t...arg1,\n\t\t\t\t\tauth: withAdapter(arg1.auth),\n\t\t\t\t});\n\treturn client as NeonClient<\n\t\tDatabase,\n\t\tSchemaName,\n\t\tSupabaseAuthAdapterInstance\n\t>;\n}\n\nfunction withAdapter<T extends Partial<SupabaseAuthConfig>>(\n\tauth: T | undefined,\n) {\n\tconst { url, allowAnonymous, ...adapterOptions } = auth ?? {};\n\treturn {\n\t\turl,\n\t\tallowAnonymous,\n\t\tadapter: SupabaseAuthAdapter(adapterOptions),\n\t} as Omit<T, keyof SupabaseAuthAdapterOptions> & {\n\t\tadapter: ReturnType<typeof SupabaseAuthAdapter>;\n\t};\n}\n"],"mappings":";;;AAqEA,SAAgB,aAKf,MACA,MACgE;CAkBhE,OAdC,OAAO,SAAS,WACb,iBAIC,MAAM;EAAE,GAAG;EAAM,MAAM,YAAY,MAAM,IAAI;CAAE,CAAC,IACjD,iBAIC;EACD,GAAG;EACH,MAAM,YAAY,KAAK,IAAI;CAC5B,CAAC;AAML;AAEA,SAAS,YACR,MACC;CACD,MAAM,EAAE,KAAK,gBAAgB,GAAG,mBAAmB,QAAQ,CAAC;CAC5D,OAAO;EACN;EACA;EACA,SAAS,oBAAoB,cAAc;CAC5C;AAGD"}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# @neon/neon-js
|
|
2
|
+
|
|
3
|
+
> The official TypeScript SDK for Neon - unified client combining authentication and PostgreSQL database querying with automatic token management.
|
|
4
|
+
|
|
5
|
+
`@neon/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) | `@neon/neon-js` |
|
|
12
|
+
| Auth only (no database) | `@neon/auth` |
|
|
13
|
+
| Database only (external auth) | `@neon/postgrest-js` |
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @neon/neon-js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Environment Variables
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# React/Vite
|
|
25
|
+
VITE_NEON_AUTH_URL=https://your-project.neon.tech/auth
|
|
26
|
+
VITE_NEON_DATA_API_URL=https://your-project.neon.tech/rest/v1
|
|
27
|
+
|
|
28
|
+
# Next.js
|
|
29
|
+
NEON_AUTH_BASE_URL=https://your-project.neon.tech
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { createClient } from '@neon/neon-js';
|
|
36
|
+
|
|
37
|
+
const client = createClient<Database>({
|
|
38
|
+
auth: {
|
|
39
|
+
url: import.meta.env.VITE_NEON_AUTH_URL,
|
|
40
|
+
},
|
|
41
|
+
dataApi: {
|
|
42
|
+
url: import.meta.env.VITE_NEON_DATA_API_URL,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Authenticate
|
|
47
|
+
await client.auth.signIn.email({
|
|
48
|
+
email: 'user@example.com',
|
|
49
|
+
password: 'secure-password',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Query database (token automatically injected)
|
|
53
|
+
const { data: users } = await client
|
|
54
|
+
.from('users')
|
|
55
|
+
.select('*')
|
|
56
|
+
.eq('status', 'active');
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Authentication
|
|
60
|
+
|
|
61
|
+
### Sign Up & Sign In
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// Sign up
|
|
65
|
+
await client.auth.signUp.email({
|
|
66
|
+
email: 'user@example.com',
|
|
67
|
+
password: 'secure-password',
|
|
68
|
+
name: 'John Doe',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Sign in with email
|
|
72
|
+
await client.auth.signIn.email({
|
|
73
|
+
email: 'user@example.com',
|
|
74
|
+
password: 'secure-password',
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Sign in with OAuth
|
|
78
|
+
await client.auth.signIn.social({
|
|
79
|
+
provider: 'google',
|
|
80
|
+
callbackURL: '/dashboard',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Get session
|
|
84
|
+
const session = await client.auth.getSession();
|
|
85
|
+
|
|
86
|
+
// Sign out
|
|
87
|
+
await client.auth.signOut();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Adapters
|
|
91
|
+
|
|
92
|
+
**Critical:** Adapters are factory functions - must call with `()`.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Supabase-compatible API: import createClient from the /supabase subpath (no adapter option)
|
|
96
|
+
import { createClient } from '@neon/neon-js/supabase';
|
|
97
|
+
|
|
98
|
+
const client = createClient<Database>({
|
|
99
|
+
auth: {
|
|
100
|
+
url: import.meta.env.VITE_NEON_AUTH_URL,
|
|
101
|
+
},
|
|
102
|
+
dataApi: {
|
|
103
|
+
url: import.meta.env.VITE_NEON_DATA_API_URL,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await client.auth.signInWithPassword({ email, password });
|
|
108
|
+
const { data: session } = await client.auth.getSession();
|
|
109
|
+
|
|
110
|
+
// Supabase adapter options (fetchOptions, sessionOptions, ...) go on the auth config, e.g. to forward a request cookie on a server:
|
|
111
|
+
// auth: { url, fetchOptions: { headers: { Cookie: request.headers.get('cookie') ?? '' } } }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// BetterAuthVanillaAdapter - Direct Better Auth API
|
|
116
|
+
import { createClient, BetterAuthVanillaAdapter } from '@neon/neon-js';
|
|
117
|
+
|
|
118
|
+
const client = createClient<Database>({
|
|
119
|
+
auth: {
|
|
120
|
+
adapter: BetterAuthVanillaAdapter(),
|
|
121
|
+
url: import.meta.env.VITE_NEON_AUTH_URL,
|
|
122
|
+
},
|
|
123
|
+
dataApi: {
|
|
124
|
+
url: import.meta.env.VITE_NEON_DATA_API_URL,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await client.auth.signIn.email({ email, password });
|
|
129
|
+
const session = await client.auth.getSession();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// BetterAuthReactAdapter - React hooks (MUST use subpath import)
|
|
134
|
+
import { createClient } from '@neon/neon-js';
|
|
135
|
+
import { BetterAuthReactAdapter } from '@neon/neon-js/auth/react/adapters';
|
|
136
|
+
|
|
137
|
+
const client = createClient<Database>({
|
|
138
|
+
auth: {
|
|
139
|
+
adapter: BetterAuthReactAdapter(),
|
|
140
|
+
url: import.meta.env.VITE_NEON_AUTH_URL,
|
|
141
|
+
},
|
|
142
|
+
dataApi: {
|
|
143
|
+
url: import.meta.env.VITE_NEON_DATA_API_URL,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
function MyComponent() {
|
|
148
|
+
const session = client.auth.useSession();
|
|
149
|
+
if (session.isPending) return <div>Loading...</div>;
|
|
150
|
+
return <div>Hello, {session.data?.user.name}</div>;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Anonymous Access
|
|
155
|
+
|
|
156
|
+
Enable RLS-based data access for unauthenticated users:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const client = createClient<Database>({
|
|
160
|
+
auth: {
|
|
161
|
+
url: import.meta.env.VITE_NEON_AUTH_URL,
|
|
162
|
+
allowAnonymous: true, // Enable anonymous data access via RLS
|
|
163
|
+
},
|
|
164
|
+
dataApi: {
|
|
165
|
+
url: import.meta.env.VITE_NEON_DATA_API_URL,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Works without signing in - uses anonymous token for RLS
|
|
170
|
+
const { data: publicItems } = await client.from('public_items').select();
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Required SQL setup:**
|
|
174
|
+
|
|
175
|
+
```sql
|
|
176
|
+
-- Enable RLS on table
|
|
177
|
+
ALTER TABLE public.public_items ENABLE ROW LEVEL SECURITY;
|
|
178
|
+
|
|
179
|
+
-- Allow anonymous read access
|
|
180
|
+
CREATE POLICY "anonymous_read" ON public.public_items
|
|
181
|
+
FOR SELECT TO anonymous USING (true);
|
|
182
|
+
|
|
183
|
+
-- Grant permissions to roles
|
|
184
|
+
GRANT SELECT ON public.public_items TO anonymous;
|
|
185
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.public_items TO authenticated;
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Next.js Integration
|
|
189
|
+
|
|
190
|
+
See [@neon/auth/NEXT-JS.md](https://github.com/neondatabase/neon-pkgs/blob/main/packages/auth/NEXT-JS.md) for full guide.
|
|
191
|
+
|
|
192
|
+
**Environment variables:**
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
NEON_AUTH_BASE_URL=https://your-project.neon.tech
|
|
196
|
+
NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Quick setup:**
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// lib/auth/server.ts - Unified server instance
|
|
203
|
+
import { createNeonAuth } from '@neon/neon-js/auth/next/server';
|
|
204
|
+
|
|
205
|
+
export const auth = createNeonAuth({
|
|
206
|
+
baseUrl: process.env.NEON_AUTH_BASE_URL!,
|
|
207
|
+
cookies: {
|
|
208
|
+
secret: process.env.NEON_AUTH_COOKIE_SECRET!,
|
|
209
|
+
sessionDataTtl: 300, // Optional: session data cache TTL in seconds (default: 300 = 5 min)
|
|
210
|
+
domain: '.example.com', // Optional: for cross-subdomain cookies
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// app/api/auth/[...path]/route.ts - API handler
|
|
215
|
+
import { auth } from '@/lib/auth/server';
|
|
216
|
+
export const { GET, POST } = auth.handler();
|
|
217
|
+
|
|
218
|
+
// middleware.ts - Route protection
|
|
219
|
+
import { auth } from '@/lib/auth/server';
|
|
220
|
+
export default auth.middleware({ loginUrl: '/auth/sign-in' });
|
|
221
|
+
|
|
222
|
+
// lib/auth/client.ts - Client-side auth
|
|
223
|
+
"use client"
|
|
224
|
+
import { createAuthClient } from '@neon/neon-js/auth/next';
|
|
225
|
+
export const authClient = createAuthClient();
|
|
226
|
+
|
|
227
|
+
// Server Components
|
|
228
|
+
import { auth } from '@/lib/auth/server';
|
|
229
|
+
// Server components using `auth` methods must be rendered dynamically
|
|
230
|
+
export const dynamic = 'force-dynamic';
|
|
231
|
+
const { data: session } = await auth.getSession();
|
|
232
|
+
|
|
233
|
+
// Server Actions
|
|
234
|
+
import { auth } from '@/lib/auth/server';
|
|
235
|
+
await auth.signIn.email({ email, password });
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Database Querying
|
|
239
|
+
|
|
240
|
+
### SELECT
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Simple select
|
|
244
|
+
const { data } = await client.from('users').select('id, name, email');
|
|
245
|
+
|
|
246
|
+
// With filters
|
|
247
|
+
const { data } = await client
|
|
248
|
+
.from('posts')
|
|
249
|
+
.select('*')
|
|
250
|
+
.eq('status', 'published')
|
|
251
|
+
.gt('views', 100)
|
|
252
|
+
.order('created_at', { ascending: false })
|
|
253
|
+
.limit(10);
|
|
254
|
+
|
|
255
|
+
// Joins
|
|
256
|
+
const { data } = await client
|
|
257
|
+
.from('posts')
|
|
258
|
+
.select(`
|
|
259
|
+
id,
|
|
260
|
+
title,
|
|
261
|
+
author:users(name, email)
|
|
262
|
+
`)
|
|
263
|
+
.eq('status', 'published');
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### INSERT
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Single row
|
|
270
|
+
const { data } = await client
|
|
271
|
+
.from('users')
|
|
272
|
+
.insert({ name: 'Alice', email: 'alice@example.com' })
|
|
273
|
+
.select();
|
|
274
|
+
|
|
275
|
+
// Multiple rows
|
|
276
|
+
const { data } = await client
|
|
277
|
+
.from('users')
|
|
278
|
+
.insert([
|
|
279
|
+
{ name: 'Bob', email: 'bob@example.com' },
|
|
280
|
+
{ name: 'Carol', email: 'carol@example.com' },
|
|
281
|
+
])
|
|
282
|
+
.select();
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### UPDATE
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
const { data } = await client
|
|
289
|
+
.from('users')
|
|
290
|
+
.update({ status: 'inactive' })
|
|
291
|
+
.eq('last_login', null)
|
|
292
|
+
.select();
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### DELETE
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
const { data } = await client
|
|
299
|
+
.from('users')
|
|
300
|
+
.delete()
|
|
301
|
+
.eq('status', 'deleted')
|
|
302
|
+
.select();
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### RPC (Stored Procedures)
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
const { data } = await client.rpc('get_user_stats', {
|
|
309
|
+
user_id: 123,
|
|
310
|
+
start_date: '2024-01-01',
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Error Handling
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { AuthRequiredError } from '@neon/neon-js';
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const { data } = await client.from('posts').select();
|
|
321
|
+
} catch (error) {
|
|
322
|
+
if (error instanceof AuthRequiredError) {
|
|
323
|
+
// User not authenticated - redirect to login
|
|
324
|
+
window.location.href = '/login';
|
|
325
|
+
}
|
|
326
|
+
// Handle PostgREST errors
|
|
327
|
+
if (error.code === 'PGRST301') {
|
|
328
|
+
// Row-level security violation - check RLS policies
|
|
329
|
+
}
|
|
330
|
+
if (error.code === '42501') {
|
|
331
|
+
// Permission denied - check GRANT statements
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## TypeScript
|
|
337
|
+
|
|
338
|
+
Pass a `Database` type generated from your schema to `createClient`:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
import type { Database } from './types/database';
|
|
342
|
+
|
|
343
|
+
const client = createClient<Database>({
|
|
344
|
+
auth: { url: process.env.NEON_AUTH_URL! },
|
|
345
|
+
dataApi: { url: process.env.NEON_DATA_API_URL! },
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Fully typed queries with autocomplete
|
|
349
|
+
const { data } = await client
|
|
350
|
+
.from('users')
|
|
351
|
+
.select('id, name, email')
|
|
352
|
+
.eq('status', 'active');
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Configuration
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
const client = createClient({
|
|
359
|
+
auth: {
|
|
360
|
+
url: 'https://your-auth-server.neon.tech/auth',
|
|
361
|
+
allowAnonymous: true,
|
|
362
|
+
},
|
|
363
|
+
dataApi: {
|
|
364
|
+
url: 'https://your-data-api.neon.tech/rest/v1',
|
|
365
|
+
options: {
|
|
366
|
+
db: { schema: 'public' },
|
|
367
|
+
global: { headers: { 'X-Custom-Header': 'value' } },
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Critical Rules
|
|
374
|
+
|
|
375
|
+
1. **Adapters are factories** - Call them: `BetterAuthVanillaAdapter()` not `BetterAuthVanillaAdapter`
|
|
376
|
+
2. **Supabase API lives at `/supabase`** - `import { createClient } from '@neon/neon-js/supabase'`; the main `createClient` does not accept `SupabaseAuthAdapter`
|
|
377
|
+
3. **React adapter import path** - Must use subpath: `@neon/neon-js/auth/react/adapters`
|
|
378
|
+
4. **Anonymous access requires RLS** - Must configure database policies and grants
|
|
379
|
+
5. **Type generation** - Regenerate your `Database` type after schema changes to keep types in sync
|
|
380
|
+
|
|
381
|
+
## Troubleshooting
|
|
382
|
+
|
|
383
|
+
| Error | Cause | Fix |
|
|
384
|
+
|-------|-------|-----|
|
|
385
|
+
| `AuthRequiredError` | No session when querying | Sign in first or enable `allowAnonymous` |
|
|
386
|
+
| `permission denied for table` | RLS blocking access | Add RLS policy + GRANT for role |
|
|
387
|
+
| `adapter is not a function` | Missing `()` on adapter | Use `BetterAuthVanillaAdapter()` not `BetterAuthVanillaAdapter` |
|
|
388
|
+
| OAuth popup blocked | Browser blocking popup | User must allow popups for domain |
|
|
389
|
+
| `PGRST301` | JWT expired or invalid | Session expired - re-authenticate |
|
|
390
|
+
| Cross-tab sync not working | Node.js environment | BroadcastChannel is browser-only feature |
|
|
391
|
+
| Session always null | Cookies blocked | Check browser settings, try non-incognito |
|
|
392
|
+
|
|
393
|
+
## Optional
|
|
394
|
+
|
|
395
|
+
- [PostgREST Documentation](https://postgrest.org): Query syntax reference
|
|
396
|
+
- [Better Auth Documentation](https://www.better-auth.com/docs): Authentication library docs
|
|
397
|
+
- [Next.js Integration Guide](https://github.com/neondatabase/neon-pkgs/blob/main/packages/auth/NEXT-JS.md): Full Next.js setup
|
package/package.json
CHANGED
|
@@ -1,10 +1,114 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neon/neon-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "TypeScript SDK for Neon Auth and Data API - authentication and PostgreSQL querying",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"neon",
|
|
7
|
+
"neondb",
|
|
8
|
+
"postgresql",
|
|
9
|
+
"postgres",
|
|
10
|
+
"database",
|
|
11
|
+
"authentication",
|
|
12
|
+
"auth",
|
|
13
|
+
"typescript",
|
|
14
|
+
"sdk",
|
|
15
|
+
"better-auth",
|
|
16
|
+
"supabase",
|
|
17
|
+
"data-api"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/neondatabase/neon-pkgs.git",
|
|
22
|
+
"directory": "packages/neon-js"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/neondatabase/neon-pkgs/tree/main/packages/neon-js#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/neondatabase/neon-pkgs/issues"
|
|
27
|
+
},
|
|
28
|
+
"license": "Apache-2.0",
|
|
29
|
+
"author": {
|
|
30
|
+
"name": "Neon",
|
|
31
|
+
"url": "https://neon.com"
|
|
32
|
+
},
|
|
33
|
+
"type": "module",
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"main": "dist/index.js",
|
|
36
|
+
"types": "dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./supabase": {
|
|
43
|
+
"types": "./dist/supabase/index.d.ts",
|
|
44
|
+
"default": "./dist/supabase/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./auth": {
|
|
47
|
+
"types": "./dist/auth/index.d.ts",
|
|
48
|
+
"default": "./dist/auth/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./auth/types": {
|
|
51
|
+
"types": "./dist/auth/types/index.d.ts",
|
|
52
|
+
"default": "./dist/auth/types/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./auth/react": {
|
|
55
|
+
"types": "./dist/auth/react/index.d.ts",
|
|
56
|
+
"default": "./dist/auth/react/index.js"
|
|
57
|
+
},
|
|
58
|
+
"./auth/react/adapters": {
|
|
59
|
+
"types": "./dist/auth/react/adapters/index.d.ts",
|
|
60
|
+
"default": "./dist/auth/react/adapters/index.js"
|
|
61
|
+
},
|
|
62
|
+
"./auth/vanilla": {
|
|
63
|
+
"types": "./dist/auth/vanilla/index.d.ts",
|
|
64
|
+
"default": "./dist/auth/vanilla/index.js"
|
|
65
|
+
},
|
|
66
|
+
"./auth/vanilla/adapters": {
|
|
67
|
+
"types": "./dist/auth/vanilla/adapters/index.d.ts",
|
|
68
|
+
"default": "./dist/auth/vanilla/adapters/index.js"
|
|
69
|
+
},
|
|
70
|
+
"./auth/next": {
|
|
71
|
+
"types": "./dist/auth/next/index.d.ts",
|
|
72
|
+
"default": "./dist/auth/next/index.js"
|
|
73
|
+
},
|
|
74
|
+
"./auth/next/server": {
|
|
75
|
+
"types": "./dist/auth/next/server/index.d.ts",
|
|
76
|
+
"default": "./dist/auth/next/server/index.js"
|
|
77
|
+
},
|
|
78
|
+
"./auth/server": {
|
|
79
|
+
"types": "./dist/auth/server/index.d.ts",
|
|
80
|
+
"default": "./dist/auth/server/index.js"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
4
83
|
"files": [
|
|
5
|
-
"README.md"
|
|
84
|
+
"README.md",
|
|
85
|
+
"dist/",
|
|
86
|
+
"package.json",
|
|
87
|
+
"llms.txt"
|
|
6
88
|
],
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/node": "^20.19.0",
|
|
91
|
+
"@vitest/coverage-v8": "^3.0.9",
|
|
92
|
+
"tsdown": "^0.14.1",
|
|
93
|
+
"typescript": "^5.9.0",
|
|
94
|
+
"vitest": "^3.0.9",
|
|
95
|
+
"@neon-internals/internal": "0.0.0"
|
|
96
|
+
},
|
|
97
|
+
"dependencies": {
|
|
98
|
+
"@neon/auth": "0.8.0",
|
|
99
|
+
"@neon/postgrest-js": "0.3.0"
|
|
100
|
+
},
|
|
101
|
+
"engines": {
|
|
102
|
+
"node": ">=20.19.0"
|
|
103
|
+
},
|
|
7
104
|
"publishConfig": {
|
|
8
|
-
"
|
|
105
|
+
"provenance": false
|
|
106
|
+
},
|
|
107
|
+
"scripts": {
|
|
108
|
+
"build": "tsc --noEmit && tsdown",
|
|
109
|
+
"test": "vitest",
|
|
110
|
+
"test:node": "node --run test",
|
|
111
|
+
"test:ci": "vitest run --typecheck --passWithNoTests",
|
|
112
|
+
"tsc": "tsc"
|
|
9
113
|
}
|
|
10
|
-
}
|
|
114
|
+
}
|