Skip to content

Commit

Permalink
chore(common): restructure starters and update root readme
Browse files Browse the repository at this point in the history
  • Loading branch information
eunjae-lee committed Jan 31, 2024
1 parent 54abb31 commit f1feb23
Show file tree
Hide file tree
Showing 114 changed files with 191 additions and 214 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ This repository is a collection of starters to help developers quickly start bui
## Introduction
Inside each project you will find a detailed README.md file that will provide instructions on how to clone and run the code. Here is a short list of all projects inside of this repository:

- [Story starter](story-starter/README.md)
- [Tool Next.js Starter](tool-nextjs-starter/README.md)
- Space Plugins
- [Nuxt Starter](space-plugins/nuxt-starter/README.md)
- [Story Starter](space-plugins/story-starter/README.md)
- Tool Plugins
- [Next.js Starter](tool-plugins/nextjs-starter/README.md)

## Glossary

Expand Down
88 changes: 0 additions & 88 deletions space-plugin-nuxt-base/server/utils/getAppSession.ts

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `space-plugin-nuxt-base` layer
# Space Plugin `nuxt-base` layer

This Nuxt layer adds basic authentication flow to your existing Storyblok's Space Plugin app.

Expand All @@ -8,7 +8,12 @@ In your `nuxt.config.ts`,

```js
export default defineNuxtConfig({
extends: ['github:storyblok/space-tool-plugins/space-plugin-nuxt-base'],
extends: [
[
'github:storyblok/space-tool-plugins/space-plugins/nuxt-base',
{ install: true },
],
],
});
```

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
121 changes: 121 additions & 0 deletions space-plugins/nuxt-base/server/utils/getAppSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {
isAppSessionQuery,
sessionCookieStore,
} from '@storyblok/app-extension-auth';

import type { H3Event } from 'h3';

type AppSessionQuery = {
spaceId: number;
userId: number;
};

// Overall auth flow
// (1) https://app.storyblok.com/v1/spaces/xxxx/app_provisions/xxxx
// (2) https://<USER-DOMAIN>/?space_id=xxxx&space_is_trial=false&space_name=xxxx&user_id=xxxx&user_name=null&user_lang=en&user_is_admin=true
// (3) https://<USER-DOMAIN>/api/connect/storyblok
// OAuth Consent Page ↓
// (4) https://app.storyblok.com/oauth/authorize?client_id=xxxx&scope=read_content%20write_content&response_type=code&redirect_uri=https%3A%2F%2F<USER-DOMAIN>%2Fapi%2Fconnect%2Fcallback&code_challenge=xxxx&state=xxxx&code_challenge_method=S256
// (5) https://<USER-DOMAIN>/api/connect/callback?code=xxxx&space_id=183395
// The cookie `sb.auth` is not set at this time, so it redirects to ↓
// (6) https://<USER-DOMAIN>/401
// The middleware catches /401 and redirects to ↓
// (7) https://app.storyblok.com/oauth/app_redirect

// Now (2) ~ (5) repeats
// (8) https://<USER-DOMAIN>/?space_id=xxxx&space_is_trial=false&space_name=xxxx&user_id=xxxx&user_name=null&user_lang=en&user_is_admin=true
// (9) https://<USER-DOMAIN>/api/connect/storyblok
// (10) https://<USER-DOMAIN>/oauth/authorize?client_id=xxxx&scope=read_content%20write_content&response_type=code&redirect_uri=https%3A%2F%2F<USER-DOMAIN>%2Fapi%2Fconnect%2Fcallback&code_challenge=xxxx&state=xxxx&code_challenge_method=S256
// (11) https://<USER-DOMAIN>/api/connect/callback?code=xxxx&state=xxxx&space_id=xxxx

// Finished. Authenticated successfully.
// (12) https://<USER-DOMAIN>/?spaceId=xxxx&userId=xxxx

// If a user visits this plugin with the `sb.auth` token already set, they will be redirected to ↓
// (13) https://<USER-DOMAIN>/?space_id=xxxx&user_id=xxxx
// instead of spaceId and userId.
// It should be more consistent, but at least the `nuxt-base` layer takes care of it now.

export const getAppSession = async (event: H3Event) => {
const appSessionQuery = extractAppSessionQuery(event);
if (!isAppSessionQuery(appSessionQuery)) {
return;
}

const appConfig = useAppConfig();
const sessionStore = sessionCookieStore(getAuthHandlerParams(appConfig.auth))(
{
req: event.node.req,
res: event.node.res,
}
);

return await sessionStore.get(appSessionQuery);
};

