@edge-base/ssr 0.1.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/README.md +175 -0
- package/dist/cookie-token-manager.d.ts +20 -0
- package/dist/cookie-token-manager.d.ts.map +1 -0
- package/dist/cookie-token-manager.js +94 -0
- package/dist/cookie-token-manager.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/server-client.d.ts +78 -0
- package/dist/server-client.d.ts.map +1 -0
- package/dist/server-client.js +123 -0
- package/dist/server-client.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/llms.txt +96 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
<h1 align="center">@edge-base/ssr</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<b>Server-side auth and data helpers for EdgeBase</b><br>
|
|
5
|
+
Cookie-based session handling for SSR frameworks like Next.js, Remix, Nuxt, and SvelteKit
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/@edge-base/ssr"><img src="https://img.shields.io/npm/v/%40edge-base%2Fssr?color=brightgreen" alt="npm"></a>
|
|
10
|
+
<a href="https://edgebase.fun/docs/sdks/nextjs"><img src="https://img.shields.io/badge/docs-ssr-blue" alt="Docs"></a>
|
|
11
|
+
<a href="https://github.com/edge-base/edgebase/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
Next.js · Remix · Nuxt · SvelteKit · Hono SSR
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="https://edgebase.fun/docs/sdks/nextjs"><b>Next.js Guide</b></a> ·
|
|
20
|
+
<a href="https://edgebase.fun/docs/sdks/client-vs-server"><b>Client vs Server</b></a> ·
|
|
21
|
+
<a href="https://edgebase.fun/docs/authentication"><b>Authentication</b></a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
`@edge-base/ssr` is the package you use when server-side code should run as the current signed-in user via cookies.
|
|
27
|
+
|
|
28
|
+
It is built for:
|
|
29
|
+
|
|
30
|
+
- Server Components
|
|
31
|
+
- Route Handlers
|
|
32
|
+
- loaders and actions
|
|
33
|
+
- SSR middleware and request handlers
|
|
34
|
+
- cookie-based session transfer between server and browser code
|
|
35
|
+
|
|
36
|
+
If you are writing browser code, use [`@edge-base/web`](https://www.npmjs.com/package/@edge-base/web). If you need privileged admin access from the server, use [`@edge-base/admin`](https://www.npmjs.com/package/@edge-base/admin).
|
|
37
|
+
|
|
38
|
+
> Beta: the package is already usable, but some APIs may still evolve before general availability.
|
|
39
|
+
|
|
40
|
+
## Documentation Map
|
|
41
|
+
|
|
42
|
+
- [Next.js Integration](https://edgebase.fun/docs/sdks/nextjs)
|
|
43
|
+
End-to-end SSR and client setup
|
|
44
|
+
- [Client vs Server SDKs](https://edgebase.fun/docs/sdks/client-vs-server)
|
|
45
|
+
Pick the right package for each runtime
|
|
46
|
+
- [Authentication](https://edgebase.fun/docs/authentication)
|
|
47
|
+
Session, OAuth, MFA, and cookie-backed auth concepts
|
|
48
|
+
- [Database Client SDK](https://edgebase.fun/docs/database/client-sdk)
|
|
49
|
+
Query patterns that also apply to SSR DB access
|
|
50
|
+
|
|
51
|
+
## For AI Coding Assistants
|
|
52
|
+
|
|
53
|
+
This package ships with an `llms.txt` file for AI-assisted SSR integration.
|
|
54
|
+
|
|
55
|
+
You can find it:
|
|
56
|
+
|
|
57
|
+
- after install: `node_modules/@edge-base/ssr/llms.txt`
|
|
58
|
+
- in the repository: [llms.txt](https://github.com/edge-base/edgebase/blob/main/packages/sdk/js/packages/ssr/llms.txt)
|
|
59
|
+
|
|
60
|
+
Use it when you want an agent to:
|
|
61
|
+
|
|
62
|
+
- set up a cookie adapter correctly
|
|
63
|
+
- keep browser auth code out of server components
|
|
64
|
+
- avoid mixing `ssr`, `web`, and `admin`
|
|
65
|
+
- use `getUser()`, `getSession()`, `setSession()`, and `clearSession()` correctly
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install @edge-base/ssr
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Most SSR apps also use the browser SDK alongside it:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install @edge-base/web @edge-base/ssr
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick Start
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { createServerClient } from '@edge-base/ssr';
|
|
83
|
+
import { cookies } from 'next/headers';
|
|
84
|
+
|
|
85
|
+
export async function createEdgeBaseServer() {
|
|
86
|
+
const cookieStore = await cookies();
|
|
87
|
+
|
|
88
|
+
return createServerClient(process.env.EDGEBASE_URL!, {
|
|
89
|
+
cookies: {
|
|
90
|
+
get: (name) => cookieStore.get(name)?.value,
|
|
91
|
+
set: (name, value, options) => {
|
|
92
|
+
try {
|
|
93
|
+
cookieStore.set(name, value, options);
|
|
94
|
+
} catch {
|
|
95
|
+
// read-only contexts such as some Server Components
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
delete: (name) => {
|
|
99
|
+
try {
|
|
100
|
+
cookieStore.delete(name);
|
|
101
|
+
} catch {
|
|
102
|
+
// read-only contexts such as some Server Components
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Then use it inside a server-side request flow:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const client = await createEdgeBaseServer();
|
|
114
|
+
const user = client.getUser();
|
|
115
|
+
|
|
116
|
+
if (user) {
|
|
117
|
+
const posts = await client.db('app').table('posts').getList();
|
|
118
|
+
console.log(posts.items);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## What This Package Includes
|
|
123
|
+
|
|
124
|
+
| Surface | Included |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| Cookie-backed session tokens | Yes |
|
|
127
|
+
| Request-bound user context | Yes |
|
|
128
|
+
| `db(namespace, id?)` | Yes |
|
|
129
|
+
| `storage` and `functions` | Yes |
|
|
130
|
+
| Client-side sign-in UI | No |
|
|
131
|
+
| Database live subscriptions | No |
|
|
132
|
+
| Rooms / push / browser auth flows | No |
|
|
133
|
+
| Service Key admin user management | No |
|
|
134
|
+
|
|
135
|
+
## Cookie Store Contract
|
|
136
|
+
|
|
137
|
+
`createServerClient()` expects a cookie adapter with:
|
|
138
|
+
|
|
139
|
+
- `get(name)`
|
|
140
|
+
- `set(name, value, options?)`
|
|
141
|
+
- `delete(name)`
|
|
142
|
+
|
|
143
|
+
That makes it easy to adapt to framework-specific cookie stores while keeping one EdgeBase interface.
|
|
144
|
+
|
|
145
|
+
## OAuth And Session Transfer
|
|
146
|
+
|
|
147
|
+
On the server, `@edge-base/ssr` is especially useful for:
|
|
148
|
+
|
|
149
|
+
- reading the current session from cookies
|
|
150
|
+
- writing tokens after a server-side OAuth callback
|
|
151
|
+
- clearing session cookies during server-side sign out
|
|
152
|
+
|
|
153
|
+
Example:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
client.setSession({
|
|
157
|
+
accessToken,
|
|
158
|
+
refreshToken,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const session = client.getSession();
|
|
162
|
+
console.log(session.accessToken);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Choose The Right Package
|
|
166
|
+
|
|
167
|
+
| Package | Use it for |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| `@edge-base/web` | Browser components and client-side auth flows |
|
|
170
|
+
| `@edge-base/ssr` | Server-side code acting as the current signed-in user via cookies |
|
|
171
|
+
| `@edge-base/admin` | Trusted server-side code with Service Key access |
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CookieTokenManager — ITokenManager implementation for SSR environments.
|
|
3
|
+
*
|
|
4
|
+
* Stores access/refresh tokens in httpOnly cookies instead of localStorage.
|
|
5
|
+
* Works with any framework that provides a CookieStore interface
|
|
6
|
+
* (Next.js cookies(), Nuxt useCookie, etc.).
|
|
7
|
+
*/
|
|
8
|
+
import type { ITokenManager, ITokenPair } from '@edge-base/core';
|
|
9
|
+
import type { CookieStore, CookieOptions } from './types.js';
|
|
10
|
+
export declare class CookieTokenManager implements ITokenManager {
|
|
11
|
+
private cookies;
|
|
12
|
+
private cookieOptions;
|
|
13
|
+
constructor(cookies: CookieStore, cookieOptions?: Partial<CookieOptions>);
|
|
14
|
+
getAccessToken(refreshFn?: (refreshToken: string) => Promise<ITokenPair>): Promise<string | null> | string | null;
|
|
15
|
+
getRefreshToken(): string | null;
|
|
16
|
+
invalidateAccessToken(): void;
|
|
17
|
+
setTokens(tokens: ITokenPair): void;
|
|
18
|
+
clearTokens(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cookie-token-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie-token-manager.d.ts","sourceRoot":"","sources":["../src/cookie-token-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwC7D,qBAAa,kBAAmB,YAAW,aAAa;IAIpD,OAAO,CAAC,OAAO;IAHjB,OAAO,CAAC,aAAa,CAAgB;gBAG3B,OAAO,EAAE,WAAW,EAC5B,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAKxC,cAAc,CACZ,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,GACxD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI;IAsBzC,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,qBAAqB,IAAI,IAAI;IAI7B,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAcnC,WAAW,IAAI,IAAI;CAIpB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CookieTokenManager — ITokenManager implementation for SSR environments.
|
|
3
|
+
*
|
|
4
|
+
* Stores access/refresh tokens in httpOnly cookies instead of localStorage.
|
|
5
|
+
* Works with any framework that provides a CookieStore interface
|
|
6
|
+
* (Next.js cookies(), Nuxt useCookie, etc.).
|
|
7
|
+
*/
|
|
8
|
+
const ACCESS_TOKEN_COOKIE = 'eb_access_token';
|
|
9
|
+
const REFRESH_TOKEN_COOKIE = 'eb_refresh_token';
|
|
10
|
+
/** Default cookie options — secure, httpOnly, SameSite=Lax */
|
|
11
|
+
const DEFAULT_COOKIE_OPTIONS = {
|
|
12
|
+
httpOnly: true,
|
|
13
|
+
secure: true,
|
|
14
|
+
sameSite: 'lax',
|
|
15
|
+
path: '/',
|
|
16
|
+
};
|
|
17
|
+
function decodeJwtPayload(token) {
|
|
18
|
+
try {
|
|
19
|
+
const parts = token.split('.');
|
|
20
|
+
if (parts.length !== 3)
|
|
21
|
+
return null;
|
|
22
|
+
const payload = parts[1];
|
|
23
|
+
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
|
|
24
|
+
const padded = base64 + '=='.slice(0, (4 - (base64.length % 4)) % 4);
|
|
25
|
+
const binary = atob(padded);
|
|
26
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
27
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function getTokenMaxAge(token) {
|
|
34
|
+
const exp = decodeJwtPayload(token)?.exp;
|
|
35
|
+
if (typeof exp !== 'number')
|
|
36
|
+
return null;
|
|
37
|
+
return Math.max(0, exp - Math.floor(Date.now() / 1000));
|
|
38
|
+
}
|
|
39
|
+
function isTokenExpired(token) {
|
|
40
|
+
const maxAge = getTokenMaxAge(token);
|
|
41
|
+
if (maxAge === null)
|
|
42
|
+
return true;
|
|
43
|
+
return maxAge <= 0;
|
|
44
|
+
}
|
|
45
|
+
export class CookieTokenManager {
|
|
46
|
+
cookies;
|
|
47
|
+
cookieOptions;
|
|
48
|
+
constructor(cookies, cookieOptions) {
|
|
49
|
+
this.cookies = cookies;
|
|
50
|
+
this.cookieOptions = { ...DEFAULT_COOKIE_OPTIONS, ...cookieOptions };
|
|
51
|
+
}
|
|
52
|
+
getAccessToken(refreshFn) {
|
|
53
|
+
const accessToken = this.cookies.get(ACCESS_TOKEN_COOKIE) ?? null;
|
|
54
|
+
// If we have an access token, return it directly
|
|
55
|
+
if (accessToken && !isTokenExpired(accessToken))
|
|
56
|
+
return accessToken;
|
|
57
|
+
if (accessToken) {
|
|
58
|
+
this.cookies.delete(ACCESS_TOKEN_COOKIE);
|
|
59
|
+
}
|
|
60
|
+
// If no access token but we have a refresh token and a refresh function,
|
|
61
|
+
// try to refresh
|
|
62
|
+
const refreshToken = this.getRefreshToken();
|
|
63
|
+
if (refreshToken && refreshFn) {
|
|
64
|
+
return refreshFn(refreshToken).then((tokens) => {
|
|
65
|
+
this.setTokens(tokens);
|
|
66
|
+
return tokens.accessToken;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
getRefreshToken() {
|
|
72
|
+
return this.cookies.get(REFRESH_TOKEN_COOKIE) ?? null;
|
|
73
|
+
}
|
|
74
|
+
invalidateAccessToken() {
|
|
75
|
+
this.cookies.delete(ACCESS_TOKEN_COOKIE);
|
|
76
|
+
}
|
|
77
|
+
setTokens(tokens) {
|
|
78
|
+
const accessMaxAge = getTokenMaxAge(tokens.accessToken) ?? 900;
|
|
79
|
+
const refreshMaxAge = getTokenMaxAge(tokens.refreshToken) ?? 60 * 60 * 24 * 28;
|
|
80
|
+
this.cookies.set(ACCESS_TOKEN_COOKIE, tokens.accessToken, {
|
|
81
|
+
...this.cookieOptions,
|
|
82
|
+
maxAge: accessMaxAge,
|
|
83
|
+
});
|
|
84
|
+
this.cookies.set(REFRESH_TOKEN_COOKIE, tokens.refreshToken, {
|
|
85
|
+
...this.cookieOptions,
|
|
86
|
+
maxAge: refreshMaxAge,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
clearTokens() {
|
|
90
|
+
this.cookies.delete(ACCESS_TOKEN_COOKIE);
|
|
91
|
+
this.cookies.delete(REFRESH_TOKEN_COOKIE);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=cookie-token-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie-token-manager.js","sourceRoot":"","sources":["../src/cookie-token-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @edge-base/ssr — Server-side rendering helpers for EdgeBase.
|
|
3
|
+
*
|
|
4
|
+
* Provides cookie-based token management for SSR frameworks
|
|
5
|
+
* (Next.js, Nuxt, SvelteKit, Remix, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createServerClient } from '@edge-base/ssr';
|
|
10
|
+
*
|
|
11
|
+
* const client = createServerClient('https://my-app.edgebase.fun', {
|
|
12
|
+
* cookies: {
|
|
13
|
+
* get: (name) => cookieStore.get(name)?.value,
|
|
14
|
+
* set: (name, value, options) => cookieStore.set(name, value, options),
|
|
15
|
+
* delete: (name) => cookieStore.delete(name),
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const user = client.getUser();
|
|
20
|
+
* const posts = await client.db('shared').table('posts').get();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export { ServerEdgeBase, type ServerUser } from './server-client.js';
|
|
24
|
+
export { CookieTokenManager } from './cookie-token-manager.js';
|
|
25
|
+
export type { CookieStore, CookieOptions, ServerClientOptions } from './types.js';
|
|
26
|
+
export type { ITokenPair } from '@edge-base/core';
|
|
27
|
+
export { EdgeBaseError } from '@edge-base/core';
|
|
28
|
+
import { ServerEdgeBase } from './server-client.js';
|
|
29
|
+
import type { ServerClientOptions } from './types.js';
|
|
30
|
+
/**
|
|
31
|
+
* Create a server-side EdgeBase client with cookie-based token management.
|
|
32
|
+
*
|
|
33
|
+
* @param url - EdgeBase project URL
|
|
34
|
+
* @param options - Cookie store and optional settings
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // Next.js App Router (Server Component)
|
|
38
|
+
* import { cookies } from 'next/headers';
|
|
39
|
+
* const cookieStore = await cookies();
|
|
40
|
+
* const client = createServerClient(process.env.EDGEBASE_URL!, {
|
|
41
|
+
* cookies: {
|
|
42
|
+
* get: (name) => cookieStore.get(name)?.value,
|
|
43
|
+
* set: (name, value, options) => cookieStore.set(name, value, options),
|
|
44
|
+
* delete: (name) => cookieStore.delete(name),
|
|
45
|
+
* },
|
|
46
|
+
* });
|
|
47
|
+
*/
|
|
48
|
+
export declare function createServerClient(url: string, options: ServerClientOptions): ServerEdgeBase;
|
|
49
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAG/D,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGlF,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAE5F"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @edge-base/ssr — Server-side rendering helpers for EdgeBase.
|
|
3
|
+
*
|
|
4
|
+
* Provides cookie-based token management for SSR frameworks
|
|
5
|
+
* (Next.js, Nuxt, SvelteKit, Remix, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createServerClient } from '@edge-base/ssr';
|
|
10
|
+
*
|
|
11
|
+
* const client = createServerClient('https://my-app.edgebase.fun', {
|
|
12
|
+
* cookies: {
|
|
13
|
+
* get: (name) => cookieStore.get(name)?.value,
|
|
14
|
+
* set: (name, value, options) => cookieStore.set(name, value, options),
|
|
15
|
+
* delete: (name) => cookieStore.delete(name),
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const user = client.getUser();
|
|
20
|
+
* const posts = await client.db('shared').table('posts').get();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
// Server client
|
|
24
|
+
export { ServerEdgeBase } from './server-client.js';
|
|
25
|
+
// Cookie token manager (for advanced usage)
|
|
26
|
+
export { CookieTokenManager } from './cookie-token-manager.js';
|
|
27
|
+
export { EdgeBaseError } from '@edge-base/core';
|
|
28
|
+
// ─── Factory ───
|
|
29
|
+
import { ServerEdgeBase } from './server-client.js';
|
|
30
|
+
/**
|
|
31
|
+
* Create a server-side EdgeBase client with cookie-based token management.
|
|
32
|
+
*
|
|
33
|
+
* @param url - EdgeBase project URL
|
|
34
|
+
* @param options - Cookie store and optional settings
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // Next.js App Router (Server Component)
|
|
38
|
+
* import { cookies } from 'next/headers';
|
|
39
|
+
* const cookieStore = await cookies();
|
|
40
|
+
* const client = createServerClient(process.env.EDGEBASE_URL!, {
|
|
41
|
+
* cookies: {
|
|
42
|
+
* get: (name) => cookieStore.get(name)?.value,
|
|
43
|
+
* set: (name, value, options) => cookieStore.set(name, value, options),
|
|
44
|
+
* delete: (name) => cookieStore.delete(name),
|
|
45
|
+
* },
|
|
46
|
+
* });
|
|
47
|
+
*/
|
|
48
|
+
export function createServerClient(url, options) {
|
|
49
|
+
return new ServerEdgeBase(url, options);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,gBAAgB;AAChB,OAAO,EAAE,cAAc,EAAmB,MAAM,oBAAoB,CAAC;AAErE,4CAA4C;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAO/D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,kBAAkB;AAElB,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,OAA4B;IAC1E,OAAO,IAAI,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServerEdgeBase — SSR-optimized EdgeBase client.
|
|
3
|
+
*
|
|
4
|
+
* Uses cookie-based token management instead of localStorage.
|
|
5
|
+
* Provides db(), storage, and functions access on behalf of the authenticated user.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createServerClient } from '@edge-base/ssr';
|
|
10
|
+
* const client = createServerClient('https://my-app.edgebase.fun', {
|
|
11
|
+
* cookies: cookieStore,
|
|
12
|
+
* });
|
|
13
|
+
* const posts = await client.db('shared').table('posts').get();
|
|
14
|
+
* const health = await client.functions.get('public/health');
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import { DbRef, StorageClient, FunctionsClient } from '@edge-base/core';
|
|
18
|
+
import type { ITokenPair } from '@edge-base/core';
|
|
19
|
+
import type { ServerClientOptions } from './types.js';
|
|
20
|
+
/** Decoded user from JWT access token (payload only, no verification). */
|
|
21
|
+
export interface ServerUser {
|
|
22
|
+
id: string;
|
|
23
|
+
email?: string;
|
|
24
|
+
displayName?: string;
|
|
25
|
+
avatarUrl?: string;
|
|
26
|
+
role?: string;
|
|
27
|
+
isAnonymous?: boolean;
|
|
28
|
+
emailVisibility?: string;
|
|
29
|
+
custom?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Server-side EdgeBase client for SSR environments.
|
|
33
|
+
*
|
|
34
|
+
* Exposes: db(), storage, functions, getUser(), getSession().
|
|
35
|
+
* Does NOT expose: auth signIn/signUp (client-side only), database-live, room, push.
|
|
36
|
+
*/
|
|
37
|
+
export declare class ServerEdgeBase {
|
|
38
|
+
readonly storage: StorageClient;
|
|
39
|
+
readonly functions: FunctionsClient;
|
|
40
|
+
private httpClient;
|
|
41
|
+
private tokenManager;
|
|
42
|
+
private baseUrl;
|
|
43
|
+
private core;
|
|
44
|
+
constructor(url: string, options: ServerClientOptions);
|
|
45
|
+
/**
|
|
46
|
+
* Access a database by namespace + optional instance ID.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const posts = await client.db('shared').table('posts').get();
|
|
50
|
+
* const docs = await client.db('workspace', 'ws-456').table('documents').get();
|
|
51
|
+
*/
|
|
52
|
+
db(namespace: string, id?: string): DbRef;
|
|
53
|
+
/**
|
|
54
|
+
* Get the current authenticated user from the cookie token.
|
|
55
|
+
* Decodes the JWT payload without server verification.
|
|
56
|
+
* Returns null if no valid access token is present.
|
|
57
|
+
*/
|
|
58
|
+
getUser(): ServerUser | null;
|
|
59
|
+
/**
|
|
60
|
+
* Get the current session tokens.
|
|
61
|
+
* Useful for passing tokens to client-side hydration.
|
|
62
|
+
*/
|
|
63
|
+
getSession(): {
|
|
64
|
+
accessToken: string | null;
|
|
65
|
+
refreshToken: string | null;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Set session tokens (e.g., after OAuth callback on the server).
|
|
69
|
+
* Writes tokens to cookies for subsequent requests.
|
|
70
|
+
*/
|
|
71
|
+
setSession(tokens: ITokenPair): void;
|
|
72
|
+
/**
|
|
73
|
+
* Clear session tokens (server-side sign out).
|
|
74
|
+
* Removes token cookies.
|
|
75
|
+
*/
|
|
76
|
+
clearSession(): void;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=server-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-client.d.ts","sourceRoot":"","sources":["../src/server-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAEL,KAAK,EACL,aAAa,EACb,eAAe,EAIhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAe;gBACf,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB;IAgBrD;;;;;;OAMG;IACH,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK;IAIzC;;;;OAIG;IACH,OAAO,IAAI,UAAU,GAAG,IAAI;IAM5B;;;OAGG;IACH,UAAU,IAAI;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;IAOzE;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIpC;;;OAGG;IACH,YAAY,IAAI,IAAI;CAIrB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServerEdgeBase — SSR-optimized EdgeBase client.
|
|
3
|
+
*
|
|
4
|
+
* Uses cookie-based token management instead of localStorage.
|
|
5
|
+
* Provides db(), storage, and functions access on behalf of the authenticated user.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createServerClient } from '@edge-base/ssr';
|
|
10
|
+
* const client = createServerClient('https://my-app.edgebase.fun', {
|
|
11
|
+
* cookies: cookieStore,
|
|
12
|
+
* });
|
|
13
|
+
* const posts = await client.db('shared').table('posts').get();
|
|
14
|
+
* const health = await client.functions.get('public/health');
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import { HttpClient, DbRef, StorageClient, FunctionsClient, ContextManager, DefaultDbApi, HttpClientAdapter, } from '@edge-base/core';
|
|
18
|
+
import { CookieTokenManager } from './cookie-token-manager.js';
|
|
19
|
+
/**
|
|
20
|
+
* Server-side EdgeBase client for SSR environments.
|
|
21
|
+
*
|
|
22
|
+
* Exposes: db(), storage, functions, getUser(), getSession().
|
|
23
|
+
* Does NOT expose: auth signIn/signUp (client-side only), database-live, room, push.
|
|
24
|
+
*/
|
|
25
|
+
export class ServerEdgeBase {
|
|
26
|
+
storage;
|
|
27
|
+
functions;
|
|
28
|
+
httpClient;
|
|
29
|
+
tokenManager;
|
|
30
|
+
baseUrl;
|
|
31
|
+
core;
|
|
32
|
+
constructor(url, options) {
|
|
33
|
+
this.baseUrl = url.replace(/\/$/, '');
|
|
34
|
+
this.tokenManager = new CookieTokenManager(options.cookies, options.cookieOptions);
|
|
35
|
+
this.httpClient = new HttpClient({
|
|
36
|
+
baseUrl: this.baseUrl,
|
|
37
|
+
tokenManager: options.serviceKey ? undefined : this.tokenManager,
|
|
38
|
+
serviceKey: options.serviceKey,
|
|
39
|
+
contextManager: new ContextManager(),
|
|
40
|
+
});
|
|
41
|
+
this.core = new DefaultDbApi(new HttpClientAdapter(this.httpClient));
|
|
42
|
+
this.storage = new StorageClient(this.httpClient, this.core);
|
|
43
|
+
this.functions = new FunctionsClient(this.httpClient);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Access a database by namespace + optional instance ID.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const posts = await client.db('shared').table('posts').get();
|
|
50
|
+
* const docs = await client.db('workspace', 'ws-456').table('documents').get();
|
|
51
|
+
*/
|
|
52
|
+
db(namespace, id) {
|
|
53
|
+
return new DbRef(this.core, namespace, id, undefined, undefined);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the current authenticated user from the cookie token.
|
|
57
|
+
* Decodes the JWT payload without server verification.
|
|
58
|
+
* Returns null if no valid access token is present.
|
|
59
|
+
*/
|
|
60
|
+
getUser() {
|
|
61
|
+
const token = this.tokenManager.getAccessToken();
|
|
62
|
+
if (!token)
|
|
63
|
+
return null;
|
|
64
|
+
return decodeJwtPayload(token);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get the current session tokens.
|
|
68
|
+
* Useful for passing tokens to client-side hydration.
|
|
69
|
+
*/
|
|
70
|
+
getSession() {
|
|
71
|
+
return {
|
|
72
|
+
accessToken: this.tokenManager.getAccessToken(),
|
|
73
|
+
refreshToken: this.tokenManager.getRefreshToken(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Set session tokens (e.g., after OAuth callback on the server).
|
|
78
|
+
* Writes tokens to cookies for subsequent requests.
|
|
79
|
+
*/
|
|
80
|
+
setSession(tokens) {
|
|
81
|
+
this.tokenManager.setTokens(tokens);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Clear session tokens (server-side sign out).
|
|
85
|
+
* Removes token cookies.
|
|
86
|
+
*/
|
|
87
|
+
clearSession() {
|
|
88
|
+
this.tokenManager.clearTokens();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// ─── JWT Decode (payload only, no verification) ───
|
|
92
|
+
function decodeJwtPayload(token) {
|
|
93
|
+
try {
|
|
94
|
+
const parts = token.split('.');
|
|
95
|
+
if (parts.length !== 3)
|
|
96
|
+
return null;
|
|
97
|
+
// Base64url decode the payload
|
|
98
|
+
const payload = parts[1]
|
|
99
|
+
.replace(/-/g, '+')
|
|
100
|
+
.replace(/_/g, '/');
|
|
101
|
+
const padded = payload + '='.repeat((4 - (payload.length % 4)) % 4);
|
|
102
|
+
// Use TextDecoder for portable base64 decoding (Node 16+, Deno, Bun, Edge)
|
|
103
|
+
const bytes = Uint8Array.from(
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
+
globalThis.atob(padded), (c) => c.charCodeAt(0));
|
|
106
|
+
const json = new TextDecoder().decode(bytes);
|
|
107
|
+
const data = JSON.parse(json);
|
|
108
|
+
return {
|
|
109
|
+
id: data.sub ?? data.id,
|
|
110
|
+
email: data.email,
|
|
111
|
+
displayName: data.displayName,
|
|
112
|
+
avatarUrl: data.avatarUrl,
|
|
113
|
+
role: data.role,
|
|
114
|
+
isAnonymous: data.isAnonymous,
|
|
115
|
+
emailVisibility: data.emailVisibility,
|
|
116
|
+
custom: data.custom,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=server-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-client.js","sourceRoot":"","sources":["../src/server-client.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @edge-base/ssr — Type definitions for cookie-based SSR authentication.
|
|
3
|
+
*/
|
|
4
|
+
/** Options for cookie serialization. */
|
|
5
|
+
export interface CookieOptions {
|
|
6
|
+
httpOnly?: boolean;
|
|
7
|
+
secure?: boolean;
|
|
8
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
9
|
+
maxAge?: number;
|
|
10
|
+
path?: string;
|
|
11
|
+
domain?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Abstract cookie store interface.
|
|
15
|
+
*
|
|
16
|
+
* Implementations:
|
|
17
|
+
* - Next.js App Router: `cookies()` from `next/headers`
|
|
18
|
+
* - Next.js Pages Router: wrapper around `nookies` or `req.cookies` + `res.setHeader`
|
|
19
|
+
* - Nuxt 3: wrapper around `useCookie` or `getCookie`/`setCookie` from `h3`
|
|
20
|
+
* - SvelteKit: wrapper around `cookies` from `event`
|
|
21
|
+
*/
|
|
22
|
+
export interface CookieStore {
|
|
23
|
+
/** Get a cookie value by name. Returns null/undefined if not set. */
|
|
24
|
+
get(name: string): string | null | undefined;
|
|
25
|
+
/** Set a cookie with the given name, value, and options. */
|
|
26
|
+
set(name: string, value: string, options?: CookieOptions): void;
|
|
27
|
+
/** Delete a cookie by name. */
|
|
28
|
+
delete(name: string): void;
|
|
29
|
+
}
|
|
30
|
+
/** Options for creating a server-side EdgeBase client. */
|
|
31
|
+
export interface ServerClientOptions {
|
|
32
|
+
/** Cookie store for token persistence across requests. */
|
|
33
|
+
cookies: CookieStore;
|
|
34
|
+
/** Override default cookie options (httpOnly, secure, sameSite, path). */
|
|
35
|
+
cookieOptions?: Partial<CookieOptions>;
|
|
36
|
+
/**
|
|
37
|
+
* Service key for admin-level access.
|
|
38
|
+
* When provided, requests use the service key instead of user tokens.
|
|
39
|
+
*/
|
|
40
|
+
serviceKey?: string;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,4DAA4D;IAC5D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAChE,+BAA+B;IAC/B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,OAAO,EAAE,WAAW,CAAC;IACrB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# EdgeBase JS SSR SDK
|
|
2
|
+
|
|
3
|
+
Use this file as a quick-reference contract for AI coding assistants working with `@edge-base/ssr`.
|
|
4
|
+
|
|
5
|
+
## Package Boundary
|
|
6
|
+
|
|
7
|
+
Use `@edge-base/ssr` for server-side code that should act as the current cookie-authenticated user.
|
|
8
|
+
|
|
9
|
+
Do not use it for browser bundles or client-side sign-in UI. Use `@edge-base/web` there. Do not use it for Service Key admin work; use `@edge-base/admin`.
|
|
10
|
+
|
|
11
|
+
## Source Of Truth
|
|
12
|
+
|
|
13
|
+
- Package README: https://github.com/edge-base/edgebase/blob/main/packages/sdk/js/packages/ssr/README.md
|
|
14
|
+
- Next.js guide: https://edgebase.fun/docs/sdks/nextjs
|
|
15
|
+
- Client vs server SDKs: https://edgebase.fun/docs/sdks/client-vs-server
|
|
16
|
+
- Authentication: https://edgebase.fun/docs/authentication
|
|
17
|
+
- Database client SDK: https://edgebase.fun/docs/database/client-sdk
|
|
18
|
+
|
|
19
|
+
## Canonical Examples
|
|
20
|
+
|
|
21
|
+
### Create a server client
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createServerClient } from '@edge-base/ssr';
|
|
25
|
+
|
|
26
|
+
const client = createServerClient(process.env.EDGEBASE_URL!, {
|
|
27
|
+
cookies: {
|
|
28
|
+
get: (name) => cookieStore.get(name)?.value,
|
|
29
|
+
set: (name, value, options) => cookieStore.set(name, value, options),
|
|
30
|
+
delete: (name) => cookieStore.delete(name),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Read the current user
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const user = client.getUser();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Query data on the server
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const posts = await client
|
|
45
|
+
.db('app')
|
|
46
|
+
.table('posts')
|
|
47
|
+
.where('published', '==', true)
|
|
48
|
+
.getList();
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Write cookies after an OAuth callback
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
client.setSession({
|
|
55
|
+
accessToken,
|
|
56
|
+
refreshToken,
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Clear the session
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
client.clearSession();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Hard Rules
|
|
67
|
+
|
|
68
|
+
- `createServerClient(url, options)` requires a cookie adapter
|
|
69
|
+
- the cookie adapter must implement `get(name)`, `set(name, value, options?)`, and `delete(name)`
|
|
70
|
+
- `getUser()` is synchronous and returns decoded JWT payload data or `null`
|
|
71
|
+
- `getSession()` is synchronous
|
|
72
|
+
- `setSession()` and `clearSession()` are synchronous cookie operations
|
|
73
|
+
- `client.db(namespace, id?)` takes the instance id positionally
|
|
74
|
+
- this package exposes `db`, `storage`, and `functions`
|
|
75
|
+
- this package does not expose browser auth flows, database live, rooms, or push
|
|
76
|
+
|
|
77
|
+
## Common Mistakes
|
|
78
|
+
|
|
79
|
+
- do not call browser-only auth methods like `client.auth.signIn()` here; this package does not expose them
|
|
80
|
+
- do not use `@edge-base/ssr` in client components
|
|
81
|
+
- do not confuse `getUser()` with a server-side verification call; it decodes the cookie token payload
|
|
82
|
+
- if you need privileged admin access or Service Key behavior, use `@edge-base/admin`
|
|
83
|
+
- if you need browser auth state listeners or realtime UI, use `@edge-base/web`
|
|
84
|
+
|
|
85
|
+
## Quick Reference
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
createServerClient(url, { cookies, cookieOptions?, serviceKey? }) -> ServerEdgeBase
|
|
89
|
+
client.getUser() -> ServerUser | null
|
|
90
|
+
client.getSession() -> { accessToken, refreshToken }
|
|
91
|
+
client.setSession(tokens) -> void
|
|
92
|
+
client.clearSession() -> void
|
|
93
|
+
client.db(namespace, id?) -> DbRef
|
|
94
|
+
client.storage -> StorageClient
|
|
95
|
+
client.functions -> FunctionsClient
|
|
96
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@edge-base/ssr",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "EdgeBase SSR helpers — cookie-based token management for server-side rendering",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/edge-base/edgebase.git",
|
|
9
|
+
"directory": "packages/sdk/js/packages/ssr"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://edgebase.fun",
|
|
12
|
+
"bugs": "https://github.com/edge-base/edgebase/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"edgebase",
|
|
15
|
+
"ssr",
|
|
16
|
+
"server-side-rendering",
|
|
17
|
+
"cookies",
|
|
18
|
+
"auth"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"llms.txt"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"dev": "tsc --watch",
|
|
40
|
+
"prepack": "pnpm run build"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@edge-base/core": "workspace:*"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"typescript": "^5.7.0"
|
|
47
|
+
}
|
|
48
|
+
}
|