Skip to content

Commit

Permalink
feat(sdk): add demo app for development (#671)
Browse files Browse the repository at this point in the history
* feat: create a new nextjs app

* chore: remove generated files

* feat: add auth provider

* feat: add frontier provider

* feat: add login and signup page

* feat: add proxy to frontier server

* feat: redirect to home is user is authorized

* feat: add callback page

* feat: add org list and sdk page

* fix: build issues

* feat: add docker file for sdk demo app

* chore: update pnpm-lock file

* feat: add sdk-demo service in docker-compose
  • Loading branch information
rsbh authored Jul 16, 2024
1 parent e035579 commit 82de892
Show file tree
Hide file tree
Showing 21 changed files with 6,080 additions and 7,005 deletions.
32 changes: 19 additions & 13 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ services:
ports:
- "5432:5432"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U frontier" ]
test: ["CMD-SHELL", "pg_isready -U frontier"]
interval: 30s
timeout: 30s
retries: 3
Expand All @@ -28,7 +28,7 @@ services:
ports:
- "5431:5432"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U spicedb" ]
test: ["CMD-SHELL", "pg_isready -U spicedb"]
interval: 30s
timeout: 30s
retries: 3
Expand Down Expand Up @@ -72,14 +72,13 @@ services:
- FRONTIER_SPICEDB_PRE_SHARED_KEY=frontier
- FRONTIER_APP_RESOURCES_CONFIG_PATH=file:///opt
- FRONTIER_UI_PORT=8083
# - FRONTIER_APP_MAILER_SMTP_HOST=sandbox.smtp.mailtrap.io
# - FRONTIER_APP_MAILER_SMTP_PORT=2525
# - FRONTIER_APP_MAILER_SMTP_USERNAME=
# - FRONTIER_APP_MAILER_SMTP_PASSWORD=
# - FRONTIER_APP_MAILER_SMTP_INSECURE=false
# - FRONTIER_APP_MAILER_SMTP_TLS_POLICY=mandatory # possible values are "mandatory", "opportunistic", or "none"
# - [email protected]

# - FRONTIER_APP_MAILER_SMTP_HOST=sandbox.smtp.mailtrap.io
# - FRONTIER_APP_MAILER_SMTP_PORT=2525
# - FRONTIER_APP_MAILER_SMTP_USERNAME=
# - FRONTIER_APP_MAILER_SMTP_PASSWORD=
# - FRONTIER_APP_MAILER_SMTP_INSECURE=false
# - FRONTIER_APP_MAILER_SMTP_TLS_POLICY=mandatory # possible values are "mandatory", "opportunistic", or "none"
# - [email protected]

spicedb-migration:
image: quay.io/authzed/spicedb:v1.29.2
Expand All @@ -94,12 +93,19 @@ services:
ports:
- "7443:8443"
- "50051:50051"
command:
serve --grpc-preshared-key "frontier" --datastore-engine postgres
command: serve --grpc-preshared-key "frontier" --datastore-engine postgres
--datastore-conn-uri postgres://spicedb:@pg2:5432/spicedb?sslmode=disable --http-enabled=true
restart: on-failure
depends_on:
pg2:
condition: service_healthy
spicedb-migration:
condition: service_completed_successfully
condition: service_completed_successfully

sdk:
build:
context: ./sdks/js/packages/sdk-demo
ports:
- "3000:3000"
depends_on:
- frontier
3 changes: 3 additions & 0 deletions sdks/js/packages/sdk-demo/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules

.env
4 changes: 4 additions & 0 deletions sdks/js/packages/sdk-demo/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.next
.nuxt
node_modules
dist
7 changes: 7 additions & 0 deletions sdks/js/packages/sdk-demo/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
root: true,
extends: ['@raystack/eslint-config'],
rules: {
'turbo/no-undeclared-env-vars': 'off'
}
};
36 changes: 36 additions & 0 deletions sdks/js/packages/sdk-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
9 changes: 9 additions & 0 deletions sdks/js/packages/sdk-demo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM node:20-alpine as builder
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
ENV PORT 3000
CMD npm start
36 changes: 36 additions & 0 deletions sdks/js/packages/sdk-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
16 changes: 16 additions & 0 deletions sdks/js/packages/sdk-demo/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/** @type {import('next').NextConfig} */

const baseUrl = process.env.FRONTIER_ENDPOINT || 'http://frontier:8080'

const nextConfig = {
rewrites: async () => {
return [
{
source: '/api/:path*',
destination: `${baseUrl}/:path*`
}
]
}
};

