diff --git a/packages/store-client/.env.development b/packages/store-client/.env.development
new file mode 100644
index 0000000..1ef76db
--- /dev/null
+++ b/packages/store-client/.env.development
@@ -0,0 +1,5 @@
+SITE_URL=https://store.coldsurf.io
+GOOGLE_OAUTH_CLIENT_ID=
+GOOGLE_OAUTH_CLIENT_SECRET=
+AUTH_SECRET=
+BASE_URL=http://localhost:8000/api/v1/
\ No newline at end of file
diff --git a/packages/store-client/.env.production b/packages/store-client/.env.production
new file mode 100644
index 0000000..1c455c1
--- /dev/null
+++ b/packages/store-client/.env.production
@@ -0,0 +1,5 @@
+SITE_URL=https://store.coldsurf.io
+GOOGLE_OAUTH_CLIENT_ID=
+GOOGLE_OAUTH_CLIENT_SECRET=
+AUTH_SECRET=
+BASE_URL=https://api.store.coldsurf.io/api/v1/
\ No newline at end of file
diff --git a/packages/store-client/.eslintrc b/packages/store-client/.eslintrc
new file mode 100644
index 0000000..ac72403
--- /dev/null
+++ b/packages/store-client/.eslintrc
@@ -0,0 +1,12 @@
+{
+ "extends": [
+ "coldsurfers", // for nodejs-typescript, or 'coldsurfers/nodejs-typescript'
+ "coldsurfers/react-typescript" // for react-typescript
+ ],
+ "plugins": ["@tanstack/query"],
+ "rules": {
+ "import/extensions": "off",
+ "import/no-unresolved": "off",
+ "no-undef": "off"
+ }
+}
\ No newline at end of file
diff --git a/packages/store-client/.gitignore b/packages/store-client/.gitignore
new file mode 100644
index 0000000..8d574ff
--- /dev/null
+++ b/packages/store-client/.gitignore
@@ -0,0 +1,38 @@
+# 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
+.env
+# .env.production
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/packages/store-client/.prettierrc.json b/packages/store-client/.prettierrc.json
new file mode 100644
index 0000000..fbe0e55
--- /dev/null
+++ b/packages/store-client/.prettierrc.json
@@ -0,0 +1,6 @@
+{
+ "trailingComma": "es5",
+ "tabWidth": 2,
+ "semi": false,
+ "singleQuote": true
+}
\ No newline at end of file
diff --git a/packages/store-client/README.md b/packages/store-client/README.md
new file mode 100644
index 0000000..bcf7c7a
--- /dev/null
+++ b/packages/store-client/README.md
@@ -0,0 +1,3 @@
+Hello, this repo was moved to `https://github.com/coldsurfers/store.coldsurf.io`.
+
+Thanks!
\ No newline at end of file
diff --git a/packages/store-client/app/api/auth/[...nextauth]/route.ts b/packages/store-client/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..28bc4dd
--- /dev/null
+++ b/packages/store-client/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,3 @@
+import { handlers } from '../../../../libs/auth'
+
+export const { GET, POST } = handlers
diff --git a/packages/store-client/app/favicon.ico b/packages/store-client/app/favicon.ico
new file mode 100644
index 0000000..718d6fe
Binary files /dev/null and b/packages/store-client/app/favicon.ico differ
diff --git a/packages/store-client/app/layout.tsx b/packages/store-client/app/layout.tsx
new file mode 100644
index 0000000..953c837
--- /dev/null
+++ b/packages/store-client/app/layout.tsx
@@ -0,0 +1,33 @@
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+import { ReactNode } from 'react'
+import LayoutWrapper from '@/components/LayoutWrapper'
+import { MODAL_PORTAL_ID } from '@/libs/constants'
+import { auth } from '@/libs/auth'
+import GlobalStyle from '@/components/GlobalStyle'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Store | ColdSurf',
+}
+
+export default async function RootLayout({
+ children,
+}: {
+ children: ReactNode
+}) {
+ const session = await auth()
+
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ )
+}
diff --git a/packages/store-client/app/page.tsx b/packages/store-client/app/page.tsx
new file mode 100644
index 0000000..20d0f19
--- /dev/null
+++ b/packages/store-client/app/page.tsx
@@ -0,0 +1,87 @@
+import { queryList } from '@coldsurfers/notion-utils'
+import {
+ PageObjectResponse,
+ // PartialPageObjectResponse,
+ // RichTextItemResponse,
+ // TextRichTextItemResponse,
+} from '@notionhq/client/build/src/api-endpoints'
+import Link from 'next/link'
+import { cache } from 'react'
+
+const getAllPosts = cache(
+ async () =>
+ // eslint-disable-next-line no-return-await
+ await queryList({
+ platform: 'store',
+ direction: 'descending',
+ timestamp: 'created_time',
+ })
+)
+
+// type A = PageObjectResponse
+
+export async function getInternalPosts(
+ options = {
+ status: 'Published',
+ }
+) {
+ const { status = 'Published' } = options
+ try {
+ const rawPosts = (await getAllPosts()) as PageObjectResponse[]
+ const posts = rawPosts.map((post) => {
+ const createdTime = new Date(post.created_time)
+ const lastEditedTime = new Date(post.last_edited_time)
+ const { properties } = post
+ const slugProperty = properties.Slug
+ const nameProperty = properties.Name
+ console.log(nameProperty)
+
+ let slug: string | undefined = ''
+ let title: string | undefined = ''
+
+ if (slugProperty.type === 'rich_text') {
+ slug = slugProperty.rich_text.at(0)?.plain_text
+ // console.log(slugProperty.rich_text.at(0)?.plain_text)
+ }
+ if (nameProperty.type === 'title') {
+ title = nameProperty.title.at(0)?.plain_text
+ // console.log(slugProperty.rich_text.at(0)?.plain_text)
+ }
+ // console.log(post.properties, slugProperty)
+
+ // const title = post.properties?.Name?.title
+ // console.log(title)
+ // const postStatus = post.properties.Status.status.name
+ return {
+ id: post.id,
+ createdTime,
+ lastEditedTime,
+ dateLocale: createdTime.toLocaleString('en-US', {
+ month: 'short',
+ day: '2-digit',
+ year: 'numeric',
+ }),
+ slug,
+ title,
+ // status: postStatus,
+ }
+ })
+
+ return posts
+
+ // return posts.filter((post) => post.status === status)
+ } catch (e) {
+ console.error(e)
+ return null
+ }
+}
+
+export default async function Home() {
+ const posts = await getInternalPosts()
+
+ return posts?.map((post) => (
+
+ {post.title}
+
+ ))
+}
diff --git a/packages/store-client/components/Button.tsx b/packages/store-client/components/Button.tsx
new file mode 100644
index 0000000..7356788
--- /dev/null
+++ b/packages/store-client/components/Button.tsx
@@ -0,0 +1,21 @@
+/* eslint-disable no-undef */
+import styled from '@emotion/styled'
+import { ButtonHTMLAttributes, DetailedHTMLProps } from 'react'
+
+export interface ButonProps
+ extends DetailedHTMLProps<
+ ButtonHTMLAttributes,
+ HTMLButtonElement
+ > {}
+
+const ButtonBase = styled.button`
+ border-radius: 14px;
+ padding: 0.5rem;
+ border: none;
+ font-size: 14px;
+ cursor: pointer;
+`
+
+export default function Button(props: ButonProps) {
+ return
+}
diff --git a/packages/store-client/components/Footer.tsx b/packages/store-client/components/Footer.tsx
new file mode 100644
index 0000000..4fc2f2e
--- /dev/null
+++ b/packages/store-client/components/Footer.tsx
@@ -0,0 +1,17 @@
+'use client'
+
+import styled from '@emotion/styled'
+
+const Container = styled.div`
+ width: 100%;
+ height: 15rem;
+ padding: 1rem;
+`
+
+export default function Footer() {
+ return (
+
+ © coldsurf
+
+ )
+}
diff --git a/packages/store-client/components/GlobalStyle.tsx b/packages/store-client/components/GlobalStyle.tsx
new file mode 100644
index 0000000..a794179
--- /dev/null
+++ b/packages/store-client/components/GlobalStyle.tsx
@@ -0,0 +1,7 @@
+'use client'
+
+import { GlobalStyle } from '@coldsurfers/ocean-road'
+
+export default function AppGlobalStyle() {
+ return
+}
diff --git a/packages/store-client/components/Header.tsx b/packages/store-client/components/Header.tsx
new file mode 100644
index 0000000..d09aa90
--- /dev/null
+++ b/packages/store-client/components/Header.tsx
@@ -0,0 +1,50 @@
+'use client'
+
+import styled from '@emotion/styled'
+import Link from 'next/link'
+import { signOut, useSession } from 'next-auth/react'
+import { useCallback } from 'react'
+import Button from './Button'
+import { useLoginModalStore } from './LoginModal'
+
+const Container = styled.div`
+ width: 100%;
+ padding: 1rem;
+ display: flex;
+ align-items: center;
+`
+
+const CompanyLogo = styled.h2`
+ font-weight: bold;
+`
+
+const LoginButtonWrapper = styled(Button)`
+ margin-left: auto;
+`
+
+export default function Header() {
+ const { open } = useLoginModalStore()
+ const { data: session } = useSession()
+ const isLoggedIn = !!session
+ const onClickLogout = useCallback(async () => {
+ await signOut()
+ }, [])
+ return (
+
+
+ ColdSurf Store
+
+ {isLoggedIn ? (
+ Log Out
+ ) : (
+ Log In
+ )}
+
+ )
+}
diff --git a/packages/store-client/components/Input.tsx b/packages/store-client/components/Input.tsx
new file mode 100644
index 0000000..e9a2cfb
--- /dev/null
+++ b/packages/store-client/components/Input.tsx
@@ -0,0 +1,14 @@
+/* eslint-disable no-undef */
+import { DetailedHTMLProps, InputHTMLAttributes, forwardRef } from 'react'
+
+export interface InputProps
+ extends DetailedHTMLProps<
+ InputHTMLAttributes,
+ HTMLInputElement
+ > {}
+
+const Input = forwardRef((props, ref) => (
+
+))
+
+export default Input
diff --git a/packages/store-client/components/LayoutWrapper.tsx b/packages/store-client/components/LayoutWrapper.tsx
new file mode 100644
index 0000000..24a4b1a
--- /dev/null
+++ b/packages/store-client/components/LayoutWrapper.tsx
@@ -0,0 +1,45 @@
+'use client'
+
+import { PropsWithChildren } from 'react'
+import styled from '@emotion/styled'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import { SessionProvider } from 'next-auth/react'
+import { Session } from 'next-auth/types'
+import Header from './Header'
+import Footer from './Footer'
+import LoginModal from './LoginModal'
+
+const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ max-width: 960px;
+ margin-left: auto;
+ margin-right: auto;
+`
+
+const ChildrenWrapper = styled.div`
+ flex: 1;
+`
+
+export const queryClient = new QueryClient({})
+
+export default async function LayoutWrapper({
+ children,
+ session,
+}: PropsWithChildren<{
+ session?: Session | null
+}>) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+
+ )
+}
diff --git a/packages/store-client/components/LoginModal.tsx b/packages/store-client/components/LoginModal.tsx
new file mode 100644
index 0000000..2d1001c
--- /dev/null
+++ b/packages/store-client/components/LoginModal.tsx
@@ -0,0 +1,71 @@
+/* eslint-disable no-undef */
+
+'use client'
+
+import styled from '@emotion/styled'
+import { create } from 'zustand'
+import { MouseEventHandler, useCallback, useRef } from 'react'
+import { signIn } from 'next-auth/react'
+import Modal from './Modal'
+import ModalPortal from '@/libs/ModalPortal'
+import Button from './Button'
+
+type LoginModalStore = {
+ isOpen: boolean
+ open: () => void
+ close: () => void
+}
+
+export const useLoginModalStore = create((set) => ({
+ isOpen: false,
+ open: () => set(() => ({ isOpen: true })),
+ close: () => set(() => ({ isOpen: false })),
+}))
+
+const CustomModal = styled(Modal.Container)`
+ width: 350px;
+ display: flex;
+ flex-direction: column;
+`
+
+const ModalTitle = styled.h2`
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ font-weight: bold;
+ font-size: 18px;
+`
+
+export default function LoginModal() {
+ const { isOpen, close } = useLoginModalStore()
+
+ const modalBackgroundRef = useRef(null)
+ const onClickBackground = useCallback>(
+ (e) => {
+ if (modalBackgroundRef.current?.isEqualNode(e.target as Node)) {
+ close()
+ }
+ },
+ []
+ )
+
+ const onClickGoogleLogin = useCallback(async () => {
+ await signIn('google')
+ }, [])
+
+ return (
+ isOpen && (
+
+
+
+ ColdSurf Store
+
+
+
+
+ )
+ )
+}
diff --git a/packages/store-client/components/Modal.tsx b/packages/store-client/components/Modal.tsx
new file mode 100644
index 0000000..76c1927
--- /dev/null
+++ b/packages/store-client/components/Modal.tsx
@@ -0,0 +1,47 @@
+/* eslint-disable no-undef */
+import styled from '@emotion/styled'
+import { MouseEventHandler, PropsWithChildren, forwardRef } from 'react'
+
+const ModalBackground = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 99;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`
+
+const ModalWrapper = styled.div`
+ border: 1px solid #ababab;
+ padding: 1rem;
+ border-radius: 12px;
+`
+
+const Modal = () => null
+
+Modal.Background = forwardRef<
+ HTMLDivElement,
+ PropsWithChildren<{
+ className?: string
+ onClickBackground?: MouseEventHandler
+ }>
+>((props, ref) => (
+
+ {props.children}
+
+))
+
+Modal.Container = (props: PropsWithChildren<{ className?: string }>) => (
+ {props.children}
+)
+
+export default Modal
diff --git a/packages/store-client/fetchers/fetchSignIn.ts b/packages/store-client/fetchers/fetchSignIn.ts
new file mode 100644
index 0000000..96f6e5d
--- /dev/null
+++ b/packages/store-client/fetchers/fetchSignIn.ts
@@ -0,0 +1,28 @@
+import { z } from 'zod'
+import { UserSchema } from '@/models/User'
+import axiosClient from '@/libs/axiosClient'
+
+const FetchSignInBodySchema = z.object({
+ social_token: z.string(),
+ provider: z.union([z.literal('google'), z.literal('facebook')]),
+})
+export type FetchSignInBodyType = z.infer
+
+const FetchSignInResponseSchema = z.object({
+ refresh_token: z.string(),
+ auth_token: z.string(),
+ user: UserSchema,
+})
+export type FetchSignInResponseType = z.infer
+
+const fetchSignIn = async (params: FetchSignInBodyType) => {
+ try {
+ const res = await axiosClient.post('/auth/social-signin', params)
+ return FetchSignInResponseSchema.parse(res.data)
+ } catch (e) {
+ console.error(e)
+ throw Error('fetchSignIn error')
+ }
+}
+
+export default fetchSignIn
diff --git a/packages/store-client/libs/ModalPortal.ts b/packages/store-client/libs/ModalPortal.ts
new file mode 100644
index 0000000..0ba502e
--- /dev/null
+++ b/packages/store-client/libs/ModalPortal.ts
@@ -0,0 +1,9 @@
+import { PropsWithChildren } from 'react'
+import { createPortal } from 'react-dom'
+import { MODAL_PORTAL_ID } from './constants'
+
+const ModalPortal = ({ children }: PropsWithChildren<{}>) =>
+ // eslint-disable-next-line no-undef
+ createPortal(children, document.getElementById(MODAL_PORTAL_ID)!)
+
+export default ModalPortal
diff --git a/packages/store-client/libs/auth.ts b/packages/store-client/libs/auth.ts
new file mode 100644
index 0000000..6adf450
--- /dev/null
+++ b/packages/store-client/libs/auth.ts
@@ -0,0 +1,168 @@
+import NextAuth from 'next-auth'
+
+// import Apple from "next-auth/providers/apple"
+// import Atlassian from "next-auth/providers/atlassian"
+// import Auth0 from "next-auth/providers/auth0"
+// import Authentik from "next-auth/providers/authentik"
+// import AzureAD from "next-auth/providers/azure-ad"
+// import AzureB2C from "next-auth/providers/azure-ad-b2c"
+// import Battlenet from "next-auth/providers/battlenet"
+// import Box from "next-auth/providers/box"
+// import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
+// import Bungie from "next-auth/providers/bungie"
+// import Cognito from "next-auth/providers/cognito"
+// import Coinbase from "next-auth/providers/coinbase"
+// import Discord from "next-auth/providers/discord"
+// import Dropbox from "next-auth/providers/dropbox"
+// import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
+// import Eveonline from "next-auth/providers/eveonline"
+// import Facebook from "next-auth/providers/facebook"
+// import Faceit from "next-auth/providers/faceit"
+// import FortyTwoSchool from "next-auth/providers/42-school"
+// import Foursquare from "next-auth/providers/foursquare"
+// import Freshbooks from "next-auth/providers/freshbooks"
+// import Fusionauth from "next-auth/providers/fusionauth"
+// import GitHub from 'next-auth/providers/github'
+// import Gitlab from "next-auth/providers/gitlab"
+import Google from 'next-auth/providers/google'
+// import Hubspot from "next-auth/providers/hubspot"
+// import Instagram from "next-auth/providers/instagram"
+// import Kakao from 'next-auth/providers/kakao'
+// import Keycloak from "next-auth/providers/keycloak"
+// import Line from "next-auth/providers/line"
+// import LinkedIn from "next-auth/providers/linkedin"
+// import Mailchimp from "next-auth/providers/mailchimp"
+// import Mailru from "next-auth/providers/mailru"
+// import Medium from "next-auth/providers/medium"
+// import Naver from "next-auth/providers/naver"
+// import Netlify from "next-auth/providers/netlify"
+// import Okta from "next-auth/providers/okta"
+// import Onelogin from "next-auth/providers/onelogin"
+// import Osso from "next-auth/providers/osso"
+// import Osu from "next-auth/providers/osu"
+// import Passage from "next-auth/providers/passage"
+// import Patreon from "next-auth/providers/patreon"
+// import Pinterest from "next-auth/providers/pinterest"
+// import Pipedrive from "next-auth/providers/pipedrive"
+// import Reddit from "next-auth/providers/reddit"
+// import Salesforce from "next-auth/providers/salesforce"
+// import Slack from "next-auth/providers/slack"
+// import Spotify from "next-auth/providers/spotify"
+// import Strava from "next-auth/providers/strava"
+// import Todoist from "next-auth/providers/todoist"
+// import Trakt from "next-auth/providers/trakt"
+// import Twitch from "next-auth/providers/twitch"
+// import Twitter from "next-auth/providers/twitter"
+// import UnitedEffects from "next-auth/providers/united-effects"
+// import Vk from "next-auth/providers/vk"
+// import Wikimedia from "next-auth/providers/wikimedia"
+// import Wordpress from "next-auth/providers/wordpress"
+// import WorkOS from "next-auth/providers/workos"
+// import Yandex from "next-auth/providers/yandex"
+// import Zitadel from "next-auth/providers/zitadel"
+// import Zoho from "next-auth/providers/zoho"
+// import Zoom from "next-auth/providers/zoom"
+
+import type { NextAuthConfig } from 'next-auth'
+import fetchSignIn from '@/fetchers/fetchSignIn'
+
+export const config = {
+ theme: {
+ logo: 'https://next-auth.js.org/img/logo/logo-sm.png',
+ },
+ secret: process.env.AUTH_SECRET,
+ providers: [
+ // Apple,
+ // Atlassian,
+ // Auth0,
+ // Authentik,
+ // AzureAD,
+ // AzureB2C,
+ // Battlenet,
+ // Box,
+ // BoxyHQSAML,
+ // Bungie,
+ // Cognito,
+ // Coinbase,
+ // Discord,
+ // Dropbox,
+ // DuendeIDS6,
+ // Eveonline,
+ // Facebook,
+ // Faceit,
+ // FortyTwoSchool,
+ // Foursquare,
+ // Freshbooks,
+ // Fusionauth,
+ // GitHub({
+ // clientId: process.env.GITHUB_ID ?? '',
+ // clientSecret: process.env.GITHUB_SECRET ?? '',
+ // }),
+ // Gitlab,
+ Google({
+ clientId: process.env.GOOGLE_OAUTH_CLIENT_ID ?? '',
+ clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET ?? '',
+ }),
+ // Hubspot,
+ // Instagram,
+ // Kakao,
+ // Keycloak,
+ // Line,
+ // LinkedIn,
+ // Mailchimp,
+ // Mailru,
+ // Medium,
+ // Naver,
+ // Netlify,
+ // Okta,
+ // Onelogin,
+ // Osso,
+ // Osu,
+ // Passage,
+ // Patreon,
+ // Pinterest,
+ // Pipedrive,
+ // Reddit,
+ // Salesforce,
+ // Slack,
+ // Spotify,
+ // Strava,
+ // Todoist,
+ // Trakt,
+ // Twitch,
+ // Twitter,
+ // UnitedEffects,
+ // Vk,
+ // Wikimedia,
+ // Wordpress,
+ // WorkOS,
+ // Yandex,
+ // Zitadel,
+ // Zoho,
+ // Zoom,
+ ],
+ callbacks: {
+ authorized({ request, auth }) {
+ const { pathname } = request.nextUrl
+ if (pathname === '/middleware-example') return !!auth
+ return true
+ },
+ async signIn(params) {
+ const { account } = params
+ if (!account) {
+ return false
+ }
+ const { access_token: accessToken, provider } = account
+ if (provider !== 'google' || !accessToken) {
+ return false
+ }
+ await fetchSignIn({
+ provider,
+ social_token: accessToken,
+ })
+ return true
+ },
+ },
+} satisfies NextAuthConfig
+
+export const { handlers, auth, signIn, signOut } = NextAuth(config)
diff --git a/packages/store-client/libs/axiosClient.ts b/packages/store-client/libs/axiosClient.ts
new file mode 100644
index 0000000..05b5c78
--- /dev/null
+++ b/packages/store-client/libs/axiosClient.ts
@@ -0,0 +1,9 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import Axios from 'axios'
+
+const axiosClient = Axios.create({
+ baseURL: process.env.BASE_URL,
+ timeout: 5000,
+})
+
+export default axiosClient
diff --git a/packages/store-client/libs/constants.ts b/packages/store-client/libs/constants.ts
new file mode 100644
index 0000000..d49c440
--- /dev/null
+++ b/packages/store-client/libs/constants.ts
@@ -0,0 +1 @@
+export const MODAL_PORTAL_ID = 'modal-portal-id'
diff --git a/packages/store-client/libs/palettes.ts b/packages/store-client/libs/palettes.ts
new file mode 100644
index 0000000..b372c84
--- /dev/null
+++ b/packages/store-client/libs/palettes.ts
@@ -0,0 +1,8 @@
+const palettes = {
+ borderPrimary: '#eaeaec',
+ white: '#ffffff',
+ background1: '#f5f5f7',
+ black: '#000000',
+}
+
+export default palettes
diff --git a/packages/store-client/models/User.ts b/packages/store-client/models/User.ts
new file mode 100644
index 0000000..8281d30
--- /dev/null
+++ b/packages/store-client/models/User.ts
@@ -0,0 +1,10 @@
+import { z } from 'zod'
+
+export const UserSchema = z.object({
+ id: z.string(),
+ email: z.string().email(),
+ password: z.string().nullable(),
+ created_at: z.string().datetime(),
+})
+
+export type UserType = z.infer
diff --git a/packages/store-client/mutations/useSignInMutation.ts b/packages/store-client/mutations/useSignInMutation.ts
new file mode 100644
index 0000000..c0a50fd
--- /dev/null
+++ b/packages/store-client/mutations/useSignInMutation.ts
@@ -0,0 +1,18 @@
+import { UseMutationOptions, useMutation } from '@tanstack/react-query'
+import fetchSignIn, {
+ FetchSignInBodyType,
+ FetchSignInResponseType,
+} from '@/fetchers/fetchSignIn'
+
+export default function useSignInMutation(
+ options?: UseMutationOptions<
+ FetchSignInResponseType,
+ Error,
+ FetchSignInBodyType
+ >
+) {
+ return useMutation({
+ mutationFn: fetchSignIn,
+ ...options,
+ })
+}
diff --git a/packages/store-client/next.config.js b/packages/store-client/next.config.js
new file mode 100644
index 0000000..e69d0e3
--- /dev/null
+++ b/packages/store-client/next.config.js
@@ -0,0 +1,5 @@
+/** @type {import('next').NextConfig} */
+
+const nextConfig = {}
+
+module.exports = nextConfig
diff --git a/packages/store-client/package.json b/packages/store-client/package.json
new file mode 100644
index 0000000..3a60ad7
--- /dev/null
+++ b/packages/store-client/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "client",
+ "version": "0.1.0",
+ "private": true,
+ "workspaces": {
+ "nohoist": [
+ "**"
+ ]
+ },
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@coldsurfers/ocean-road": "1.5.1-rc.4",
+ "@emotion/react": "^11.11.1",
+ "@emotion/styled": "^11.11.0",
+ "@react-oauth/google": "^0.12.1",
+ "@tanstack/react-query": "^5.12.2",
+ "axios": "^1.6.2",
+ "emotion-reset": "^3.0.1",
+ "next": "14.0.3",
+ "next-auth": "beta",
+ "react": "^18",
+ "react-dom": "^18",
+ "react-hook-form": "^7.48.2",
+ "zod": "^3.22.4",
+ "zustand": "^4.4.7"
+ },
+ "devDependencies": {
+ "@tanstack/eslint-plugin-query": "^5.12.1",
+ "@types/node": "^20",
+ "@types/react": "^18",
+ "@types/react-dom": "^18",
+ "typescript": "^5"
+ }
+}
diff --git a/packages/store-client/public/next.svg b/packages/store-client/public/next.svg
new file mode 100644
index 0000000..5174b28
--- /dev/null
+++ b/packages/store-client/public/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/store-client/public/vercel.svg b/packages/store-client/public/vercel.svg
new file mode 100644
index 0000000..d2f8422
--- /dev/null
+++ b/packages/store-client/public/vercel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/store-client/stores/authStore.ts b/packages/store-client/stores/authStore.ts
new file mode 100644
index 0000000..da576e6
--- /dev/null
+++ b/packages/store-client/stores/authStore.ts
@@ -0,0 +1,12 @@
+import { create } from 'zustand'
+
+export const useAuthStore = create<{
+ authToken?: string
+ refreshToken?: string
+ // eslint-disable-next-line no-unused-vars
+ login: (params: { authToken?: string; refreshToken?: string }) => void
+}>((set) => ({
+ authToken: undefined,
+ refreshToken: undefined,
+ login: (params) => set(params),
+}))
diff --git a/packages/store-client/stores/userStore.ts b/packages/store-client/stores/userStore.ts
new file mode 100644
index 0000000..0d32e10
--- /dev/null
+++ b/packages/store-client/stores/userStore.ts
@@ -0,0 +1,11 @@
+import { create } from 'zustand'
+import { UserType } from '@/models/User'
+
+export const useUserStore = create<{
+ user: UserType | null
+ // eslint-disable-next-line no-unused-vars
+ login: (user: UserType) => void
+}>((set) => ({
+ user: null,
+ login: (user) => set({ user }),
+}))
diff --git a/packages/store-client/tsconfig.json b/packages/store-client/tsconfig.json
new file mode 100644
index 0000000..c714696
--- /dev/null
+++ b/packages/store-client/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/packages/store-server/.env.example b/packages/store-server/.env.example
new file mode 100644
index 0000000..1acd3b2
--- /dev/null
+++ b/packages/store-server/.env.example
@@ -0,0 +1,7 @@
+# Environment variables declared in this file are automatically made available to Prisma.
+# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
+
+# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
+# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
+
+DATABASE_URL=""
\ No newline at end of file
diff --git a/packages/store-server/.eslintrc b/packages/store-server/.eslintrc
new file mode 100644
index 0000000..752bb5f
--- /dev/null
+++ b/packages/store-server/.eslintrc
@@ -0,0 +1,9 @@
+{
+ "extends": [
+ "coldsurfers", // for nodejs-typescript, or 'coldsurfers/nodejs-typescript'
+ "coldsurfers/react-typescript" // for react-typescript
+ ],
+ "rules": {
+ "camelcase": "off"
+ }
+}
\ No newline at end of file
diff --git a/packages/store-server/.gitignore b/packages/store-server/.gitignore
new file mode 100644
index 0000000..52e66d1
--- /dev/null
+++ b/packages/store-server/.gitignore
@@ -0,0 +1,11 @@
+node_modules
+# Keep environment variables out of version control
+.env
+
+src/config/config.json
+
+Dockerfile
+
+dist/
+
+docker-compose.yml
\ No newline at end of file
diff --git a/packages/store-server/.prettierrc.json b/packages/store-server/.prettierrc.json
new file mode 100644
index 0000000..fbe0e55
--- /dev/null
+++ b/packages/store-server/.prettierrc.json
@@ -0,0 +1,6 @@
+{
+ "trailingComma": "es5",
+ "tabWidth": 2,
+ "semi": false,
+ "singleQuote": true
+}
\ No newline at end of file
diff --git a/packages/store-server/Dockerfile.example b/packages/store-server/Dockerfile.example
new file mode 100644
index 0000000..823bc76
--- /dev/null
+++ b/packages/store-server/Dockerfile.example
@@ -0,0 +1,14 @@
+# https://umanking.github.io/2023/08/04/mysql-dockerfile/
+# Dockerfile
+
+# MySQL 이미지를 기반으로 이미지 생성
+FROM mysql:latest
+
+# MySQL 설정
+ENV MYSQL_ROOT_PASSWORD=my-secret-pw
+ENV MYSQL_DATABASE=mydb
+ENV MYSQL_USER=myuser
+ENV MYSQL_PASSWORD=mypassword
+
+# 포트 설정 (기본 MySQL 포트는 3306)
+EXPOSE 3306
\ No newline at end of file
diff --git a/packages/store-server/docker-compose.example.yml b/packages/store-server/docker-compose.example.yml
new file mode 100644
index 0000000..d9ce0c6
--- /dev/null
+++ b/packages/store-server/docker-compose.example.yml
@@ -0,0 +1,16 @@
+# https://wecandev.tistory.com/107
+
+version: '3'
+services:
+ mysql:
+ image: mysql:8.0
+ container_name: mysql
+ ports:
+ - 3306:3306 # HOST:CONTAINER
+ environment:
+ MYSQL_ROOT_PASSWORD: admin
+ command:
+ - --character-set-server=utf8mb4
+ - --collation-server=utf8mb4_unicode_ci
+ volumes:
+ - D:/mysql/data:/var/lib/mysql
\ No newline at end of file
diff --git a/packages/store-server/package.json b/packages/store-server/package.json
new file mode 100644
index 0000000..e052102
--- /dev/null
+++ b/packages/store-server/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "server",
+ "version": "1.0.0",
+ "license": "MIT",
+ "scripts": {
+ "dev": "NODE_ENV=development npx ts-node ./src/server.ts",
+ "start": "NODE_ENV=production node ./dist/server.js",
+ "build": "tsc && cp -R ./src/config ./dist/config",
+ "deploy": "yarn pm2 start ./src/config/ecosystem.config.js"
+ },
+ "devDependencies": {
+ "@types/nconf": "^0.10.6",
+ "@types/node": "^20",
+ "pm2": "^5.3.0",
+ "prisma": "^5.7.1",
+ "typescript": "^5"
+ },
+ "dependencies": {
+ "@fastify/autoload": "^5.8.0",
+ "@fastify/cors": "^8.4.2",
+ "@fastify/jwt": "^7.2.4",
+ "@prisma/client": "^5.7.1",
+ "fastify": "^4.24.3",
+ "google-auth-library": "^9.4.1",
+ "nconf": "^0.12.1",
+ "uuidv4": "^6.2.13",
+ "zod": "^3.22.4"
+ }
+}
diff --git a/packages/store-server/prisma/migrations/20231213115753_init/migration.sql b/packages/store-server/prisma/migrations/20231213115753_init/migration.sql
new file mode 100644
index 0000000..7672ec1
--- /dev/null
+++ b/packages/store-server/prisma/migrations/20231213115753_init/migration.sql
@@ -0,0 +1,29 @@
+-- CreateTable
+CREATE TABLE "User" (
+ "id" TEXT NOT NULL,
+ "email" TEXT NOT NULL,
+ "password" VARCHAR(255),
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+
+ CONSTRAINT "User_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "AuthToken" (
+ "id" TEXT NOT NULL,
+ "auth_token" TEXT NOT NULL,
+ "refresh_token" TEXT NOT NULL,
+ "user_id" TEXT NOT NULL,
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+
+ CONSTRAINT "AuthToken_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "AuthToken_user_id_key" ON "AuthToken"("user_id");
+
+-- AddForeignKey
+ALTER TABLE "AuthToken" ADD CONSTRAINT "AuthToken_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/packages/store-server/prisma/migrations/migration_lock.toml b/packages/store-server/prisma/migrations/migration_lock.toml
new file mode 100644
index 0000000..fbffa92
--- /dev/null
+++ b/packages/store-server/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (i.e. Git)
+provider = "postgresql"
\ No newline at end of file
diff --git a/packages/store-server/prisma/schema.prisma b/packages/store-server/prisma/schema.prisma
new file mode 100644
index 0000000..2b62cdd
--- /dev/null
+++ b/packages/store-server/prisma/schema.prisma
@@ -0,0 +1,28 @@
+// This is your Prisma schema file,
+// learn more about it in the docs: https://pris.ly/d/prisma-schema
+
+generator client {
+ provider = "prisma-client-js"
+}
+
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+model User {
+ id String @id @default(uuid())
+ email String @unique
+ password String? @db.VarChar(255)
+ created_at DateTime @default(now())
+ auth_token AuthToken?
+}
+
+model AuthToken {
+ id String @id @default(uuid())
+ auth_token String @db.Text
+ refresh_token String @db.Text
+ user User @relation(fields: [user_id], references: [id])
+ user_id String @unique
+ created_at DateTime @default(now())
+}
diff --git a/packages/store-server/src/api/controllers/authController.ts b/packages/store-server/src/api/controllers/authController.ts
new file mode 100644
index 0000000..9fa4298
--- /dev/null
+++ b/packages/store-server/src/api/controllers/authController.ts
@@ -0,0 +1,64 @@
+import { RouteHandler } from 'fastify'
+import { OAuth2Client } from 'google-auth-library'
+import User from '../models/User'
+import AuthToken from '../models/AuthToken'
+
+const client = new OAuth2Client()
+
+export const socialSignInCtrl: RouteHandler<{
+ Body: {
+ social_token: string
+ provider: 'google'
+ }
+}> = async (req, res) => {
+ const { social_token: socialToken, provider } = req.body
+ try {
+ if (provider === 'google') {
+ const tokenInfo = await client.getTokenInfo(socialToken)
+ const { email: gmail } = tokenInfo
+ if (!gmail) {
+ throw Error('cannot get gmail')
+ }
+ let user = await User.findByEmail(gmail)
+ if (!user) {
+ user = await new User({
+ email: gmail,
+ }).create()
+ }
+ const authToken = new AuthToken({
+ auth_token: await res.jwtSign(
+ {
+ provider,
+ email: user.email,
+ id: user.id,
+ },
+ {
+ expiresIn: '7d',
+ }
+ ),
+ refresh_token: await res.jwtSign(
+ {
+ provider,
+ email: user.email,
+ id: user.id,
+ },
+ {
+ expiresIn: '30d',
+ }
+ ),
+ user_id: user.id,
+ })
+ const { refresh_token, auth_token } = await authToken.create()
+
+ return res.status(200).send({
+ refresh_token,
+ auth_token,
+ user,
+ })
+ }
+ return res.status(404).send()
+ } catch (e) {
+ console.error(e)
+ return res.send(e)
+ }
+}
diff --git a/packages/store-server/src/api/controllers/meController.ts b/packages/store-server/src/api/controllers/meController.ts
new file mode 100644
index 0000000..4b75051
--- /dev/null
+++ b/packages/store-server/src/api/controllers/meController.ts
@@ -0,0 +1,14 @@
+import { FastifyError, RouteHandler } from 'fastify'
+// import { JWTDecoded } from '../../types/jwt'
+
+export const getMeCtrl: RouteHandler<{}> = async (req, rep) => {
+ try {
+ await req.jwtVerify()
+ // const decoded = (await req.jwtDecode()) as JWTDecoded
+ // todo find user by auth token
+ return rep.status(501)
+ } catch (e) {
+ const error = e as FastifyError
+ return rep.status(error.statusCode ?? 500).send(error)
+ }
+}
diff --git a/packages/store-server/src/api/controllers/userController.ts b/packages/store-server/src/api/controllers/userController.ts
new file mode 100644
index 0000000..5ded820
--- /dev/null
+++ b/packages/store-server/src/api/controllers/userController.ts
@@ -0,0 +1,10 @@
+import { RouteHandler } from 'fastify'
+
+export const getUserCtrl: RouteHandler<{
+ Params: {
+ userId: string
+ }
+}> = (req, res) =>
+ res.status(200).send({
+ status: 'okay',
+ })
diff --git a/packages/store-server/src/api/database/prisma.ts b/packages/store-server/src/api/database/prisma.ts
new file mode 100644
index 0000000..6260dd0
--- /dev/null
+++ b/packages/store-server/src/api/database/prisma.ts
@@ -0,0 +1,3 @@
+import { PrismaClient } from '@prisma/client'
+
+export const prisma = new PrismaClient()
diff --git a/packages/store-server/src/api/models/AuthToken.ts b/packages/store-server/src/api/models/AuthToken.ts
new file mode 100644
index 0000000..164b548
--- /dev/null
+++ b/packages/store-server/src/api/models/AuthToken.ts
@@ -0,0 +1,77 @@
+import { prisma } from '../database/prisma'
+
+export type AuthTokenSerialized = {
+ id: string
+ auth_token: string
+ refresh_token: string
+ user_id: string
+ created_at: string
+}
+
+export default class AuthToken {
+ public id?: string
+
+ public auth_token!: string
+
+ public refresh_token!: string
+
+ public user_id!: string
+
+ public created_at?: Date
+
+ constructor(params: {
+ id?: string
+ auth_token: string
+ refresh_token: string
+ user_id: string
+ created_at?: Date
+ }) {
+ this.id = params.id
+ this.auth_token = params.auth_token
+ this.refresh_token = params.refresh_token
+ this.user_id = params.user_id
+ this.created_at = params.created_at
+ }
+
+ public static async getByUserId(userId: string) {
+ // eslint-disable-next-line no-return-await
+ return await prisma.authToken.findUnique({
+ where: {
+ user_id: userId,
+ },
+ })
+ }
+
+ public static async deleteById(id: string) {
+ await prisma.authToken.delete({
+ where: {
+ id,
+ },
+ })
+ }
+
+ public async create() {
+ const existing = await AuthToken.getByUserId(this.user_id)
+ if (existing) {
+ await AuthToken.deleteById(existing.id)
+ }
+ // eslint-disable-next-line no-return-await
+ return await prisma.authToken.create({
+ data: {
+ auth_token: this.auth_token,
+ refresh_token: this.refresh_token,
+ user_id: this.user_id,
+ },
+ })
+ }
+
+ public serialize(): AuthTokenSerialized {
+ return {
+ id: this.id ?? '',
+ auth_token: this.auth_token,
+ refresh_token: this.refresh_token,
+ user_id: this.user_id,
+ created_at: this.created_at?.toISOString() ?? '',
+ }
+ }
+}
diff --git a/packages/store-server/src/api/models/User.ts b/packages/store-server/src/api/models/User.ts
new file mode 100644
index 0000000..4e834bd
--- /dev/null
+++ b/packages/store-server/src/api/models/User.ts
@@ -0,0 +1,49 @@
+/* eslint-disable class-methods-use-this */
+import { prisma } from '../database/prisma'
+
+export type UserSerialized = {
+ id: string
+ email: string
+ created_at: string
+}
+
+export default class User {
+ public id?: string
+
+ public email!: string
+
+ public created_at?: Date
+
+ constructor(params: { id?: string; email: string; created_at?: Date }) {
+ this.id = params.id
+ this.email = params.email
+ this.created_at = params.created_at
+ }
+
+ public static async findByEmail(email: string) {
+ const user = await prisma.user.findUnique({
+ where: {
+ email,
+ },
+ })
+
+ return user
+ }
+
+ public async create() {
+ const user = await prisma.user.create({
+ data: {
+ email: this.email,
+ },
+ })
+ return user
+ }
+
+ public serialize(): UserSerialized {
+ return {
+ id: this.id ?? '',
+ email: this.email,
+ created_at: this.created_at?.toISOString() ?? '',
+ }
+ }
+}
diff --git a/packages/store-server/src/api/routes/auth.ts b/packages/store-server/src/api/routes/auth.ts
new file mode 100644
index 0000000..f5ce7df
--- /dev/null
+++ b/packages/store-server/src/api/routes/auth.ts
@@ -0,0 +1,9 @@
+import { FastifyPluginCallback } from 'fastify'
+import { socialSignInCtrl } from '../controllers/authController'
+
+const authRoute: FastifyPluginCallback = (fastify, opts, done) => {
+ fastify.post('/auth/social-signin', socialSignInCtrl)
+ done()
+}
+
+export default authRoute
diff --git a/packages/store-server/src/api/routes/me.ts b/packages/store-server/src/api/routes/me.ts
new file mode 100644
index 0000000..112efa2
--- /dev/null
+++ b/packages/store-server/src/api/routes/me.ts
@@ -0,0 +1,9 @@
+import { FastifyPluginCallback } from 'fastify'
+import { getMeCtrl } from '../controllers/meController'
+
+const meRoute: FastifyPluginCallback = (fastify, opts, done) => {
+ fastify.get('/me', getMeCtrl)
+ done()
+}
+
+export default meRoute
diff --git a/packages/store-server/src/api/routes/user.ts b/packages/store-server/src/api/routes/user.ts
new file mode 100644
index 0000000..343f1ce
--- /dev/null
+++ b/packages/store-server/src/api/routes/user.ts
@@ -0,0 +1,9 @@
+import { FastifyPluginCallback } from 'fastify'
+import { getUserCtrl } from '../controllers/userController'
+
+const userRoute: FastifyPluginCallback = (fastify, opts, done) => {
+ fastify.get('/user/:userId', getUserCtrl)
+ done()
+}
+
+export default userRoute
diff --git a/packages/store-server/src/config/config.example.json b/packages/store-server/src/config/config.example.json
new file mode 100644
index 0000000..aa168b7
--- /dev/null
+++ b/packages/store-server/src/config/config.example.json
@@ -0,0 +1,6 @@
+{
+ "port": "",
+ "secrets": {
+ "jwt": ""
+ }
+}
\ No newline at end of file
diff --git a/packages/store-server/src/config/ecosystem.config.js b/packages/store-server/src/config/ecosystem.config.js
new file mode 100644
index 0000000..a5ec3a3
--- /dev/null
+++ b/packages/store-server/src/config/ecosystem.config.js
@@ -0,0 +1,8 @@
+module.exports = {
+ apps: [
+ {
+ name: 'coldsurf store server',
+ script: 'node ./dist/server.js',
+ },
+ ],
+}
diff --git a/packages/store-server/src/server.ts b/packages/store-server/src/server.ts
new file mode 100644
index 0000000..95fe7e1
--- /dev/null
+++ b/packages/store-server/src/server.ts
@@ -0,0 +1,57 @@
+import Fastify from 'fastify'
+import AutoLoad from '@fastify/autoload'
+import path from 'path'
+import nconf from 'nconf'
+import jwt from '@fastify/jwt'
+import cors from '@fastify/cors'
+
+const fastify = Fastify({
+ ignoreTrailingSlash: true,
+ logger: {
+ level: 'info',
+ },
+})
+
+async function loadSettings() {
+ return new Promise((resolve, reject) => {
+ try {
+ nconf.file({
+ file: path.resolve(__dirname, './config/config.json'),
+ })
+ resolve()
+ } catch (e) {
+ reject(e)
+ }
+ })
+}
+
+async function main() {
+ try {
+ await loadSettings()
+ await fastify.register(cors, {
+ origin:
+ process.env.NODE_ENV === 'development'
+ ? ['http://localhost:3000']
+ : ['https://store.coldsurf.io'],
+ preflight: true,
+ methods: ['GET', 'POST', 'OPTIONS', 'PATCH', 'PUT', 'DELETE'],
+ })
+ await fastify.register(AutoLoad, {
+ dir: path.resolve(__dirname, './api/routes'),
+ options: {
+ prefix: '/api/v1',
+ },
+ })
+ await fastify.register(jwt, {
+ secret: nconf.get('secrets').jwt,
+ })
+
+ await fastify.listen({ port: nconf.get('port'), host: '0.0.0.0' })
+ fastify.log.info('server started', process.env.NODE_ENV)
+ } catch (err) {
+ fastify.log.error(err)
+ process.exit(1)
+ }
+}
+
+main()
diff --git a/packages/store-server/src/types/auth.ts b/packages/store-server/src/types/auth.ts
new file mode 100644
index 0000000..a49e7a8
--- /dev/null
+++ b/packages/store-server/src/types/auth.ts
@@ -0,0 +1 @@
+export type SocialAuthProvider = 'google'
diff --git a/packages/store-server/src/types/fastify-jwt.d.ts b/packages/store-server/src/types/fastify-jwt.d.ts
new file mode 100644
index 0000000..2a7b0e1
--- /dev/null
+++ b/packages/store-server/src/types/fastify-jwt.d.ts
@@ -0,0 +1,14 @@
+// fastify-jwt.d.ts
+import '@fastify/jwt'
+import { JWTPayload } from './jwt'
+
+declare module '@fastify/jwt' {
+ interface FastifyJWT {
+ payload: JWTPayload // payload type is used for signing and verifying
+ // user: {
+ // id: number
+ // name: string
+ // age: number
+ // } // user type is return type of `request.user` object
+ }
+}
diff --git a/packages/store-server/src/types/jwt.ts b/packages/store-server/src/types/jwt.ts
new file mode 100644
index 0000000..c6be056
--- /dev/null
+++ b/packages/store-server/src/types/jwt.ts
@@ -0,0 +1,15 @@
+import { SocialAuthProvider } from './auth'
+
+export type JWTDecoded = {
+ provider: SocialAuthProvider
+ email: string
+ id: string
+ iat: number
+ exp: number
+}
+
+export type JWTPayload = {
+ provider: SocialAuthProvider
+ email: string
+ id: string
+}
diff --git a/packages/store-server/tsconfig.json b/packages/store-server/tsconfig.json
new file mode 100644
index 0000000..3f761d9
--- /dev/null
+++ b/packages/store-server/tsconfig.json
@@ -0,0 +1,109 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig to read more about this file */
+
+ /* Projects */
+ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
+ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
+
+ /* Language and Environment */
+ "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
+ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
+ // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
+ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
+ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
+ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
+ // "resolveJsonModule": true, /* Enable importing .json files. */
+ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
+ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
+
+ /* JavaScript Support */
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+
+ /* Emit */
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+ "outDir": "./dist", /* Specify an output folder for all emitted files. */
+ // "removeComments": true, /* Disable emitting comments. */
+ // "noEmit": true, /* Disable emitting files from a compilation. */
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
+ // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
+ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+
+ /* Interop Constraints */
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
+ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
+ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
+ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
+ // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
+
+ /* Completeness */
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}
diff --git a/packages/wamuseum-server/package.json b/packages/wamuseum-server/package.json
index e3e9a62..0380563 100644
--- a/packages/wamuseum-server/package.json
+++ b/packages/wamuseum-server/package.json
@@ -25,7 +25,7 @@
"@fastify/jwt": "^7.2.4",
"@fastify/multipart": "^8.0.0",
"@fastify/static": "^6.12.0",
- "@prisma/client": "^5.7.1",
+ "@prisma/client": "5.8.0",
"crypto-js": "^4.2.0",
"fastify": "^4.25.2",
"google-auth-library": "^9.4.1",
diff --git a/yarn.lock b/yarn.lock
index 69c410d..2b52834 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -713,6 +713,13 @@
dependencies:
"@coldsurfers/design-tokens" "1.10.0"
+"@coldsurfers/ocean-road@1.5.1-rc.4":
+ version "1.5.1-rc.4"
+ resolved "https://npm.pkg.github.com/download/@coldsurfers/ocean-road/1.5.1-rc.4/1fdda4c202431757e90521518a8db558ee57318f#1fdda4c202431757e90521518a8db558ee57318f"
+ integrity sha512-o8ogWQzPTttF9KfQiaKV/ULQaahKGoOBZCfu8rkfOxBCTb6SOP7bcZBAUwYj684aXisIyCyOy3T2GasKFiT4Yg==
+ dependencies:
+ "@coldsurfers/design-tokens" "1.10.0"
+
"@coldsurfers/ocean-road@^1.11.0":
version "1.11.0"
resolved "https://npm.pkg.github.com/download/@coldsurfers/ocean-road/1.11.0/b91fb55818288fc79cf87ae1223b5aaba74bb27e"
@@ -786,7 +793,7 @@
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz"
integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
-"@emotion/react@^11.8.2", "@emotion/react@^11.9.0":
+"@emotion/react@^11.11.1", "@emotion/react@^11.8.2", "@emotion/react@^11.9.0":
version "11.11.3"
resolved "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz"
integrity sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==
@@ -816,7 +823,7 @@
resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz"
integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==
-"@emotion/styled@^11.8.1":
+"@emotion/styled@^11.11.0", "@emotion/styled@^11.8.1":
version "11.11.0"
resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz"
integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==
@@ -936,7 +943,7 @@
dependencies:
text-decoding "^1.0.0"
-"@fastify/cors@^8.5.0":
+"@fastify/cors@^8.4.2", "@fastify/cors@^8.5.0":
version "8.5.0"
resolved "https://registry.npmjs.org/@fastify/cors/-/cors-8.5.0.tgz"
integrity sha512-/oZ1QSb02XjP0IK1U0IXktEsw/dUBTxJOW7IpIeO8c/tNalw/KjoNSJv1Sf6eqoBPO+TDGkifq6ynFK3v68HFQ==
@@ -1081,6 +1088,11 @@
resolved "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz"
integrity sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==
+"@next/env@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.3.tgz#9a58b296e7ae04ffebce8a4e5bd0f87f71de86bd"
+ integrity sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA==
+
"@next/env@14.0.4":
version "14.0.4"
resolved "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz"
@@ -1149,6 +1161,11 @@
resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz"
integrity sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==
+"@next/swc-darwin-arm64@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.3.tgz#b1a0440ffbf69056451947c4aea5b6d887e9fbbc"
+ integrity sha512-64JbSvi3nbbcEtyitNn2LEDS/hcleAFpHdykpcnrstITFlzFgB/bW0ER5/SJJwUPj+ZPY+z3e+1jAfcczRLVGw==
+
"@next/swc-darwin-arm64@14.0.4":
version "14.0.4"
resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.4.tgz"
@@ -1169,6 +1186,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz#9c72ee31cc356cb65ce6860b658d807ff39f1578"
integrity sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==
+"@next/swc-darwin-x64@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.3.tgz#48b527ef7eb5dbdcaf62fd107bc3a78371f36f09"
+ integrity sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ==
+
"@next/swc-darwin-x64@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.4.tgz#9940c449e757d0ee50bb9e792d2600cc08a3eb3b"
@@ -1204,6 +1226,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz#59f5f66155e85380ffa26ee3d95b687a770cfeab"
integrity sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==
+"@next/swc-linux-arm64-gnu@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.3.tgz#0a36475a38b2855ab8ea0fe8b56899bc90184c0f"
+ integrity sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg==
+
"@next/swc-linux-arm64-gnu@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.4.tgz#0eafd27c8587f68ace7b4fa80695711a8434de21"
@@ -1224,6 +1251,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz#f012518228017052736a87d69bae73e587c76ce2"
integrity sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==
+"@next/swc-linux-arm64-musl@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.3.tgz#25328a9f55baa09fde6364e7e47ade65c655034f"
+ integrity sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA==
+
"@next/swc-linux-arm64-musl@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz#2b0072adb213f36dada5394ea67d6e82069ae7dd"
@@ -1244,6 +1276,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz#339b867a7e9e7ee727a700b496b269033d820df4"
integrity sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==
+"@next/swc-linux-x64-gnu@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.3.tgz#594b747e3c8896b2da67bba54fcf8a6b5a410e5e"
+ integrity sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg==
+
"@next/swc-linux-x64-gnu@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz#68c67d20ebc8e3f6ced6ff23a4ba2a679dbcec32"
@@ -1264,6 +1301,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz#ae0ae84d058df758675830bcf70ca1846f1028f2"
integrity sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==
+"@next/swc-linux-x64-musl@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.3.tgz#a02da58fc6ecad8cf5c5a2a96a7f6030ec7f6215"
+ integrity sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg==
+
"@next/swc-linux-x64-musl@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz#67cd81b42fb2caf313f7992fcf6d978af55a1247"
@@ -1284,6 +1326,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz#a5cc0c16920485a929a17495064671374fdbc661"
integrity sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==
+"@next/swc-win32-arm64-msvc@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.3.tgz#bf2be23d3ba2ebd0d4a9376a31f783efdb677b48"
+ integrity sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog==
+
"@next/swc-win32-arm64-msvc@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz#be06585906b195d755ceda28f33c633e1443f1a3"
@@ -1304,6 +1351,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz#6a2409b84a2cbf34bf92fe714896455efb4191e4"
integrity sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==
+"@next/swc-win32-ia32-msvc@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.3.tgz#839f8de85a4bf2c3c69242483ab87cb916427551"
+ integrity sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg==
+
"@next/swc-win32-ia32-msvc@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz#e76cabefa9f2d891599c3d85928475bd8d3f6600"
@@ -1324,6 +1376,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz#4a3e2a206251abc729339ba85f60bc0433c2865d"
integrity sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==
+"@next/swc-win32-x64-msvc@14.0.3":
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.3.tgz#27b623612b1d0cea6efe0a0d31aa1a335fc99647"
+ integrity sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ==
+
"@next/swc-win32-x64-msvc@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz#e74892f1a9ccf41d3bf5979ad6d3d77c07b9cba1"
@@ -1562,7 +1619,7 @@
"@pnpm/network.ca-file" "^1.0.1"
config-chain "^1.1.11"
-"@prisma/client@^5.7.1":
+"@prisma/client@5.8.0", "@prisma/client@^5.7.1":
version "5.8.0"
resolved "https://registry.npmjs.org/@prisma/client/-/client-5.8.0.tgz"
integrity sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==
@@ -1603,6 +1660,11 @@
dependencies:
"@prisma/debug" "5.8.0"
+"@react-oauth/google@^0.12.1":
+ version "0.12.1"
+ resolved "https://registry.yarnpkg.com/@react-oauth/google/-/google-0.12.1.tgz#b76432c3a525e9afe076f787d2ded003fcc1bee9"
+ integrity sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg==
+
"@react-spring/animated@~9.7.3":
version "9.7.3"
resolved "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz"
@@ -2195,7 +2257,7 @@
dependencies:
defer-to-connect "^2.0.1"
-"@tanstack/eslint-plugin-query@^5.17.7":
+"@tanstack/eslint-plugin-query@^5.12.1", "@tanstack/eslint-plugin-query@^5.17.7":
version "5.17.7"
resolved "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.17.7.tgz"
integrity sha512-RpKZXIuplRrUZLqqh+jTM1yJP8/Ck21FpaSB5uGyc9LY8LNwxC8AwgaRAXVOZzKVeQMunnt3HrK83HME+7jnGw==
@@ -2207,7 +2269,7 @@
resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.17.10.tgz"
integrity sha512-bJ2oQUDBftvHcEkLS3gyzzShSeZpJyzNNRu8oHK13iNdsofyaDXtNO/c1Zy/PZYVX+PhqOXwoT42gMiEMRSSfQ==
-"@tanstack/react-query@^5.17.9":
+"@tanstack/react-query@^5.12.2", "@tanstack/react-query@^5.17.9":
version "5.17.10"
resolved "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.17.10.tgz"
integrity sha512-TNmJN7LkSLzmv01Jen3JbcvhXZyRhc/ETJNjssmmlyMB8IoNvicfgvDRX2gX3q1FTONq+mfsmWintwI+ejmEUw==
@@ -2375,6 +2437,11 @@
dependencies:
"@types/node" "*"
+"@types/uuid@8.3.4":
+ version "8.3.4"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
+ integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
+
"@typescript-eslint/eslint-plugin@^5.21.0", "@typescript-eslint/eslint-plugin@^5.53.0", "@typescript-eslint/eslint-plugin@^5.62.0":
version "5.62.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz"
@@ -2921,6 +2988,15 @@ axios@^1.4.0, axios@^1.6.3:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
+axios@^1.6.2:
+ version "1.6.5"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8"
+ integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==
+ dependencies:
+ follow-redirects "^1.15.4"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz"
@@ -4545,7 +4621,7 @@ fastify-plugin@^4.0.0:
resolved "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz"
integrity sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==
-fastify@^4.25.2:
+fastify@^4.24.3, fastify@^4.25.2:
version "4.25.2"
resolved "https://registry.npmjs.org/fastify/-/fastify-4.25.2.tgz"
integrity sha512-SywRouGleDHvRh054onj+lEZnbC1sBCLkR0UY3oyJwjD4BdZJUrxBqfkfCaqn74pVCwBaRHGuL3nEWeHbHzAfw==
@@ -4661,7 +4737,7 @@ flatted@^3.2.9:
resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz"
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
-follow-redirects@^1.14.0:
+follow-redirects@^1.14.0, follow-redirects@^1.15.4:
version "1.15.5"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz"
integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
@@ -6055,6 +6131,13 @@ next-auth@^5.0.0-beta.4:
dependencies:
"@auth/core" "0.18.4"
+next-auth@beta:
+ version "5.0.0-beta.4"
+ resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-5.0.0-beta.4.tgz#3be1ca3a89626e993e04bfc5129a8f8e0afb161b"
+ integrity sha512-vgocjvwPA8gxd/zrIP/vr9lJ/HeNe+C56lPP1D3sdyenHt8KncQV6ro7q0xCsDp1fcOKx7WAWVZH5o8aMxDzgw==
+ dependencies:
+ "@auth/core" "0.18.4"
+
next-sitemap@^4.2.3:
version "4.2.3"
resolved "https://registry.npmjs.org/next-sitemap/-/next-sitemap-4.2.3.tgz"
@@ -6113,6 +6196,29 @@ next@13.1.0:
"@next/swc-win32-ia32-msvc" "13.1.0"
"@next/swc-win32-x64-msvc" "13.1.0"
+next@14.0.3:
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/next/-/next-14.0.3.tgz#8d801a08eaefe5974203d71092fccc463103a03f"
+ integrity sha512-AbYdRNfImBr3XGtvnwOxq8ekVCwbFTv/UJoLwmaX89nk9i051AEY4/HAWzU0YpaTDw8IofUpmuIlvzWF13jxIw==
+ dependencies:
+ "@next/env" "14.0.3"
+ "@swc/helpers" "0.5.2"
+ busboy "1.6.0"
+ caniuse-lite "^1.0.30001406"
+ postcss "8.4.31"
+ styled-jsx "5.1.1"
+ watchpack "2.4.0"
+ optionalDependencies:
+ "@next/swc-darwin-arm64" "14.0.3"
+ "@next/swc-darwin-x64" "14.0.3"
+ "@next/swc-linux-arm64-gnu" "14.0.3"
+ "@next/swc-linux-arm64-musl" "14.0.3"
+ "@next/swc-linux-x64-gnu" "14.0.3"
+ "@next/swc-linux-x64-musl" "14.0.3"
+ "@next/swc-win32-arm64-msvc" "14.0.3"
+ "@next/swc-win32-ia32-msvc" "14.0.3"
+ "@next/swc-win32-x64-msvc" "14.0.3"
+
next@14.0.4:
version "14.0.4"
resolved "https://registry.npmjs.org/next/-/next-14.0.4.tgz"
@@ -6892,6 +6998,11 @@ react-dom@18.2.0, react-dom@^18:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-hook-form@^7.48.2:
+ version "7.49.3"
+ resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.49.3.tgz#576a4567f8a774830812f4855e89f5da5830435c"
+ integrity sha512-foD6r3juidAT1cOZzpmD/gOKt7fRsDhXXZ0y28+Al1CHgX+AY1qIN9VSIIItXRq1dN68QrRwl1ORFlwjBaAqeQ==
+
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
@@ -7925,6 +8036,11 @@ url-join@5.0.0:
resolved "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz"
integrity sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==
+use-sync-external-store@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
+ integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
@@ -7941,15 +8057,23 @@ util@^0.12.5:
is-typed-array "^1.1.3"
which-typed-array "^1.1.2"
+uuid@8.3.2, uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
uuid@^3.2.1:
version "3.4.0"
resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-uuid@^8.3.2:
- version "8.3.2"
- resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
- integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+uuidv4@^6.2.13:
+ version "6.2.13"
+ resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.13.tgz#8f95ec5ef22d1f92c8e5d4c70b735d1c89572cb7"
+ integrity sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ==
+ dependencies:
+ "@types/uuid" "8.3.4"
+ uuid "8.3.2"
v8-compile-cache@^2.0.3:
version "2.4.0"
@@ -8192,3 +8316,10 @@ zod@^3.22.4:
version "3.22.4"
resolved "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz"
integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==
+
+zustand@^4.4.7:
+ version "4.4.7"
+ resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.7.tgz#355406be6b11ab335f59a66d2cf9815e8f24038c"
+ integrity sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==
+ dependencies:
+ use-sync-external-store "1.2.0"