function extractAppSessionQuery(event: H3Event): AppSessionQuery | undefined {
const appSession = event.context.appSession;
const query = getQuery(event);

if (appSession?.spaceId && appSession?.userId) {
// When a page is already authenticated on the server side,
// and it's rendering a page that includes `useFetch('...', { server: true })`,
// Nuxt directly runs the serverless function on the server side
// (without an actual HTTP request).
//
// In that case `event.context.appSession` exists.
return convertToAppSessionQuery(appSession?.spaceId, appSession?.userId);
}

// (12) if this is a page request (/?spaceId=xxx&userId=yyy)
if (query.spaceId && query.userId) {
return convertToAppSessionQuery(query.spaceId, query.userId);
}

// (13) if this is a page request (/?space_id=xxx&user_id=yyy)
if (query.space_id && query.user_id) {
return convertToAppSessionQuery(query.space_id, query.user_id);
}

const referer = getHeader(event, 'referer');
// if this is an API request (/api/xxx), the `referer` header exists.
if (referer) {
// `referer` can be one of the following:
// https://<USER-DOMAIN>/?spaceId=xxxx&userId=xxxx
// or
// https://<USER-DOMAIN>/?space_id=xxxx&user_id=xxxx
const refererParams = new URL(referer).searchParams;
if (refererParams.get('spaceId') && refererParams.get('userId')) {
return convertToAppSessionQuery(
refererParams.get('spaceId'),
refererParams.get('userId')
);
}

if (refererParams.get('space_id') && refererParams.get('user_id')) {
return convertToAppSessionQuery(
refererParams.get('space_id'),
refererParams.get('user_id')
);
}
}
}

function convertToAppSessionQuery(spaceId: any, userId: any): AppSessionQuery {
return {
spaceId: toNumber(spaceId),
userId: toNumber(userId),
};
}

const toNumber = (value: any) => {
if (typeof value === 'string') {
return parseInt(value, 10);
}
if (typeof value === 'number') {
return value;
}
throw new Error(
`Expected to be string or number. Actual value: ${JSON.stringify(value)}`
);
};
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This Nuxt starter is a Storyblok Space Plugin app that includes the basic authen
## Getting Started

```sh
npx giget@latest gh:storyblok/space-tool-plugins/space-plugin-nuxt-starter YOUR-PROJECT-NAME
npx giget@latest gh:storyblok/space-tool-plugins/space-plugins/nuxt-starter YOUR-PROJECT-NAME
```

This repository is developed using [pnpm](https://pnpm.io/). However, you can also use Yarn or NPM.
Expand Down Expand Up @@ -36,7 +36,7 @@ And then you can find the information.

<img src="./docs/oauth.png" alt="OAuth information" width="600" />

3. Configure the following environment variables in `<ROOT-OF-YOUR-PROJECT>/starters/nuxt/.env`.
3. Configure the following environment variables in `<ROOT-OF-YOUR-PROJECT>/.env`.

- `CLIENT_ID=`: Client Identifer
- `CLIENT_SECRET=`: Client Secret
Expand All @@ -58,10 +58,6 @@ Ensure that "Production" is the section that contains information about the prod

7. Open the `starters/nuxt/stories.config.ts` file and implement your own actions. You can refer to the existing sample implementation for guidance.

8. Deploying

The starter is set up as a monorepo, and most hosting platforms support it seamlessly. For instance, Vercel recognizes it as a Nuxt project and automatically configures the root directory for you.

<img src="./docs/deploy-subdir.png" alt="Vercel Deployment" width="600" />
8. Deployment

You should configure the same environment variables on the hosting platform as well.
File renamed without changes
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
extends: ['github:storyblok/space-tool-plugins/space-plugin-nuxt-base'],
extends: [
[
'github:storyblok/space-tool-plugins/space-plugins/nuxt-base',
{ install: true },
],
],
css: ['~/assets/css/base.css'],
modules: ['nuxt-lucide-icons', '@nuxtjs/google-fonts', '@nuxtjs/tailwindcss'],
googleFonts: {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions space-plugins/story-starter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.env
.env.*
!.env.example

.idea
**/node_modules
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ npx giget@latest gh:storyblok/space-tool-plugins/story-starter YOUR-PROJECT-NAME
```

To learn more about the configuration, read the [space-plugin-nuxt-starter's README](https://github.com/storyblok/space-tool-plugins/blob/main/space-plugin-nuxt-starter/README.md#configuration).

## Deployment

The Story Starter is set up as a monorepo, and most hosting platforms support it seamlessly. For instance, Vercel recognizes it as a Nuxt project and automatically configures the root directory for you.

<img src="./docs/deploy-subdir.png" alt="Vercel Deployment" width="600" />
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
"description": "",
"private": true,
"workspaces": [
"starters/*",
"packages/*"
"starters/*"
],
"scripts": {
"dev:nuxt": "pnpm -F nuxt dev"
Expand Down
Loading

0 comments on commit f1feb23

Please sign in to comment.