@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 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,3 @@
1
+ export { G as GetServerSessionOptions, g as getServerSession } from '../server-CZ-Exumw.cjs';
2
+ import '../zod-DbKYqexO.cjs';
3
+ import 'zod';
@@ -0,0 +1,3 @@
1
+ export { G as GetServerSessionOptions, g as getServerSession } from '../server-OYDWuirO.js';
2
+ import '../zod-DbKYqexO.js';
3
+ import 'zod';
@@ -0,0 +1,2 @@
1
+ // Zentry Engine Core Pipeline Output
2
+ import{a}from"../chunk-OMDRZCFK.js";import"../chunk-SCUKQ3VA.js";export{a as 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
+ }