export default nextConfig;
24 changes: 24 additions & 0 deletions sdks/js/packages/sdk-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "sdk-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@raystack/apsara": "^0.16.1",
"@raystack/frontier": "^0.22.0",
"next": "14.2.5",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5"
}
}
17 changes: 17 additions & 0 deletions sdks/js/packages/sdk-demo/src/app/[orgId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';
import { Window, OrganizationProfile } from '@raystack/frontier/react';

export default function OrgPage({ params }: { params: { orgId: string } }) {
const orgId = params.orgId;

return orgId ? (
<Window open={true} onOpenChange={() => {}}>
<OrganizationProfile
organizationId={orgId}
showBilling={true}
showTokens={true}
showPreferences={true}
/>
</Window>
) : null;
}
55 changes: 55 additions & 0 deletions sdks/js/packages/sdk-demo/src/app/callback/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client';

import { useEffect, useCallback, Suspense } from 'react';
import { useFrontier } from '@raystack/frontier/react';
import { Flex } from '@raystack/apsara';
import { redirect, useSearchParams } from 'next/navigation';
import useAuthRedirect from '@/hooks/useAuthRedirect';

function Callback() {
const { client } = useFrontier();

const searchParams = useSearchParams();

const callFrontierCallback = useCallback(async () => {
const state = searchParams.get('state');
const code = searchParams.get('code');

try {
if (state && code) {
const resp = await client?.frontierServiceAuthCallback({ state, code });
if (resp?.status === 200) {
redirect('/');
} else {
throw new Error('Auth callback failed');
}
}
} catch (err) {
redirect('/login');
}
}, [client, searchParams]);

useEffect(() => {
callFrontierCallback();
}, [callFrontierCallback]);

return (
<Flex
justify="center"
align="center"
style={{ height: '100vh', width: '100vw' }}
>
Loading...
</Flex>
);
}

export default function Page() {
useAuthRedirect();

return (
<Suspense>
<Callback />
</Suspense>
);
}
26 changes: 26 additions & 0 deletions sdks/js/packages/sdk-demo/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import config from '@/config/frontier';
import AuthContextProvider from '@/contexts/auth/provider';
import { FrontierProvider } from '@raystack/frontier/react';
import type { Metadata } from 'next';
import React from 'react';

export const metadata: Metadata = {
title: 'Frontier SDK',
description: 'Frontier SDK'
};

export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<FrontierProvider config={config}>
<AuthContextProvider>{children}</AuthContextProvider>
</FrontierProvider>
</body>
</html>
);
}
18 changes: 18 additions & 0 deletions sdks/js/packages/sdk-demo/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';

import useAuthRedirect from '@/hooks/useAuthRedirect';
import { Flex } from '@raystack/apsara';
import { SignIn } from '@raystack/frontier/react';

export default function LoginRoute() {
useAuthRedirect();
return (
<Flex
justify="center"
align="center"
style={{ height: '100vh', width: '100vw' }}
>
<SignIn />
</Flex>
);
}
43 changes: 43 additions & 0 deletions sdks/js/packages/sdk-demo/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client';
import AuthContext from '@/contexts/auth';
import { Flex } from '@raystack/apsara';
import { useFrontier } from '@raystack/frontier/react';
import Link from 'next/link';
import { redirect } from 'next/navigation';
import { useContext, useEffect } from 'react';

export default function Home() {
const { isAuthorized } = useContext(AuthContext);
const { organizations } = useFrontier();
useEffect(() => {
if (!isAuthorized) {
redirect('/login');
}
}, [isAuthorized]);

return (
<main>
<Flex
justify="center"
align="center"
style={{ height: '100vh', width: '100vw' }}
>
<Flex direction="column">
{organizations.map(org => (
<Flex
key={org.id}
style={{
padding: '16px',
border: '1px solid var(--border-base)',
width: '100%',
margin: '8px'
}}
>
<Link href={`/${org.id}`}>{org.title}</Link>
</Flex>
))}
</Flex>
</Flex>
</main>
);
}
18 changes: 18 additions & 0 deletions sdks/js/packages/sdk-demo/src/app/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';
import useAuthRedirect from '@/hooks/useAuthRedirect';
import { Flex } from '@raystack/apsara';
import { SignUp } from '@raystack/frontier/react';

export default function SignUpRoute() {
useAuthRedirect();

return (
<Flex
justify="center"
align="center"
style={{ height: '100vh', width: '100vw' }}
>
<SignUp />
</Flex>
);
}
5 changes: 5 additions & 0 deletions sdks/js/packages/sdk-demo/src/config/frontier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const config = {
endpoint: '/api'
};

export default config;
Loading

0 comments on commit 82de892

Please sign in to comment.