@zentry-org/sdk 0.0.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 +579 -0
- package/dist/chunk-OMDRZCFK.js +2 -0
- package/dist/chunk-SCUKQ3VA.js +2 -0
- package/dist/node/index.cjs +2 -0
- package/dist/node/index.d.cts +37 -0
- package/dist/node/index.d.ts +37 -0
- package/dist/node/index.js +2 -0
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.d.cts +70 -0
- package/dist/react/index.d.ts +70 -0
- package/dist/react/index.js +2 -0
- package/dist/react/server.cjs +2 -0
- package/dist/react/server.d.cts +3 -0
- package/dist/react/server.d.ts +3 -0
- package/dist/react/server.js +2 -0
- package/dist/server-CZ-Exumw.d.cts +100 -0
- package/dist/server-OYDWuirO.d.ts +100 -0
- package/dist/zod-DbKYqexO.d.cts +43 -0
- package/dist/zod-DbKYqexO.d.ts +43 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
# `@zentry-org/sdk`
|
|
2
|
+
|
|
3
|
+
Zentry SDK for frontend apps and backend APIs.
|
|
4
|
+
|
|
5
|
+
This package supports two integration layers:
|
|
6
|
+
|
|
7
|
+
- `@zentry-org/sdk/react` for browser apps such as Vite + React, Next.js, and TanStack Start
|
|
8
|
+
- `@zentry-org/sdk/node` for backend APIs such as Express
|
|
9
|
+
|
|
10
|
+
Both layers use the same normalized session payload: `ZentrySessionType`.
|
|
11
|
+
|
|
12
|
+
## How Zentry Works
|
|
13
|
+
|
|
14
|
+
Zentry separates:
|
|
15
|
+
|
|
16
|
+
- organization identity
|
|
17
|
+
- end-user identity
|
|
18
|
+
|
|
19
|
+
For a request to be treated as an authenticated user request inside an organization:
|
|
20
|
+
|
|
21
|
+
1. the frontend authenticates the user with Zentry
|
|
22
|
+
2. Zentry issues a user session token
|
|
23
|
+
3. the frontend stores that token in `localStorage`
|
|
24
|
+
4. the frontend sends the token on requests to the developer's backend API
|
|
25
|
+
5. the backend validates that user token against Zentry using:
|
|
26
|
+
- the forwarded user token
|
|
27
|
+
- the organization's `orgId`
|
|
28
|
+
- the organization's secret `apiKey`
|
|
29
|
+
6. Zentry returns the validated session in the shared `ZentrySessionType` shape
|
|
30
|
+
|
|
31
|
+
The backend never identifies a user from `orgId` and `apiKey` alone. Those values identify the organization and application. The user token identifies the signed-in user.
|
|
32
|
+
|
|
33
|
+
## Shared Session Shape
|
|
34
|
+
|
|
35
|
+
The React SDK and Node SDK both work with the same session structure from [`src/zod.ts`](./src/zod.ts):
|
|
36
|
+
|
|
37
|
+
- `user`
|
|
38
|
+
- `org`
|
|
39
|
+
- `membership`
|
|
40
|
+
- `account`
|
|
41
|
+
|
|
42
|
+
Backend middleware attaches this payload to:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
req.zentry
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Type:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import type { ZentrySessionType } from '@zentry-org/sdk/react';
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pnpm add @zentry-org/sdk
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Peer dependencies:
|
|
61
|
+
|
|
62
|
+
- `react` for the React SDK
|
|
63
|
+
- `express` for the Node SDK
|
|
64
|
+
|
|
65
|
+
## React Setup
|
|
66
|
+
|
|
67
|
+
Use the React SDK in your frontend application to:
|
|
68
|
+
|
|
69
|
+
- redirect users to Zentry login/register
|
|
70
|
+
- sync the current session from Zentry
|
|
71
|
+
- access the authenticated session in React
|
|
72
|
+
- capture the callback token returned by Zentry
|
|
73
|
+
- use built-in unstyled auth components if you do not want to wire the buttons yourself
|
|
74
|
+
|
|
75
|
+
### Required frontend env
|
|
76
|
+
|
|
77
|
+
The React SDK expects:
|
|
78
|
+
|
|
79
|
+
```env
|
|
80
|
+
ZENTRY_ORG_ID=your-org-id
|
|
81
|
+
ZENTRY_APP_CALLBACK_URL=http://localhost:3000/auth/callback
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Notes:
|
|
85
|
+
|
|
86
|
+
- `ZENTRY_ORG_ID` identifies the organization context
|
|
87
|
+
- `ZENTRY_APP_CALLBACK_URL` is the frontend route Zentry redirects back to after login/register
|
|
88
|
+
- the SDK uses its internal fixed Zentry API base URL constant
|
|
89
|
+
|
|
90
|
+
### Built-in React components
|
|
91
|
+
|
|
92
|
+
The SDK already exports raw, unstyled HTML components.
|
|
93
|
+
|
|
94
|
+
- `RegisterButton`
|
|
95
|
+
- `LoginButton`
|
|
96
|
+
- `LogoutButton`
|
|
97
|
+
- `Authenticated`
|
|
98
|
+
- `UnAuthenticated`
|
|
99
|
+
|
|
100
|
+
These are intentionally unstyled so each app can theme them however it wants.
|
|
101
|
+
|
|
102
|
+
Example:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import {
|
|
106
|
+
Authenticated,
|
|
107
|
+
LoginButton,
|
|
108
|
+
LogoutButton,
|
|
109
|
+
RegisterButton,
|
|
110
|
+
UnAuthenticated,
|
|
111
|
+
} from '@zentry-org/sdk/react';
|
|
112
|
+
|
|
113
|
+
export function AuthActions() {
|
|
114
|
+
return (
|
|
115
|
+
<>
|
|
116
|
+
<UnAuthenticated>
|
|
117
|
+
<RegisterButton className="btn btn-secondary" />
|
|
118
|
+
<LoginButton className="btn btn-primary" />
|
|
119
|
+
</UnAuthenticated>
|
|
120
|
+
|
|
121
|
+
<Authenticated>
|
|
122
|
+
<LogoutButton className="btn btn-danger" label="Sign out" />
|
|
123
|
+
</Authenticated>
|
|
124
|
+
</>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Framework examples
|
|
130
|
+
|
|
131
|
+
### Vite + React
|
|
132
|
+
|
|
133
|
+
Wrap your root app with `ZentryProvider`:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { ZentryProvider } from '@zentry-org/sdk/react';
|
|
137
|
+
|
|
138
|
+
export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
139
|
+
return (
|
|
140
|
+
<ZentryProvider
|
|
141
|
+
env={{
|
|
142
|
+
ZENTRY_ORG_ID: import.meta.env.VITE_ZENTRY_ORG_ID,
|
|
143
|
+
ZENTRY_APP_CALLBACK_URL: `${window.location.origin}/auth/callback`,
|
|
144
|
+
}}
|
|
145
|
+
>
|
|
146
|
+
{children}
|
|
147
|
+
</ZentryProvider>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Then mount it in `src/main.tsx`:
|
|
153
|
+
```tsx
|
|
154
|
+
import { AppProviders } from './AppProviders';
|
|
155
|
+
import { createRoot } from 'react-dom/client';
|
|
156
|
+
import App from './App';
|
|
157
|
+
import './index.css';
|
|
158
|
+
|
|
159
|
+
createRoot(document.getElementById('root')!).render(
|
|
160
|
+
<AppProviders>
|
|
161
|
+
<App />
|
|
162
|
+
</AppProviders>
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Use the callback hook on your callback route:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { useZentryCallbackSync } from '@zentry-org/sdk/react';
|
|
171
|
+
|
|
172
|
+
export default function AuthCallbackPage() {
|
|
173
|
+
useZentryCallbackSync();
|
|
174
|
+
return <div>Signing you in...</div>;
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### TanStack Start
|
|
179
|
+
|
|
180
|
+
TanStack Start apps typically mount shared providers inside the root route shell.
|
|
181
|
+
In a setup like `your-app/src/routes/__root.tsx`,
|
|
182
|
+
add `ZentryProvider` inside the `RootDocument` body alongside your other app-wide providers.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
import * as React from 'react';
|
|
186
|
+
import { HeadContent, Scripts, createRootRouteWithContext } from '@tanstack/react-router';
|
|
187
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
188
|
+
import { ZentryProvider } from '@zentry-org/sdk/react';
|
|
189
|
+
|
|
190
|
+
interface MyRouterContext {
|
|
191
|
+
queryClient: QueryClient;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const Route = createRootRouteWithContext<MyRouterContext>()({
|
|
195
|
+
shellComponent: RootDocument,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
199
|
+
return (
|
|
200
|
+
<html lang="en">
|
|
201
|
+
<head>
|
|
202
|
+
<HeadContent />
|
|
203
|
+
</head>
|
|
204
|
+
<body>
|
|
205
|
+
<ZentryProvider env={{
|
|
206
|
+
ZENTRY_ORG_ID: import.meta.env.VITE_ZENTRY_ORG_ID,
|
|
207
|
+
ZENTRY_APP_CALLBACK_URL: `${window.location.origin}/auth/callback`,
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
{children}
|
|
211
|
+
</ZentryProvider>
|
|
212
|
+
<Scripts />
|
|
213
|
+
</body>
|
|
214
|
+
</html>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Example callback page:
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
223
|
+
import { useZentryCallbackSync } from '@zentry-org/sdk/react';
|
|
224
|
+
|
|
225
|
+
export const Route = createFileRoute('/auth/callback')({
|
|
226
|
+
component: AuthCallbackPage,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
function AuthCallbackPage() {
|
|
230
|
+
useZentryCallbackSync();
|
|
231
|
+
return <div>Signing you in...</div>;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Example server-side session lookup:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
import { createServerFn } from '@tanstack/react-start';
|
|
239
|
+
import { getServerSession } from '@zentry-org/sdk/react-server';
|
|
240
|
+
|
|
241
|
+
export const getCurrentSession = createServerFn({ method: 'POST' })
|
|
242
|
+
.validator((token: string) => token)
|
|
243
|
+
.handler(async ({ data }) => {
|
|
244
|
+
return getServerSession({
|
|
245
|
+
env: {
|
|
246
|
+
ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
247
|
+
},
|
|
248
|
+
token: data,
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Next.js
|
|
254
|
+
|
|
255
|
+
Wrap your client-side provider in a client component:
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
'use client';
|
|
259
|
+
|
|
260
|
+
import type { ReactNode } from 'react';
|
|
261
|
+
import { ZentryProvider } from '@zentry-org/sdk/react';
|
|
262
|
+
|
|
263
|
+
export function Providers({ children }: { children: ReactNode }) {
|
|
264
|
+
return (
|
|
265
|
+
<ZentryProvider
|
|
266
|
+
env={{
|
|
267
|
+
ZENTRY_ORG_ID: process.env.NEXT_PUBLIC_ZENTRY_ORG_ID!,
|
|
268
|
+
ZENTRY_APP_CALLBACK_URL: `${process.env.NEXT_PUBLIC_APP_URL!}/auth/callback`,
|
|
269
|
+
}}
|
|
270
|
+
>
|
|
271
|
+
{children}
|
|
272
|
+
</ZentryProvider>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Mount it in `app/layout.tsx` or `src/app/layout.tsx`:
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
import type { ReactNode } from 'react';
|
|
281
|
+
import { Providers } from './providers';
|
|
282
|
+
|
|
283
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
284
|
+
return (
|
|
285
|
+
<html lang="en">
|
|
286
|
+
<body>
|
|
287
|
+
<Providers>{children}</Providers>
|
|
288
|
+
</body>
|
|
289
|
+
</html>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Callback page example:
|
|
295
|
+
|
|
296
|
+
```tsx
|
|
297
|
+
'use client';
|
|
298
|
+
|
|
299
|
+
import { useZentryCallbackSync } from '@zentry-org/sdk/react';
|
|
300
|
+
|
|
301
|
+
export default function AuthCallbackPage() {
|
|
302
|
+
useZentryCallbackSync();
|
|
303
|
+
return <div>Signing you in...</div>;
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Server component session lookup example:
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
import { cookies } from 'next/headers';
|
|
311
|
+
import { getServerSession } from '@zentry-org/sdk/react-server';
|
|
312
|
+
|
|
313
|
+
export default async function DashboardPage() {
|
|
314
|
+
const cookieStore = await cookies();
|
|
315
|
+
|
|
316
|
+
const session = await getServerSession({
|
|
317
|
+
env: {
|
|
318
|
+
ZENTRY_ORG_ID: process.env.NEXT_PUBLIC_ZENTRY_ORG_ID!,
|
|
319
|
+
},
|
|
320
|
+
cookie: cookieStore.toString(),
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (!session) {
|
|
324
|
+
return <div>No session found</div>;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return <div>Welcome {session.user.firstName}</div>;
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Read auth state
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
import { useZentry, LogoutButton} from '@zentry-org/sdk/react';
|
|
335
|
+
|
|
336
|
+
export function Profile() {
|
|
337
|
+
const { session, isAuthenticated, isLoading } = useZentry();
|
|
338
|
+
|
|
339
|
+
if (isLoading) return <div>Loading...</div>;
|
|
340
|
+
if (!isAuthenticated) {
|
|
341
|
+
return (
|
|
342
|
+
<div>
|
|
343
|
+
<p>You are not logged in.</p>
|
|
344
|
+
</div>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<div>
|
|
350
|
+
<p>User ID: {session?.user.id}</p>
|
|
351
|
+
<p>Org ID: {session?.org.id}</p>
|
|
352
|
+
<p>Role: {session?.membership.role}</p>
|
|
353
|
+
<LogoutButton label="Sign out" />
|
|
354
|
+
</div>
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Capture the callback token
|
|
360
|
+
|
|
361
|
+
When Zentry redirects back to your app, the token is returned in the URL. Use `useZentryCallbackSync()` on the callback page to:
|
|
362
|
+
|
|
363
|
+
- read the token from the query string
|
|
364
|
+
- store it in `localStorage`
|
|
365
|
+
- clear it from the URL
|
|
366
|
+
- reload the app so session sync runs again
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
import { useZentryCallbackSync } from '@zentry-org/sdk/react';
|
|
370
|
+
|
|
371
|
+
export default function AuthCallbackPage() {
|
|
372
|
+
useZentryCallbackSync();
|
|
373
|
+
|
|
374
|
+
return <div>Signing you in...</div>;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Frontend request forwarding
|
|
379
|
+
|
|
380
|
+
When your frontend calls your own backend API, forward the Zentry token:
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import axios from 'axios';
|
|
384
|
+
import { useZentry } from '@zentry-org/sdk/react';
|
|
385
|
+
|
|
386
|
+
export function ExampleButton() {
|
|
387
|
+
const { getSessionToken } = useZentry();
|
|
388
|
+
|
|
389
|
+
async function handleClick() {
|
|
390
|
+
const token = getSessionToken();
|
|
391
|
+
if (!token) return;
|
|
392
|
+
|
|
393
|
+
// Forward the token to the backend API when making requests
|
|
394
|
+
await axios.get('/api/v1/*', {
|
|
395
|
+
headers: {
|
|
396
|
+
Authorization: `Bearer ${token}`,
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return <button onClick={handleClick}>Call API</button>;
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
You can isolate the token attachment logic from the UI. (only work in browser environments, for server environments use the `getServerSession` helper described below)
|
|
406
|
+
```ts
|
|
407
|
+
import { useZentry } from '@zentry-org/sdk/react';
|
|
408
|
+
import axios from 'axios';
|
|
409
|
+
|
|
410
|
+
export const api = axios.create({
|
|
411
|
+
baseURL: 'your-api-url',
|
|
412
|
+
withCredentials: true,
|
|
413
|
+
headers: {
|
|
414
|
+
'Content-Type': 'application/json',
|
|
415
|
+
},
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
api.interceptors.request.use((config) => {
|
|
419
|
+
if (typeof window !== 'undefined') {
|
|
420
|
+
const { getSessionToken } = useZentry();
|
|
421
|
+
const storedToken = getSessionToken();
|
|
422
|
+
|
|
423
|
+
if (storedToken) {
|
|
424
|
+
config.headers = axios.AxiosHeaders.from(config.headers);
|
|
425
|
+
config.headers.set('Authorization', `Bearer ${storedToken}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return config;
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
This is the current integration model: the frontend forwards the user session token stored in `localStorage` to the developer's backend API on each authenticated request.
|
|
434
|
+
|
|
435
|
+
## React Server Session Helper
|
|
436
|
+
|
|
437
|
+
For server-side React code, use the server helper when you need to validate a forwarded token or incoming cookie against Zentry.
|
|
438
|
+
|
|
439
|
+
Import path:
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
import { getServerSession } from '@zentry-org/sdk/react-server';
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Example:
|
|
446
|
+
|
|
447
|
+
```ts
|
|
448
|
+
import { getServerSession } from '@zentry-org/sdk/react-server';
|
|
449
|
+
|
|
450
|
+
export async function loadSession(token: string) {
|
|
451
|
+
return getServerSession({
|
|
452
|
+
env: {
|
|
453
|
+
ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
454
|
+
},
|
|
455
|
+
token,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Node / Express Setup
|
|
461
|
+
|
|
462
|
+
Use the Node SDK in the developer's backend API to validate the forwarded user token with Zentry.
|
|
463
|
+
|
|
464
|
+
### Required backend env
|
|
465
|
+
|
|
466
|
+
```env
|
|
467
|
+
ZENTRY_ORG_ID=your-org-id
|
|
468
|
+
ZENTRY_API_KEY_RAW=your-org-api-key
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Notes:
|
|
472
|
+
|
|
473
|
+
- `ZENTRY_ORG_ID` identifies the organization
|
|
474
|
+
- `ZENTRY_API_KEY_RAW` is the secret API key for the organization
|
|
475
|
+
- the Node SDK uses the internal fixed Zentry API base URL constant
|
|
476
|
+
|
|
477
|
+
### Create the client
|
|
478
|
+
|
|
479
|
+
```ts
|
|
480
|
+
import { ZentryClient } from '@zentry-org/sdk/node';
|
|
481
|
+
|
|
482
|
+
export const zentry = new ZentryClient({
|
|
483
|
+
orgId: process.env.ZENTRY_ORG_ID!,
|
|
484
|
+
apiKey: process.env.ZENTRY_API_KEY_RAW!,
|
|
485
|
+
});
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Protect routes with `requireUser()`
|
|
489
|
+
|
|
490
|
+
`requireUser()`:
|
|
491
|
+
|
|
492
|
+
- reads the incoming bearer token from the developer API request
|
|
493
|
+
- calls Zentry to validate the token for the configured org
|
|
494
|
+
- validates the response shape
|
|
495
|
+
- attaches the session to `req.zentry`
|
|
496
|
+
|
|
497
|
+
```ts
|
|
498
|
+
import express from 'express';
|
|
499
|
+
import { zentry } from './zentry';
|
|
500
|
+
|
|
501
|
+
const app = express();
|
|
502
|
+
|
|
503
|
+
app.get('/api/me', zentry.requireUser(), (req, res) => {
|
|
504
|
+
res.json({
|
|
505
|
+
session: req.zentry,
|
|
506
|
+
userId: req.zentry?.user.id,
|
|
507
|
+
orgId: req.zentry?.org.id,
|
|
508
|
+
role: req.zentry?.membership.role,
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Use `requireOrg()`
|
|
514
|
+
|
|
515
|
+
`requireOrg()` is a lightweight middleware that confirms the SDK instance is configured with valid org credentials before continuing.
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
app.use(zentry.requireOrg());
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
In the current version it does not perform a remote org verification request by itself.
|
|
522
|
+
|
|
523
|
+
## End-to-End Flow
|
|
524
|
+
|
|
525
|
+
### Browser flow
|
|
526
|
+
|
|
527
|
+
1. frontend renders inside `ZentryProvider`
|
|
528
|
+
2. user clicks `login()` or `register()`
|
|
529
|
+
3. user is redirected to the Zentry UI
|
|
530
|
+
4. after success, Zentry redirects back to the app callback URL with a token
|
|
531
|
+
5. callback page stores that token in `localStorage`
|
|
532
|
+
6. the provider calls Zentry to fetch the full session in `ZentrySessionType` shape
|
|
533
|
+
7. React code uses `useZentry()` to read auth state
|
|
534
|
+
|
|
535
|
+
### Backend flow
|
|
536
|
+
|
|
537
|
+
1. frontend sends `Authorization: Bearer <token>` to the developer API
|
|
538
|
+
2. Express route uses `zentry.requireUser()`
|
|
539
|
+
3. the SDK sends a request to Zentry with:
|
|
540
|
+
- the user token in `Authorization`
|
|
541
|
+
- the org ID header
|
|
542
|
+
- the org API key header
|
|
543
|
+
4. Zentry validates:
|
|
544
|
+
- organization identity
|
|
545
|
+
- API key
|
|
546
|
+
- user session token
|
|
547
|
+
- organization membership
|
|
548
|
+
5. Zentry returns the normalized session payload
|
|
549
|
+
6. the SDK attaches the payload to `req.zentry`
|
|
550
|
+
7. the route handler uses `req.zentry`
|
|
551
|
+
|
|
552
|
+
## Headers Used Internally
|
|
553
|
+
|
|
554
|
+
The SDK uses these shared header constants:
|
|
555
|
+
|
|
556
|
+
- `X-Zentry-Org-ID`
|
|
557
|
+
- `X-Zentry-API-Key`
|
|
558
|
+
|
|
559
|
+
Frontend apps usually only send the organization header to Zentry directly.
|
|
560
|
+
|
|
561
|
+
Backend apps send:
|
|
562
|
+
|
|
563
|
+
- `Authorization: Bearer <user_token>`
|
|
564
|
+
- `X-Zentry-Org-ID`
|
|
565
|
+
- `X-Zentry-API-Key`
|
|
566
|
+
|
|
567
|
+
## Summary
|
|
568
|
+
|
|
569
|
+
Use:
|
|
570
|
+
|
|
571
|
+
- `@zentry/sdk/react` in the UI
|
|
572
|
+
- `@zentry/sdk/react-server` for server-side React helpers
|
|
573
|
+
- `@zentry/sdk/node` in the backend API
|
|
574
|
+
|
|
575
|
+
The UI owns login and token capture.
|
|
576
|
+
|
|
577
|
+
The backend owns secure user validation against Zentry.
|
|
578
|
+
|
|
579
|
+
Both consume the same `ZentrySessionType`, which keeps frontend and backend auth handling aligned.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
import{b as t,d as s,f as n,g as i}from"./chunk-SCUKQ3VA.js";import c from"axios";async function f(e){try{let r={[s]:e.env.ZENTRY_ORG_ID};e.token&&(r.Authorization=`Bearer ${e.token}`),e.cookie&&(r.Cookie=e.cookie);let a=await c.get(`${t}/auth/org/me`,{headers:r}),o=n(i).safeParse(a.data);if(!o.success)throw console.error("Invalid session data received from server:",o.error),new Error("Invalid session data received from Zentry server.");return o.data.data}catch(r){return console.error({error:r,message:"Failed to get session"}),null}}export{f as a};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
var p="token",m="http://localhost:5000/api/v1",l="http://localhost:3000",u="X-Zentry-Org-ID",d="X-Zentry-API-Key";import{z as e}from"zod";var t=e.string().min(1),n=e.enum(["CREDENTIAL","OAUTH"]),r=e.enum(["LOCAL","GOOGLE"]),s=e.enum(["ADMIN","MEMBER"]),i=e.unknown(),a=e.object({id:e.uuid(),email:e.email(),firstName:e.string(),lastName:e.string(),emailVerified:e.boolean(),imageUrl:e.string().nullable(),createdAt:t,updatedAt:t}),c={status_code:e.number().int().nonnegative(),message:e.string()},h=o=>e.object({success:e.literal(!0),...c,data:o}),x=e.object({user:a,org:e.object({id:e.uuid(),name:e.string()}),membership:e.object({id:e.uuid(),role:s,isBanned:e.boolean(),permissions:i.nullable()}),account:e.object({id:e.uuid(),provider:r,providerType:n,accountId:e.string(),providerAvatarUrl:e.string().nullable()})});export{p as a,m as b,l as c,u as d,d as e,h as f,x as g};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
"use strict";var R=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var v=(r,e)=>{for(var s in e)a(r,s,{get:e[s],enumerable:!0})},d=(r,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of A(e))!_.call(r,n)&&n!==s&&a(r,n,{get:()=>e[n],enumerable:!(o=x(e,n))||o.enumerable});return r};var Z=(r,e,s)=>(s=r!=null?R(I(r)):{},d(e||!r||!r.__esModule?a(s,"default",{value:r,enumerable:!0}):s,r)),q=r=>d(a({},"__esModule",{value:!0}),r);var H={};v(H,{ZentryClient:()=>p,extractBearerToken:()=>E});module.exports=q(H);var c=Z(require("axios"),1);var l="http://localhost:5000/api/v1";var y="X-Zentry-Org-ID",g="X-Zentry-API-Key";var t=require("zod"),h=t.z.string().min(1),T=t.z.enum(["CREDENTIAL","OAUTH"]),O=t.z.enum(["LOCAL","GOOGLE"]),b=t.z.enum(["ADMIN","MEMBER"]),w=t.z.unknown(),k=t.z.object({id:t.z.uuid(),email:t.z.email(),firstName:t.z.string(),lastName:t.z.string(),emailVerified:t.z.boolean(),imageUrl:t.z.string().nullable(),createdAt:h,updatedAt:h}),N={status_code:t.z.number().int().nonnegative(),message:t.z.string()},S=r=>t.z.object({success:t.z.literal(!0),...N,data:r}),f=t.z.object({user:k,org:t.z.object({id:t.z.uuid(),name:t.z.string()}),membership:t.z.object({id:t.z.uuid(),role:b,isBanned:t.z.boolean(),permissions:w.nullable()}),account:t.z.object({id:t.z.uuid(),provider:O,providerType:T,accountId:t.z.string(),providerAvatarUrl:t.z.string().nullable()})});var D=S(f),u=r=>typeof r=="string"&&r.trim().length>0,E=r=>{let e=r.header("authorization")?.trim();if(!e)return null;let[s,o]=e.split(/\s+/,2);return s!=="Bearer"||!o?null:o.trim()},i=(r,e,s)=>{r.status(e).json({success:!1,status_code:e,message:s,data:null})},p=class{orgId;apiKey;constructor(e){if(!u(e.orgId))throw new Error("ZentryClient requires a non-empty orgId.");if(!u(e.apiKey))throw new Error("ZentryClient requires a non-empty apiKey.");this.orgId=e.orgId.trim(),this.apiKey=e.apiKey.trim()}createRequestHeaders(e){return{[y]:this.orgId,[g]:this.apiKey,Authorization:`Bearer ${e}`}}async verifyUserToken(e){if(!u(e))throw new Error("A non-empty user token is required.");let s=await c.default.get(`${l}/auth/org/server/me`,{headers:this.createRequestHeaders(e.trim())}),o=D.safeParse(s.data);if(!o.success)throw new Error("Invalid session payload received from Zentry.");return o.data.data}async getSessionFromRequest(e){let s=E(e);if(!s)throw new Error("Authentication token is missing. Provide a Bearer token.");return this.verifyUserToken(s)}requireUser(){return async(e,s,o)=>{try{e.zentry=await this.getSessionFromRequest(e),o()}catch(n){if(n instanceof c.AxiosError){let m=n.response?.status??502;if(m===401||m===403){i(s,401,"Unauthorized user session.");return}i(s,502,"Failed to validate the user session with Zentry.");return}if(n instanceof Error){if(n.message.includes("Authentication token is missing")){i(s,401,n.message);return}if(n.message.includes("Invalid session payload")){i(s,502,n.message);return}}o(n)}}}requireOrg(){return(e,s,o)=>{if(!this.orgId||!this.apiKey){i(s,500,"Zentry client is not configured correctly.");return}o()}}};0&&(module.exports={ZentryClient,extractBearerToken});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Z as ZentrySessionType } from '../zod-DbKYqexO.cjs';
|
|
2
|
+
import { RequestHandler, Request } from 'express';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
namespace Express {
|
|
7
|
+
interface Request {
|
|
8
|
+
zentry?: ZentrySessionType;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ZentryClientOptions {
|
|
14
|
+
orgId: string;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
}
|
|
17
|
+
declare const extractBearerToken: (req: Request) => string | null;
|
|
18
|
+
/**
|
|
19
|
+
* @description This class is used to validate the user session with Zentry.
|
|
20
|
+
* @param options {ZentryClientOptions} - The options for the Zentry client.
|
|
21
|
+
* @param options.orgId {string} - The organization ID.
|
|
22
|
+
* @param options.apiKey {string} - The API key.
|
|
23
|
+
* @returns {ZentryClient} - The Zentry client instance.
|
|
24
|
+
* @throws {Error} - If the orgId or apiKey is not provided or is empty.
|
|
25
|
+
* */
|
|
26
|
+
declare class ZentryClient {
|
|
27
|
+
readonly orgId: string;
|
|
28
|
+
readonly apiKey: string;
|
|
29
|
+
constructor(options: ZentryClientOptions);
|
|
30
|
+
private createRequestHeaders;
|
|
31
|
+
private verifyUserToken;
|
|
32
|
+
private getSessionFromRequest;
|
|
33
|
+
requireUser(): RequestHandler;
|
|
34
|
+
requireOrg(): RequestHandler;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { ZentryClient, type ZentryClientOptions, extractBearerToken };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Z as ZentrySessionType } from '../zod-DbKYqexO.js';
|
|
2
|
+
import { RequestHandler, Request } from 'express';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
namespace Express {
|
|
7
|
+
interface Request {
|
|
8
|
+
zentry?: ZentrySessionType;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ZentryClientOptions {
|
|
14
|
+
orgId: string;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
}
|
|
17
|
+
declare const extractBearerToken: (req: Request) => string | null;
|
|
18
|
+
/**
|
|
19
|
+
* @description This class is used to validate the user session with Zentry.
|
|
20
|
+
* @param options {ZentryClientOptions} - The options for the Zentry client.
|
|
21
|
+
* @param options.orgId {string} - The organization ID.
|
|
22
|
+
* @param options.apiKey {string} - The API key.
|
|
23
|
+
* @returns {ZentryClient} - The Zentry client instance.
|
|
24
|
+
* @throws {Error} - If the orgId or apiKey is not provided or is empty.
|
|
25
|
+
* */
|
|
26
|
+
declare class ZentryClient {
|
|
27
|
+
readonly orgId: string;
|
|
28
|
+
readonly apiKey: string;
|
|
29
|
+
constructor(options: ZentryClientOptions);
|
|
30
|
+
private createRequestHeaders;
|
|
31
|
+
private verifyUserToken;
|
|
32
|
+
private getSessionFromRequest;
|
|
33
|
+
requireUser(): RequestHandler;
|
|
34
|
+
requireOrg(): RequestHandler;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { ZentryClient, type ZentryClientOptions, extractBearerToken };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
import{b as u,d as c,e as p,f as y,g as d}from"../chunk-SCUKQ3VA.js";import l,{AxiosError as g}from"axios";var f=y(d),o=n=>typeof n=="string"&&n.trim().length>0,h=n=>{let e=n.header("authorization")?.trim();if(!e)return null;let[r,t]=e.split(/\s+/,2);return r!=="Bearer"||!t?null:t.trim()},i=(n,e,r)=>{n.status(e).json({success:!1,status_code:e,message:r,data:null})},m=class{orgId;apiKey;constructor(e){if(!o(e.orgId))throw new Error("ZentryClient requires a non-empty orgId.");if(!o(e.apiKey))throw new Error("ZentryClient requires a non-empty apiKey.");this.orgId=e.orgId.trim(),this.apiKey=e.apiKey.trim()}createRequestHeaders(e){return{[c]:this.orgId,[p]:this.apiKey,Authorization:`Bearer ${e}`}}async verifyUserToken(e){if(!o(e))throw new Error("A non-empty user token is required.");let r=await l.get(`${u}/auth/org/server/me`,{headers:this.createRequestHeaders(e.trim())}),t=f.safeParse(r.data);if(!t.success)throw new Error("Invalid session payload received from Zentry.");return t.data.data}async getSessionFromRequest(e){let r=h(e);if(!r)throw new Error("Authentication token is missing. Provide a Bearer token.");return this.verifyUserToken(r)}requireUser(){return async(e,r,t)=>{try{e.zentry=await this.getSessionFromRequest(e),t()}catch(s){if(s instanceof g){let a=s.response?.status??502;if(a===401||a===403){i(r,401,"Unauthorized user session.");return}i(r,502,"Failed to validate the user session with Zentry.");return}if(s instanceof Error){if(s.message.includes("Authentication token is missing")){i(r,401,s.message);return}if(s.message.includes("Invalid session payload")){i(r,502,s.message);return}}t(s)}}}requireOrg(){return(e,r,t)=>{if(!this.orgId||!this.apiKey){i(r,500,"Zentry client is not configured correctly.");return}t()}}};export{m as ZentryClient,h as extractBearerToken};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
"use strict";var B=Object.create;var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var G=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var $=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},_=(e,t,n,c)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of U(t))!Y.call(e,r)&&r!==n&&m(e,r,{get:()=>t[r],enumerable:!(c=D(t,r))||c.enumerable});return e};var A=(e,t,n)=>(n=e!=null?B(G(e)):{},_(t||!e||!e.__esModule?m(n,"default",{value:e,enumerable:!0}):n,e)),z=e=>_(m({},"__esModule",{value:!0}),e);var ne={};$(ne,{Authenticated:()=>ee,LoginButton:()=>Q,LogoutButton:()=>W,RegisterButton:()=>J,UnAuthenticated:()=>te,ZentryProvider:()=>X,getServerSession:()=>oe,useZentry:()=>l,useZentryCallbackSync:()=>q});module.exports=z(ne);var s=require("react"),R=A(require("axios"),1);var u="token",d="http://localhost:5000/api/v1",S="http://localhost:3000",p="X-Zentry-Org-ID";var o=require("zod"),Z=o.z.string().min(1),K=o.z.enum(["CREDENTIAL","OAUTH"]),j=o.z.enum(["LOCAL","GOOGLE"]),H=o.z.enum(["ADMIN","MEMBER"]),M=o.z.unknown(),F=o.z.object({id:o.z.uuid(),email:o.z.email(),firstName:o.z.string(),lastName:o.z.string(),emailVerified:o.z.boolean(),imageUrl:o.z.string().nullable(),createdAt:Z,updatedAt:Z}),V={status_code:o.z.number().int().nonnegative(),message:o.z.string()},g=e=>o.z.object({success:o.z.literal(!0),...V,data:e}),f=o.z.object({user:F,org:o.z.object({id:o.z.uuid(),name:o.z.string()}),membership:o.z.object({id:o.z.uuid(),role:H,isBanned:o.z.boolean(),permissions:M.nullable()}),account:o.z.object({id:o.z.uuid(),provider:j,providerType:K,accountId:o.z.string(),providerAvatarUrl:o.z.string().nullable()})});var k=require("react/jsx-runtime"),v=()=>{if(typeof window>"u")return null;let e=localStorage.getItem(u);return typeof e!="string"?(console.error("No active token found or token is not a string"),null):e},x=e=>{typeof window>"u"||localStorage.removeItem(e)},w=(0,s.createContext)(void 0);function X({children:e,env:t}){let[n,c]=(0,s.useState)(null),[r,y]=(0,s.useState)(!1),[T,E]=(0,s.useState)(!0),P=async()=>{let i=v();if(!i){E(!1),console.log("No active token found, skipping session sync");return}try{let O=await R.default.get(`${d}/auth/org/me`,{headers:{[p]:t.ZENTRY_ORG_ID,Authorization:`Bearer ${i}`}}),h=g(f).safeParse(O.data);if(!h.success)throw console.error("Invalid session data received from server:",h.error),new Error("Invalid session data received from Zentry server.");c(h.data.data),y(!0)}catch{x(u),c(null),y(!1)}finally{E(!1)}};(0,s.useEffect)(()=>{P().then(()=>{console.log("Session synced")}).catch(i=>{console.error("Error syncing session:",i)})},[]);let N=()=>{window.location.href=`${S}/org/register?callbackUrl=${encodeURIComponent(t.ZENTRY_APP_CALLBACK_URL)}`},L=()=>{window.location.href=`${S}/org/login?callbackUrl=${encodeURIComponent(t.ZENTRY_APP_CALLBACK_URL)}`},b=async()=>{try{let i=v();if(!i){console.error("No active token found, skipping logout");return}await R.default.post(`${d}/auth/org/logout`,{},{headers:{[p]:t.ZENTRY_ORG_ID,Authorization:`Bearer ${i}`}}),x(u),c(null),y(!1),window.location.reload()}catch(i){console.error("Error logging out:",i)}},C=()=>v();return(0,k.jsx)(w.Provider,{value:{isAuthenticated:r,isLoading:T,session:n,login:L,logout:b,register:N,getSessionToken:C},children:e})}function l(){let e=(0,s.useContext)(w);if(!e)throw new Error("useZentry must be nested within a ZentryProvider");return e}function q(){(0,s.useEffect)(()=>{if(typeof window>"u")return;let t=new URLSearchParams(window.location.search).get("token");if(t){localStorage.setItem(u,t);let n=window.location.pathname+window.location.hash;window.history.replaceState({},document.title,n),window.location.reload()}},[])}var de=require("react");var a=require("react/jsx-runtime"),J=({className:e="",label:t="Register"})=>{let{register:n}=l();return(0,a.jsx)("button",{onClick:n,className:e,children:t})};function Q({className:e="",label:t="Login"}){let{login:n}=l();return(0,a.jsx)("button",{onClick:n,className:e,children:t})}function W({className:e="",label:t="LogOut"}){let{logout:n}=l();return(0,a.jsx)("button",{onClick:async()=>{await n()},className:e,children:t})}var ee=({children:e})=>{let{isAuthenticated:t}=l();return t?(0,a.jsx)(a.Fragment,{children:e}):null},te=({children:e})=>{let{isAuthenticated:t}=l();return t?null:(0,a.jsx)(a.Fragment,{children:e})};var I=A(require("axios"),1);async function oe(e){try{let t={[p]:e.env.ZENTRY_ORG_ID};e.token&&(t.Authorization=`Bearer ${e.token}`),e.cookie&&(t.Cookie=e.cookie);let n=await I.default.get(`${d}/auth/org/me`,{headers:t}),r=g(f).safeParse(n.data);if(!r.success)throw console.error("Invalid session data received from server:",r.error),new Error("Invalid session data received from Zentry server.");return r.data.data}catch(t){return console.error({error:t,message:"Failed to get session"}),null}}0&&(module.exports={Authenticated,LoginButton,LogoutButton,RegisterButton,UnAuthenticated,ZentryProvider,getServerSession,useZentry,useZentryCallbackSync});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default, { ReactNode } from 'react';
|
|
3
|
+
import { C as ClientEnv } from '../server-CZ-Exumw.cjs';
|
|
4
|
+
export { G as GetServerSessionOptions, g as getServerSession } from '../server-CZ-Exumw.cjs';
|
|
5
|
+
import { Z as ZentrySessionType } from '../zod-DbKYqexO.cjs';
|
|
6
|
+
import 'zod';
|
|
7
|
+
|
|
8
|
+
interface ZentryContextType {
|
|
9
|
+
isAuthenticated: boolean;
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
session: ZentrySessionType | null;
|
|
12
|
+
register: () => void;
|
|
13
|
+
login: () => void;
|
|
14
|
+
logout: () => Promise<void>;
|
|
15
|
+
getSessionToken: () => string | null;
|
|
16
|
+
}
|
|
17
|
+
interface ZentryProviderProps {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
env: Pick<ClientEnv, 'ZENTRY_ORG_ID' | 'ZENTRY_APP_CALLBACK_URL'>;
|
|
20
|
+
}
|
|
21
|
+
declare function ZentryProvider({ children, env }: ZentryProviderProps): React.JSX.Element;
|
|
22
|
+
declare function useZentry(): ZentryContextType;
|
|
23
|
+
/**
|
|
24
|
+
* Automatically captures, stores, and purges the token from the URL params.
|
|
25
|
+
*/
|
|
26
|
+
declare function useZentryCallbackSync(): void;
|
|
27
|
+
|
|
28
|
+
interface ButtonProps {
|
|
29
|
+
className?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @description Register Button
|
|
34
|
+
* @returns A button component
|
|
35
|
+
* @param className - The class name of the button
|
|
36
|
+
* @param label - The label of the button
|
|
37
|
+
* */
|
|
38
|
+
declare const RegisterButton: ({ className, label }: ButtonProps) => React__default.JSX.Element;
|
|
39
|
+
/**
|
|
40
|
+
* @description Login Button
|
|
41
|
+
* @returns A button component
|
|
42
|
+
* @param className - The class name of the button
|
|
43
|
+
* @param label - The label of the button
|
|
44
|
+
* */
|
|
45
|
+
declare function LoginButton({ className, label }: ButtonProps): React__default.JSX.Element;
|
|
46
|
+
/**
|
|
47
|
+
* @description Logout Button
|
|
48
|
+
* @returns A button component
|
|
49
|
+
* @param className - The class name of the button
|
|
50
|
+
* @param label - The label of the button
|
|
51
|
+
* */
|
|
52
|
+
declare function LogoutButton({ className, label }: ButtonProps): React__default.JSX.Element;
|
|
53
|
+
/**
|
|
54
|
+
* @description Authenticated Component
|
|
55
|
+
* @returns A component that renders its children if the user is authenticated
|
|
56
|
+
* @param children - The children to render if the user is authenticated
|
|
57
|
+
* */
|
|
58
|
+
declare const Authenticated: ({ children }: {
|
|
59
|
+
children: React__default.ReactNode;
|
|
60
|
+
}) => React__default.JSX.Element | null;
|
|
61
|
+
/**
|
|
62
|
+
* @description UnAuthenticated Component
|
|
63
|
+
* @returns A component that renders its children if the user is not authenticated
|
|
64
|
+
* @param children - The children to render if the user is not authenticated
|
|
65
|
+
* */
|
|
66
|
+
declare const UnAuthenticated: ({ children }: {
|
|
67
|
+
children: React__default.ReactNode;
|
|
68
|
+
}) => React__default.JSX.Element | null;
|
|
69
|
+
|
|
70
|
+
export { Authenticated, LoginButton, LogoutButton, RegisterButton, UnAuthenticated, ZentryProvider, type ZentryProviderProps, ZentrySessionType, useZentry, useZentryCallbackSync };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default, { ReactNode } from 'react';
|
|
3
|
+
import { C as ClientEnv } from '../server-OYDWuirO.js';
|
|
4
|
+
export { G as GetServerSessionOptions, g as getServerSession } from '../server-OYDWuirO.js';
|
|
5
|
+
import { Z as ZentrySessionType } from '../zod-DbKYqexO.js';
|
|
6
|
+
import 'zod';
|
|
7
|
+
|
|
8
|
+
interface ZentryContextType {
|
|
9
|
+
isAuthenticated: boolean;
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
session: ZentrySessionType | null;
|
|
12
|
+
register: () => void;
|
|
13
|
+
login: () => void;
|
|
14
|
+
logout: () => Promise<void>;
|
|
15
|
+
getSessionToken: () => string | null;
|
|
16
|
+
}
|
|
17
|
+
interface ZentryProviderProps {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
env: Pick<ClientEnv, 'ZENTRY_ORG_ID' | 'ZENTRY_APP_CALLBACK_URL'>;
|
|
20
|
+
}
|
|
21
|
+
declare function ZentryProvider({ children, env }: ZentryProviderProps): React.JSX.Element;
|
|
22
|
+
declare function useZentry(): ZentryContextType;
|
|
23
|
+
/**
|
|
24
|
+
* Automatically captures, stores, and purges the token from the URL params.
|
|
25
|
+
*/
|
|
26
|
+
declare function useZentryCallbackSync(): void;
|
|
27
|
+
|
|
28
|
+
interface ButtonProps {
|
|
29
|
+
className?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @description Register Button
|
|
34
|
+
* @returns A button component
|
|
35
|
+
* @param className - The class name of the button
|
|
36
|
+
* @param label - The label of the button
|
|
37
|
+
* */
|
|
38
|
+
declare const RegisterButton: ({ className, label }: ButtonProps) => React__default.JSX.Element;
|
|
39
|
+
/**
|
|
40
|
+
* @description Login Button
|
|
41
|
+
* @returns A button component
|
|
42
|
+
* @param className - The class name of the button
|
|
43
|
+
* @param label - The label of the button
|
|
44
|
+
* */
|
|
45
|
+
declare function LoginButton({ className, label }: ButtonProps): React__default.JSX.Element;
|
|
46
|
+
/**
|
|
47
|
+
* @description Logout Button
|
|
48
|
+
* @returns A button component
|
|
49
|
+
* @param className - The class name of the button
|
|
50
|
+
* @param label - The label of the button
|
|
51
|
+
* */
|
|
52
|
+
declare function LogoutButton({ className, label }: ButtonProps): React__default.JSX.Element;
|
|
53
|
+
/**
|
|
54
|
+
* @description Authenticated Component
|
|
55
|
+
* @returns A component that renders its children if the user is authenticated
|
|
56
|
+
* @param children - The children to render if the user is authenticated
|
|
57
|
+
* */
|
|
58
|
+
declare const Authenticated: ({ children }: {
|
|
59
|
+
children: React__default.ReactNode;
|
|
60
|
+
}) => React__default.JSX.Element | null;
|
|
61
|
+
/**
|
|
62
|
+
* @description UnAuthenticated Component
|
|
63
|
+
* @returns A component that renders its children if the user is not authenticated
|
|
64
|
+
* @param children - The children to render if the user is not authenticated
|
|
65
|
+
* */
|
|
66
|
+
declare const UnAuthenticated: ({ children }: {
|
|
67
|
+
children: React__default.ReactNode;
|
|
68
|
+
}) => React__default.JSX.Element | null;
|
|
69
|
+
|
|
70
|
+
export { Authenticated, LoginButton, LogoutButton, RegisterButton, UnAuthenticated, ZentryProvider, type ZentryProviderProps, ZentrySessionType, useZentry, useZentryCallbackSync };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
import{a as b}from"../chunk-OMDRZCFK.js";import{a as s,b as u,c as d,d as f,f as m,g as h}from"../chunk-SCUKQ3VA.js";import{createContext as x,useContext as T,useState as p,useEffect as v}from"react";import w from"axios";import{jsx as I}from"react/jsx-runtime";var g=()=>{if(typeof window>"u")return null;let e=localStorage.getItem(s);return typeof e!="string"?(console.error("No active token found or token is not a string"),null):e},R=e=>{typeof window>"u"||localStorage.removeItem(e)},S=x(void 0);function D({children:e,env:t}){let[o,a]=p(null),[A,c]=p(!1),[P,y]=p(!0),_=async()=>{let n=g();if(!n){y(!1),console.log("No active token found, skipping session sync");return}try{let N=await w.get(`${u}/auth/org/me`,{headers:{[f]:t.ZENTRY_ORG_ID,Authorization:`Bearer ${n}`}}),l=m(h).safeParse(N.data);if(!l.success)throw console.error("Invalid session data received from server:",l.error),new Error("Invalid session data received from Zentry server.");a(l.data.data),c(!0)}catch{R(s),a(null),c(!1)}finally{y(!1)}};v(()=>{_().then(()=>{console.log("Session synced")}).catch(n=>{console.error("Error syncing session:",n)})},[]);let k=()=>{window.location.href=`${d}/org/register?callbackUrl=${encodeURIComponent(t.ZENTRY_APP_CALLBACK_URL)}`},C=()=>{window.location.href=`${d}/org/login?callbackUrl=${encodeURIComponent(t.ZENTRY_APP_CALLBACK_URL)}`},E=async()=>{try{let n=g();if(!n){console.error("No active token found, skipping logout");return}await w.post(`${u}/auth/org/logout`,{},{headers:{[f]:t.ZENTRY_ORG_ID,Authorization:`Bearer ${n}`}}),R(s),a(null),c(!1),window.location.reload()}catch(n){console.error("Error logging out:",n)}},L=()=>g();return I(S.Provider,{value:{isAuthenticated:A,isLoading:P,session:o,login:C,logout:E,register:k,getSessionToken:L},children:e})}function r(){let e=T(S);if(!e)throw new Error("useZentry must be nested within a ZentryProvider");return e}function G(){v(()=>{if(typeof window>"u")return;let t=new URLSearchParams(window.location.search).get("token");if(t){localStorage.setItem(s,t);let o=window.location.pathname+window.location.hash;window.history.replaceState({},document.title,o),window.location.reload()}},[])}import"react";import{Fragment as Z,jsx as i}from"react/jsx-runtime";var J=({className:e="",label:t="Register"})=>{let{register:o}=r();return i("button",{onClick:o,className:e,children:t})};function M({className:e="",label:t="Login"}){let{login:o}=r();return i("button",{onClick:o,className:e,children:t})}function Q({className:e="",label:t="LogOut"}){let{logout:o}=r();return i("button",{onClick:async()=>{await o()},className:e,children:t})}var V=({children:e})=>{let{isAuthenticated:t}=r();return t?i(Z,{children:e}):null},W=({children:e})=>{let{isAuthenticated:t}=r();return t?null:i(Z,{children:e})};export{V as Authenticated,M as LoginButton,Q as LogoutButton,J as RegisterButton,W as UnAuthenticated,D as ZentryProvider,b as getServerSession,r as useZentry,G as useZentryCallbackSync};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Zentry Engine Core Pipeline Output
|
|
2
|
+
"use strict";var S=Object.create;var s=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var h=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var y=(t,r)=>{for(var o in r)s(t,o,{get:r[o],enumerable:!0})},a=(t,r,o,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of v(r))!E.call(t,n)&&n!==o&&s(t,n,{get:()=>r[n],enumerable:!(i=g(r,n))||i.enumerable});return t};var _=(t,r,o)=>(o=t!=null?S(h(t)):{},a(r||!t||!t.__esModule?s(o,"default",{value:t,enumerable:!0}):o,t)),x=t=>a(s({},"__esModule",{value:!0}),t);var b={};y(b,{getServerSession:()=>T});module.exports=x(b);var u=_(require("axios"),1);var c="http://localhost:5000/api/v1";var m="X-Zentry-Org-ID";var e=require("zod"),p=e.z.string().min(1),A=e.z.enum(["CREDENTIAL","OAUTH"]),R=e.z.enum(["LOCAL","GOOGLE"]),f=e.z.enum(["ADMIN","MEMBER"]),I=e.z.unknown(),O=e.z.object({id:e.z.uuid(),email:e.z.email(),firstName:e.z.string(),lastName:e.z.string(),emailVerified:e.z.boolean(),imageUrl:e.z.string().nullable(),createdAt:p,updatedAt:p}),D={status_code:e.z.number().int().nonnegative(),message:e.z.string()},l=t=>e.z.object({success:e.z.literal(!0),...D,data:t}),d=e.z.object({user:O,org:e.z.object({id:e.z.uuid(),name:e.z.string()}),membership:e.z.object({id:e.z.uuid(),role:f,isBanned:e.z.boolean(),permissions:I.nullable()}),account:e.z.object({id:e.z.uuid(),provider:R,providerType:A,accountId:e.z.string(),providerAvatarUrl:e.z.string().nullable()})});async function T(t){try{let r={[m]:t.env.ZENTRY_ORG_ID};t.token&&(r.Authorization=`Bearer ${t.token}`),t.cookie&&(r.Cookie=t.cookie);let o=await u.default.get(`${c}/auth/org/me`,{headers:r}),n=l(d).safeParse(o.data);if(!n.success)throw console.error("Invalid session data received from server:",n.error),new Error("Invalid session data received from Zentry server.");return n.data.data}catch(r){return console.error({error:r,message:"Failed to get session"}),null}}0&&(module.exports={getServerSession});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Z as ZentrySessionType } from './zod-DbKYqexO.cjs';
|
|
3
|
+
|
|
4
|
+
declare const ClientEnvSchema: z.ZodObject<{
|
|
5
|
+
ZENTRY_ORG_ID: z.ZodString;
|
|
6
|
+
ZENTRY_APP_CALLBACK_URL: z.ZodString;
|
|
7
|
+
ZENTRY_API_BASE_URL: z.ZodOptional<z.ZodString>;
|
|
8
|
+
ZENTRY_UI_BASE_URL: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type ClientEnv = z.infer<typeof ClientEnvSchema>;
|
|
11
|
+
|
|
12
|
+
interface GetServerSessionOptions {
|
|
13
|
+
env: Pick<ClientEnv, 'ZENTRY_ORG_ID'>;
|
|
14
|
+
token?: string;
|
|
15
|
+
cookie?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @description This function is used to get the session
|
|
19
|
+
* @returns {Promise<ZentrySessionType | null>} The session or null if not found.
|
|
20
|
+
* @throws {Error} If the session is not found or if there is an error.
|
|
21
|
+
* @remarks
|
|
22
|
+
* Server-side code cannot read browser `localStorage`, so the caller must forward either:
|
|
23
|
+
* - the user's Bearer token, or
|
|
24
|
+
* - the incoming `Cookie` header
|
|
25
|
+
*
|
|
26
|
+
* This function uses `X-Zentry-Org-ID` as public org context and validates the user session
|
|
27
|
+
* through the forwarded Bearer token or cookie.
|
|
28
|
+
*
|
|
29
|
+
* @example TanStack Start client hook passing the token into a server function:
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import { createServerFn } from '@tanstack/react-start';
|
|
32
|
+
* import { getServerSession } from '@zentry/sdk/react/server';
|
|
33
|
+
* import { useZentry } from '@zentry/sdk/react';
|
|
34
|
+
*
|
|
35
|
+
* export const getCurrentSession = createServerFn({ method: 'POST' })
|
|
36
|
+
* .validator((token: string) => token)
|
|
37
|
+
* .handler(async ({ data }) => {
|
|
38
|
+
* return getServerSession({
|
|
39
|
+
* env: {
|
|
40
|
+
* ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
41
|
+
* },
|
|
42
|
+
* token: data,
|
|
43
|
+
* });
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* export function SessionGate() {
|
|
47
|
+
* const { getSessionToken } = useZentry();
|
|
48
|
+
*
|
|
49
|
+
* async function handleLoadSession() {
|
|
50
|
+
* const token = getSessionToken();
|
|
51
|
+
* if (!token) return null;
|
|
52
|
+
*
|
|
53
|
+
* return getCurrentSession({ data: token });
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* return <button onClick={handleLoadSession}>Load session</button>;
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
* @example Next.js Server Component using cookies:
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { cookies } from 'next/headers';
|
|
62
|
+
* import { getServerSession } from '@zentry/sdk/react/server';
|
|
63
|
+
*
|
|
64
|
+
* async function fetchSession() {
|
|
65
|
+
* const cookieStore = await cookies();
|
|
66
|
+
* const session = await getServerSession({
|
|
67
|
+
* env: {
|
|
68
|
+
* ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
69
|
+
* },
|
|
70
|
+
* cookie: cookieStore.toString(),
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* if (!session) {
|
|
74
|
+
* return <div>No session found</div>;
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* return (
|
|
78
|
+
* <div>
|
|
79
|
+
* <h1>Welcome, {session.user.firstName}!</h1>
|
|
80
|
+
* </div>
|
|
81
|
+
* );
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
* @example Server function using a Bearer token:
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { getServerSession } from '@zentry/sdk/react/server';
|
|
87
|
+
*
|
|
88
|
+
* export async function loadUserSession(token: string) {
|
|
89
|
+
* return getServerSession({
|
|
90
|
+
* env: {
|
|
91
|
+
* ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
92
|
+
* },
|
|
93
|
+
* token,
|
|
94
|
+
* });
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
* */
|
|
98
|
+
declare function getServerSession(options: GetServerSessionOptions): Promise<ZentrySessionType | null>;
|
|
99
|
+
|
|
100
|
+
export { type ClientEnv as C, type GetServerSessionOptions as G, getServerSession as g };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Z as ZentrySessionType } from './zod-DbKYqexO.js';
|
|
3
|
+
|
|
4
|
+
declare const ClientEnvSchema: z.ZodObject<{
|
|
5
|
+
ZENTRY_ORG_ID: z.ZodString;
|
|
6
|
+
ZENTRY_APP_CALLBACK_URL: z.ZodString;
|
|
7
|
+
ZENTRY_API_BASE_URL: z.ZodOptional<z.ZodString>;
|
|
8
|
+
ZENTRY_UI_BASE_URL: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type ClientEnv = z.infer<typeof ClientEnvSchema>;
|
|
11
|
+
|
|
12
|
+
interface GetServerSessionOptions {
|
|
13
|
+
env: Pick<ClientEnv, 'ZENTRY_ORG_ID'>;
|
|
14
|
+
token?: string;
|
|
15
|
+
cookie?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @description This function is used to get the session
|
|
19
|
+
* @returns {Promise<ZentrySessionType | null>} The session or null if not found.
|
|
20
|
+
* @throws {Error} If the session is not found or if there is an error.
|
|
21
|
+
* @remarks
|
|
22
|
+
* Server-side code cannot read browser `localStorage`, so the caller must forward either:
|
|
23
|
+
* - the user's Bearer token, or
|
|
24
|
+
* - the incoming `Cookie` header
|
|
25
|
+
*
|
|
26
|
+
* This function uses `X-Zentry-Org-ID` as public org context and validates the user session
|
|
27
|
+
* through the forwarded Bearer token or cookie.
|
|
28
|
+
*
|
|
29
|
+
* @example TanStack Start client hook passing the token into a server function:
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import { createServerFn } from '@tanstack/react-start';
|
|
32
|
+
* import { getServerSession } from '@zentry/sdk/react/server';
|
|
33
|
+
* import { useZentry } from '@zentry/sdk/react';
|
|
34
|
+
*
|
|
35
|
+
* export const getCurrentSession = createServerFn({ method: 'POST' })
|
|
36
|
+
* .validator((token: string) => token)
|
|
37
|
+
* .handler(async ({ data }) => {
|
|
38
|
+
* return getServerSession({
|
|
39
|
+
* env: {
|
|
40
|
+
* ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
41
|
+
* },
|
|
42
|
+
* token: data,
|
|
43
|
+
* });
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* export function SessionGate() {
|
|
47
|
+
* const { getSessionToken } = useZentry();
|
|
48
|
+
*
|
|
49
|
+
* async function handleLoadSession() {
|
|
50
|
+
* const token = getSessionToken();
|
|
51
|
+
* if (!token) return null;
|
|
52
|
+
*
|
|
53
|
+
* return getCurrentSession({ data: token });
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* return <button onClick={handleLoadSession}>Load session</button>;
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
* @example Next.js Server Component using cookies:
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { cookies } from 'next/headers';
|
|
62
|
+
* import { getServerSession } from '@zentry/sdk/react/server';
|
|
63
|
+
*
|
|
64
|
+
* async function fetchSession() {
|
|
65
|
+
* const cookieStore = await cookies();
|
|
66
|
+
* const session = await getServerSession({
|
|
67
|
+
* env: {
|
|
68
|
+
* ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
69
|
+
* },
|
|
70
|
+
* cookie: cookieStore.toString(),
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* if (!session) {
|
|
74
|
+
* return <div>No session found</div>;
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* return (
|
|
78
|
+
* <div>
|
|
79
|
+
* <h1>Welcome, {session.user.firstName}!</h1>
|
|
80
|
+
* </div>
|
|
81
|
+
* );
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
* @example Server function using a Bearer token:
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { getServerSession } from '@zentry/sdk/react/server';
|
|
87
|
+
*
|
|
88
|
+
* export async function loadUserSession(token: string) {
|
|
89
|
+
* return getServerSession({
|
|
90
|
+
* env: {
|
|
91
|
+
* ZENTRY_ORG_ID: process.env.ZENTRY_ORG_ID!,
|
|
92
|
+
* },
|
|
93
|
+
* token,
|
|
94
|
+
* });
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
* */
|
|
98
|
+
declare function getServerSession(options: GetServerSessionOptions): Promise<ZentrySessionType | null>;
|
|
99
|
+
|
|
100
|
+
export { type ClientEnv as C, type GetServerSessionOptions as G, getServerSession as g };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const ZentrySessionSchema: z.ZodObject<{
|
|
4
|
+
user: z.ZodObject<{
|
|
5
|
+
id: z.ZodUUID;
|
|
6
|
+
email: z.ZodEmail;
|
|
7
|
+
firstName: z.ZodString;
|
|
8
|
+
lastName: z.ZodString;
|
|
9
|
+
emailVerified: z.ZodBoolean;
|
|
10
|
+
imageUrl: z.ZodNullable<z.ZodString>;
|
|
11
|
+
createdAt: z.ZodString;
|
|
12
|
+
updatedAt: z.ZodString;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
org: z.ZodObject<{
|
|
15
|
+
id: z.ZodUUID;
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
membership: z.ZodObject<{
|
|
19
|
+
id: z.ZodUUID;
|
|
20
|
+
role: z.ZodEnum<{
|
|
21
|
+
ADMIN: "ADMIN";
|
|
22
|
+
MEMBER: "MEMBER";
|
|
23
|
+
}>;
|
|
24
|
+
isBanned: z.ZodBoolean;
|
|
25
|
+
permissions: z.ZodNullable<z.ZodUnknown>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
account: z.ZodObject<{
|
|
28
|
+
id: z.ZodUUID;
|
|
29
|
+
provider: z.ZodEnum<{
|
|
30
|
+
LOCAL: "LOCAL";
|
|
31
|
+
GOOGLE: "GOOGLE";
|
|
32
|
+
}>;
|
|
33
|
+
providerType: z.ZodEnum<{
|
|
34
|
+
CREDENTIAL: "CREDENTIAL";
|
|
35
|
+
OAUTH: "OAUTH";
|
|
36
|
+
}>;
|
|
37
|
+
accountId: z.ZodString;
|
|
38
|
+
providerAvatarUrl: z.ZodNullable<z.ZodString>;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
type ZentrySessionType = z.infer<typeof ZentrySessionSchema>;
|
|
42
|
+
|
|
43
|
+
export type { ZentrySessionType as Z };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const ZentrySessionSchema: z.ZodObject<{
|
|
4
|
+
user: z.ZodObject<{
|
|
5
|
+
id: z.ZodUUID;
|
|
6
|
+
email: z.ZodEmail;
|
|
7
|
+
firstName: z.ZodString;
|
|
8
|
+
lastName: z.ZodString;
|
|
9
|
+
emailVerified: z.ZodBoolean;
|
|
10
|
+
imageUrl: z.ZodNullable<z.ZodString>;
|
|
11
|
+
createdAt: z.ZodString;
|
|
12
|
+
updatedAt: z.ZodString;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
org: z.ZodObject<{
|
|
15
|
+
id: z.ZodUUID;
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
membership: z.ZodObject<{
|
|
19
|
+
id: z.ZodUUID;
|
|
20
|
+
role: z.ZodEnum<{
|
|
21
|
+
ADMIN: "ADMIN";
|
|
22
|
+
MEMBER: "MEMBER";
|
|
23
|
+
}>;
|
|
24
|
+
isBanned: z.ZodBoolean;
|
|
25
|
+
permissions: z.ZodNullable<z.ZodUnknown>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
account: z.ZodObject<{
|
|
28
|
+
id: z.ZodUUID;
|
|
29
|
+
provider: z.ZodEnum<{
|
|
30
|
+
LOCAL: "LOCAL";
|
|
31
|
+
GOOGLE: "GOOGLE";
|
|
32
|
+
}>;
|
|
33
|
+
providerType: z.ZodEnum<{
|
|
34
|
+
CREDENTIAL: "CREDENTIAL";
|
|
35
|
+
OAUTH: "OAUTH";
|
|
36
|
+
}>;
|
|
37
|
+
accountId: z.ZodString;
|
|
38
|
+
providerAvatarUrl: z.ZodNullable<z.ZodString>;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
type ZentrySessionType = z.infer<typeof ZentrySessionSchema>;
|
|
42
|
+
|
|
43
|
+
export type { ZentrySessionType as Z };
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zentry-org/sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"author": "Kavinda Rathnayake",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/kavinda-100/zentry"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/kavinda-100/zentry/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/kavinda-100/zentry#readme",
|
|
18
|
+
"exports": {
|
|
19
|
+
"./react": {
|
|
20
|
+
"types": "./dist/react/index.d.ts",
|
|
21
|
+
"import": "./dist/react/index.js",
|
|
22
|
+
"require": "./dist/react/index.cjs"
|
|
23
|
+
},
|
|
24
|
+
"./react-server": {
|
|
25
|
+
"types": "./dist/react/server.d.ts",
|
|
26
|
+
"import": "./dist/react/server.js",
|
|
27
|
+
"require": "./dist/react/server.cjs"
|
|
28
|
+
},
|
|
29
|
+
"./node": {
|
|
30
|
+
"types": "./dist/node/index.d.ts",
|
|
31
|
+
"import": "./dist/node/index.js",
|
|
32
|
+
"require": "./dist/node/index.cjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsup"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"express": "^4.19.0 || ^5.0.0",
|
|
40
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"axios": "^1.18.0",
|
|
44
|
+
"react-dom": "^19.2.7",
|
|
45
|
+
"tsup": "^8.5.1",
|
|
46
|
+
"zod": "^4.4.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/express": "^5.0.6",
|
|
50
|
+
"@types/node": "^26.0.0",
|
|
51
|
+
"@types/react": "^19.2.17",
|
|
52
|
+
"typescript": "^6.0.3"
|
|
53
|
+
}
|
|
54
|
+
}
|