Working on arthome

This commit is contained in:
2024-08-25 18:33:37 +02:00
parent a5120d006a
commit a1e31a89a7
49 changed files with 3139 additions and 284 deletions

View File

@@ -1,22 +1,15 @@
<script lang="ts" setup>
useHead({
link: [{ rel: 'icon', type: 'image/png', href: '/favicon.ico' }],
title: 'Home by Arthur Danjou',
title: 'ArtHome by Arthur Danjou',
})
const { loggedIn, clear, user } = useUserSession()
const colorMode = useColorMode()
const authorized = await isAuthorized()
onMounted(async () => {
if (!authorized) {
navigateTo('/')
}
})
watch(loggedIn, async () => {
if (!loggedIn.value) {
navigateTo('/')
navigateTo('/login')
}
})
@@ -24,6 +17,12 @@ function toggleColorMode() {
colorMode.preference = colorMode.preference === 'dark' ? 'light' : 'dark'
}
async function logout() {
await clear()
navigateTo('/login')
window.location.reload()
}
defineShortcuts({
t: () => toggleColorMode(),
c: () => toggleColorMode(),
@@ -43,7 +42,7 @@ defineShortcuts({
square
trailing-icon="i-ph:person-arms-spread-duotone"
variant="ghost"
@click="clear"
@click="logout"
/>
</UTooltip>
<UButton

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
</script>
<template>
<div>
<slot />
</div>
</template>
<style scoped>
</style>

18
app/components/Tab.vue Normal file
View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import type { Tab } from '~~/server/utils/db'
defineProps<{
tab: PropType<Tab>
}>()
</script>
<template>
<div>
Tab
{{ tab }}
</div>
</template>
<style scoped>
</style>

View File

@@ -1,10 +0,0 @@
export async function isAuthorized() {
const { user } = useUserSession()
const { data: authorized } = await useFetch('/api/authorized', {
method: 'POST',
body: {
email: user.value?.email ?? 'test@nuxt.com',
},
})
return authorized.value
}

View File

@@ -0,0 +1,13 @@
export function useCategories() {
async function getCategories() {
return useAsyncData<CategoryType[]>(async () => {
const res = await $fetch('/api/categories')
console.log('res', res)
return res
})
}
return {
getCategories,
}
}

21
app/composables/tabs.ts Normal file
View File

@@ -0,0 +1,21 @@
export function useTabs() {
async function createTab(tab: TabType) {
console.log('createTab', tab)
return tab
}
async function deleteTab(tab: TabType) {
console.log('deleteTab', tab)
return tab
}
async function updateTab(tab: TabType) {
console.log('updateTab', tab)
return tab
}
return {
createTab,
deleteTab,
}
}

21
app/composables/toasts.ts Normal file
View File

@@ -0,0 +1,21 @@
export function useSuccessToast(title: string, description?: string) {
const toast = useToast()
toast.add({
title,
description,
color: 'green',
icon: 'i-ph:check-circle-duotone',
})
}
export function useErrorToast(title: string, description?: string) {
const toast = useToast()
toast.add({
title,
description,
color: 'red',
icon: 'i-ph:x-circle-duotone',
})
}

View File

@@ -0,0 +1,22 @@
export function useUserLimit() {
function hasUserFreePlan() {
return true
}
function getRemainingCategories() {
if (!hasUserFreePlan())
return -1
return 3
}
function getRemainingTabs(category_id: number) {
if (!hasUserFreePlan())
return -1
return category_id * 3
}
return {
getRemainingCategories,
getRemainingTabs,
}
}

View File

@@ -1,8 +1,7 @@
export default defineNuxtRouteMiddleware(async () => {
const { loggedIn } = useUserSession()
const authorized = await isAuthorized()
if (!loggedIn.value || !authorized) {
return navigateTo('/')
if (!loggedIn.value) {
return navigateTo('/login')
}
})

7
app/middleware/ghost.ts Normal file
View File

@@ -0,0 +1,7 @@
export default defineNuxtRouteMiddleware(async () => {
const { loggedIn } = useUserSession()
if (loggedIn.value) {
return navigateTo('/')
}
})

13
app/pages/[user].vue Normal file
View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
const router = useRouter()
</script>
<template>
<section>
{{ router.currentRoute.value.params.user }}
</section>
</template>
<style scoped>
</style>

View File

@@ -1,41 +0,0 @@
<script lang="ts" setup>
definePageMeta({
middleware: 'auth',
})
const date = ref<Date>(new Date())
onMounted(() => {
setInterval(() => date.value = new Date(), 1000)
})
const apps = await queryContent('/').find()
const dev = apps.filter(app => app._dir === 'dev')
const perso = apps.filter(app => app._dir === 'perso')
const maths = apps.filter(app => app._dir === 'maths')
const social = apps.filter(app => app._dir === 'social')
</script>
<template>
<main class="my-12">
<div v-if="date" class="flex flex-col items-center">
<h1 class="text-6xl md:text-9xl font-bold">
{{ useDateFormat(date, 'HH') }}
<span class="animate-pulse">:</span>
{{ useDateFormat(date, 'mm') }}
</h1>
<h1 class="text-2xl md:text-5xl">
{{ useDateFormat(date, 'dddd D MMMM YYYY', { locales: () => 'fr-FR' }) }}
</h1>
</div>
<div v-if="apps" class="space-y-12 mt-12">
<section class="grid grid-cols-1 auto-rows-auto sm:grid-cols-3 gap-4">
<Weather />
<Map />
</section>
<Application :apps="perso" title="Personnel" />
<Application :apps="social" title="Social" />
<Application :apps="dev" title="Développement" />
<Application :apps="maths" title="Mathématiques" />
</div>
</main>
</template>

View File

@@ -1,64 +1,54 @@
<script lang="ts" setup>
const { loggedIn } = useUserSession()
const authorized = await isAuthorized()
onMounted(() => {
if (authorized) {
navigateTo('/home')
}
definePageMeta({
middleware: 'auth',
})
const date = ref<Date>(new Date())
onMounted(() => {
setInterval(() => date.value = new Date(), 1000)
})
const { user, session } = useUserSession()
const { getCategories } = useCategories()
const categories = await getCategories()
</script>
<template>
<div class="min-h-screen flex items-center justify-center">
<UCard class="w-full md:w-1/2">
<template #header>
<h1 class="font-bold text-black dark:text-white text-lg space-y-2">
Welcome to ArtHome
<main v-if="user" class="my-12">
<div v-if="date" class="flex flex-col items-center">
<h1 class="text-6xl md:text-9xl font-bold">
{{ useDateFormat(date, 'HH') }}
<span class="animate-pulse">:</span>
{{ useDateFormat(date, 'mm') }}
</h1>
<h1 class="text-2xl md:text-5xl">
{{ useDateFormat(date, 'dddd D MMMM YYYY', { locales: user.language }) }}
</h1>
</template>
<template #default>
<p>
ArtHome is a private platform. You need to request access to be able to use it by asking to
<a
class="duration-300 underline-offset-2 text-md text-black dark:text-white underline decoration-gray-300 dark:decoration-neutral-700 hover:decoration-black dark:hover:decoration-white"
href="mailto:arthurdanjou@outlook.fr"
rel="noopener"
target="_blank"
>Arthur Danjou</a>
</p>
<div v-if="!loggedIn" class="flex gap-2 mt-2">
<UButton
:external="true"
color="black"
icon="i-ph:github-logo-duotone"
label="GitHub"
to="/auth/github"
/>
<UButton
:external="true"
color="red"
icon="i-ph:google-logo-duotone"
label="Google"
to="/auth/google"
/>
</div>
<UButton
v-if="authorized"
color="black"
icon="i-ph:house-duotone"
label="Go Home"
to="/home"
/>
<p v-if="!authorized && loggedIn" class="text-red-500 font-medium">
You're not authorized to access
</p>
</template>
<template #footer>
<p class="italic text-sm">
No personal informations regarding your account are stored in database.
</p>
</template>
</UCard>
<div>
{{ user }}
</div>
<div>
{{ session }}
</div>
<div>
{{ user === session.user }}
</div>
<div v-if="categories">
{{ categories }}
</div>
<div>
<Category>
<Tab
:tab="{
name: 'Test',
nameVisible: true,
icon: 'i-ph:cloud-duotone',
color: 'blue',
}"
/>
</Category>
</div>
</main>
</template>

104
app/pages/login.vue Normal file
View File

@@ -0,0 +1,104 @@
<script lang="ts" setup>
import { z } from 'zod'
import { useSession } from 'h3'
import type { FormSubmitEvent } from '#ui/types'
const { loggedIn } = useUserSession()
definePageMeta({
middleware: 'ghost',
})
const schema = z.object({
email: z.string().email('Invalid email'),
})
const form = ref()
type Schema = z.output<typeof schema>
const state = reactive({ email: undefined })
async function onSubmit(event: FormSubmitEvent<Schema>) {
// Do something with data
// todo: add login logic
console.log(event.data)
state.email = ''
}
const message = useState<string>('message')
if (import.meta.server) {
const session = await useSession(useRequestEvent()!, {
password: useRuntimeConfig().session.password,
})
message.value = session.data.message
await session.update({
message: '',
})
}
</script>
<template>
<div class="min-h-screen flex flex-col items-center justify-center">
<h1 class="tracking-widest text-4xl font-bold text-black dark:text-white mb-12">
ArtHome
</h1>
<div class="w-full md:w-1/3">
<UAlert
v-if="message"
class="mb-8"
color="red"
variant="outline"
:close-button="{ icon: 'i-ph:x-circle-duotone', color: 'red', variant: 'link', padded: false }"
:description="message"
@close="message = ''"
/>
</div>
<UCard class="w-full md:w-1/3 mt-2">
<template #header>
<h1 class="text-center font-bold text-black dark:text-white text-lg py-2">
Sign in to your ArtHome account
</h1>
</template>
<template #default>
<div v-if="!loggedIn" class="flex flex-col gap-4 p-4">
<UForm ref="form" :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup name="email">
<UInput v-model="state.email" color="gray" placeholder="arthur@arthome.com" />
</UFormGroup>
<UButton
:external="true"
color="gray"
icon="i-ph:envelope-duotone"
label="Continue with Email"
block
type="submit"
/>
</UForm>
<UDivider label="or" />
<UButton
:external="true"
color="gray"
icon="i-ph:github-logo-duotone"
label="Continue with GitHub"
block
to="/auth/github"
/>
<UButton
:external="true"
color="gray"
icon="i-ph:google-logo-duotone"
label="Continue With Google"
block
to="/auth/google"
/>
</div>
</template>
<template #footer>
<p class="italic text-xs">
We only store your email address, name and profile picture. We will never share your data with third parties.
</p>
</template>
</UCard>
</div>
</template>

24
app/pages/profile.vue Normal file
View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
const { user, loggedIn, session, clear } = useUserSession()
</script>
<template>
<div>
<div>
User: {{ user }}
</div>
<div>
LoggedIn: {{ loggedIn }}
</div>
<div>
Session: {{ session }}
</div>
<div @click="clear">
clear
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,7 +1,13 @@
import type { Config } from 'drizzle-kit'
import { config } from 'dotenv'
config()
export default {
dialect: 'sqlite',
dialect: 'postgresql',
schema: './server/database/schema.ts',
out: './server/database/migrations',
dbCredentials: {
url: process.env.NUXT_POSTGRES_URL,
},
} satisfies Config

View File

@@ -35,7 +35,8 @@ export default defineNuxtConfig({
hub: {
cache: true,
analytics: true,
database: true,
blob: true,
kv: true,
},
// Nuxt Icon
@@ -79,6 +80,10 @@ export default defineNuxtConfig({
lang: '',
units: '',
},
postgres: {
url: '',
dir: './server/db',
},
public: {
mapbox: {
style: '',

View File

@@ -8,7 +8,10 @@
"remote": "nuxt dev --remote --host",
"postinstall": "nuxt prepare",
"lint:fix": "eslint . --fix",
"db:generate": "drizzle-kit generate"
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push",
"db:pull": "drizzle-kit pull"
},
"dependencies": {
"@nuxt/content": "^2.13.2",
@@ -16,9 +19,10 @@
"@nuxthq/studio": "^2.0.3",
"@nuxthub/core": "^0.7.3",
"@nuxtjs/google-fonts": "^3.2.0",
"drizzle-orm": "^0.32.1",
"drizzle-orm": "^0.33.0",
"h3-zod": "^0.5.3",
"nuxt-auth-utils": "^0.3.4",
"postgres": "^3.4.4",
"vue": "^3.4.38",
"vue-router": "^4.4.3",
"zod": "^3.23.8"
@@ -28,9 +32,11 @@
"@nuxt/devtools": "^1.3.14",
"@nuxt/ui": "^2.18.4",
"@types/node": "^22.4.2",
"@types/pg": "^8.11.6",
"@vueuse/core": "^11.0.1",
"@vueuse/nuxt": "^11.0.1",
"drizzle-kit": "^0.23.0",
"dotenv": "^16.4.5",
"drizzle-kit": "^0.24.1",
"eslint": "^9.9.0",
"mapbox-gl": "^3.6.0",
"nuxt": "^3.13.0",

252
pnpm-lock.yaml generated
View File

@@ -10,7 +10,7 @@ importers:
dependencies:
'@nuxt/content':
specifier: ^2.13.2
version: 2.13.2(ioredis@5.4.1)(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))
version: 2.13.2(ioredis@5.4.1)(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))
'@nuxt/image':
specifier: ^1.7.0
version: 1.7.0(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.21.0)
@@ -24,14 +24,17 @@ importers:
specifier: ^3.2.0
version: 3.2.0(magicast@0.3.4)(rollup@4.21.0)
drizzle-orm:
specifier: ^0.32.1
version: 0.32.2(@cloudflare/workers-types@4.20240821.1)
specifier: ^0.33.0
version: 0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4)
h3-zod:
specifier: ^0.5.3
version: 0.5.3(h3@1.12.0)(zod@3.23.8)
nuxt-auth-utils:
specifier: ^0.3.4
version: 0.3.4(magicast@0.3.4)(rollup@4.21.0)
postgres:
specifier: ^3.4.4
version: 3.4.4
vue:
specifier: ^3.4.38
version: 3.4.38(typescript@5.5.4)
@@ -54,15 +57,21 @@ importers:
'@types/node':
specifier: ^22.4.2
version: 22.5.0
'@types/pg':
specifier: ^8.11.6
version: 8.11.6
'@vueuse/core':
specifier: ^11.0.1
version: 11.0.1(vue@3.4.38(typescript@5.5.4))
'@vueuse/nuxt':
specifier: ^11.0.1
version: 11.0.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))
version: 11.0.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))
dotenv:
specifier: ^16.4.5
version: 16.4.5
drizzle-kit:
specifier: ^0.23.0
version: 0.23.2
specifier: ^0.24.1
version: 0.24.1
eslint:
specifier: ^9.9.0
version: 9.9.0(jiti@1.21.6)
@@ -71,7 +80,7 @@ importers:
version: 3.6.0
nuxt:
specifier: ^3.13.0
version: 3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4))
version: 3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4))
nuxt-mapbox:
specifier: ^1.6.0
version: 1.6.0(magicast@0.3.4)(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))
@@ -364,8 +373,8 @@ packages:
peerDependencies:
postcss-selector-parser: ^6.0.13
'@drizzle-team/brocli@0.8.2':
resolution: {integrity: sha512-zTrFENsqGvOkBOuHDC1pXCkDXNd2UhP4lI3gYGhQ1R1SPeAAfqzPsV1dcpMy4uNU6kB5VpU5NGhvwxVNETR02A==}
'@drizzle-team/brocli@0.10.1':
resolution: {integrity: sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg==}
'@es-joy/jsdoccomment@0.43.1':
resolution: {integrity: sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==}
@@ -1873,6 +1882,9 @@ packages:
'@types/pbf@3.0.5':
resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==}
'@types/pg@8.11.6':
resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==}
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
@@ -2965,12 +2977,12 @@ packages:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
drizzle-kit@0.23.2:
resolution: {integrity: sha512-NWkQ7GD2OTbQ7HzcjsaCOf3n0tlFPSEAF38fvDpwDj8jRbGWGFtN2cD8I8wp4lU+5Os/oyP2xycTKGLHdPipUw==}
drizzle-kit@0.24.1:
resolution: {integrity: sha512-y47ZuFpy3ZEz5v2P4Q4m7CZpC9infdmFAVP8klfl92hyBBvgWlyFnriDkycK2HXqB1PrYWNTck2p5TfFY5+EWw==}
hasBin: true
drizzle-orm@0.32.2:
resolution: {integrity: sha512-3fXKzPzrgZIcnWCSLiERKN5Opf9Iagrag75snfFlKeKSYB1nlgPBshzW3Zn6dQymkyiib+xc4nIz0t8U+Xdpuw==}
drizzle-orm@0.33.0:
resolution: {integrity: sha512-SHy72R2Rdkz0LEq0PSG/IdvnT3nGiWuRk+2tXZQ90GVq/XQhpCzu/EFT3V2rox+w8MlkBQxifF8pCStNYnERfA==}
peerDependencies:
'@aws-sdk/client-rds-data': '>=3'
'@cloudflare/workers-types': '>=3'
@@ -4637,6 +4649,9 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
obuf@1.1.2:
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
ofetch@1.3.4:
resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==}
@@ -4793,6 +4808,48 @@ packages:
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
pg-connection-string@2.6.4:
resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==}
pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
pg-numeric@1.0.2:
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
engines: {node: '>=4'}
pg-pool@3.6.2:
resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==}
peerDependencies:
pg: '>=8.0'
pg-protocol@1.6.1:
resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==}
pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
pg-types@4.0.2:
resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==}
engines: {node: '>=10'}
pg@8.12.0:
resolution: {integrity: sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
peerDependenciesMeta:
pg-native:
optional: true
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
@@ -5036,6 +5093,45 @@ packages:
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
engines: {node: ^10 || ^12 || >=14}
postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
postgres-array@3.0.2:
resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
engines: {node: '>=12'}
postgres-bytea@1.0.0:
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
engines: {node: '>=0.10.0'}
postgres-bytea@3.0.0:
resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
engines: {node: '>= 6'}
postgres-date@1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
postgres-date@2.1.0:
resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==}
engines: {node: '>=12'}
postgres-interval@1.2.0:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
postgres-interval@3.0.0:
resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
engines: {node: '>=12'}
postgres-range@1.1.4:
resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==}
postgres@3.4.4:
resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==}
engines: {node: '>=12'}
potpack@2.0.0:
resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==}
@@ -5471,6 +5567,10 @@ packages:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'}
split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
stable-hash@0.0.4:
resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
@@ -6577,7 +6677,7 @@ snapshots:
dependencies:
postcss-selector-parser: 6.1.2
'@drizzle-team/brocli@0.8.2': {}
'@drizzle-team/brocli@0.10.1': {}
'@es-joy/jsdoccomment@0.43.1':
dependencies:
@@ -7254,13 +7354,13 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
'@nuxt/content@2.13.2(ioredis@5.4.1)(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))':
'@nuxt/content@2.13.2(ioredis@5.4.1)(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))':
dependencies:
'@nuxt/kit': 3.13.0(magicast@0.3.4)(rollup@4.21.0)
'@nuxtjs/mdc': 0.8.3(magicast@0.3.4)(rollup@4.21.0)
'@vueuse/core': 10.11.1(vue@3.4.38(typescript@5.5.4))
'@vueuse/head': 2.0.0(vue@3.4.38(typescript@5.5.4))
'@vueuse/nuxt': 10.11.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))
'@vueuse/nuxt': 10.11.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))
consola: 3.2.3
defu: 6.1.4
destr: 2.0.3
@@ -8111,6 +8211,12 @@ snapshots:
'@types/pbf@3.0.5': {}
'@types/pg@8.11.6':
dependencies:
'@types/node': 22.5.0
pg-protocol: 1.6.1
pg-types: 4.0.2
'@types/resolve@1.20.2': {}
'@types/responselike@1.0.3':
@@ -8544,13 +8650,13 @@ snapshots:
'@vueuse/metadata@11.0.1': {}
'@vueuse/nuxt@10.11.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))':
'@vueuse/nuxt@10.11.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))':
dependencies:
'@nuxt/kit': 3.13.0(magicast@0.3.4)(rollup@4.21.0)
'@vueuse/core': 10.11.1(vue@3.4.38(typescript@5.5.4))
'@vueuse/metadata': 10.11.1
local-pkg: 0.5.0
nuxt: 3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4))
nuxt: 3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4))
vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4))
transitivePeerDependencies:
- '@vue/composition-api'
@@ -8559,13 +8665,13 @@ snapshots:
- supports-color
- vue
'@vueuse/nuxt@11.0.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))':
'@vueuse/nuxt@11.0.1(magicast@0.3.4)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)))(rollup@4.21.0)(vue@3.4.38(typescript@5.5.4))':
dependencies:
'@nuxt/kit': 3.13.0(magicast@0.3.4)(rollup@4.21.0)
'@vueuse/core': 11.0.1(vue@3.4.38(typescript@5.5.4))
'@vueuse/metadata': 11.0.1
local-pkg: 0.5.0
nuxt: 3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4))
nuxt: 3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4))
vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4))
transitivePeerDependencies:
- '@vue/composition-api'
@@ -9168,9 +9274,9 @@ snapshots:
date-fns@3.6.0: {}
db0@0.1.4(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1)):
db0@0.1.4(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4)):
optionalDependencies:
drizzle-orm: 0.32.2(@cloudflare/workers-types@4.20240821.1)
drizzle-orm: 0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4)
de-indent@1.0.2: {}
@@ -9291,18 +9397,21 @@ snapshots:
dotenv@16.4.5: {}
drizzle-kit@0.23.2:
drizzle-kit@0.24.1:
dependencies:
'@drizzle-team/brocli': 0.8.2
'@drizzle-team/brocli': 0.10.1
'@esbuild-kit/esm-loader': 2.6.5
esbuild: 0.19.12
esbuild-register: 3.6.0(esbuild@0.19.12)
transitivePeerDependencies:
- supports-color
drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1):
drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4):
optionalDependencies:
'@cloudflare/workers-types': 4.20240821.1
'@types/pg': 8.11.6
pg: 8.12.0
postgres: 3.4.4
duplexer@0.1.2: {}
@@ -11245,7 +11354,7 @@ snapshots:
mlly: 1.7.1
pkg-types: 1.1.3
nitropack@2.9.7(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(magicast@0.3.4):
nitropack@2.9.7(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(magicast@0.3.4):
dependencies:
'@cloudflare/kv-asset-handler': 0.3.4
'@netlify/functions': 2.8.1
@@ -11268,7 +11377,7 @@ snapshots:
cookie-es: 1.2.2
croner: 8.1.1
crossws: 0.2.4
db0: 0.1.4(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))
db0: 0.1.4(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))
defu: 6.1.4
destr: 2.0.3
dot-prop: 8.0.2
@@ -11456,7 +11565,7 @@ snapshots:
- utf-8-validate
- vite
nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)):
nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@22.5.0)(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(eslint@9.9.0(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.4)(meow@9.0.0)(optionator@0.9.4)(rollup@4.21.0)(terser@5.31.6)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))(vue-tsc@2.0.29(typescript@5.5.4)):
dependencies:
'@nuxt/devalue': 2.0.2
'@nuxt/devtools': 1.3.14(rollup@4.21.0)(vite@5.4.2(@types/node@22.5.0)(terser@5.31.6))
@@ -11490,7 +11599,7 @@ snapshots:
knitwork: 1.1.0
magic-string: 0.30.11
mlly: 1.7.1
nitropack: 2.9.7(drizzle-orm@0.32.2(@cloudflare/workers-types@4.20240821.1))(magicast@0.3.4)
nitropack: 2.9.7(drizzle-orm@0.33.0(@cloudflare/workers-types@4.20240821.1)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(magicast@0.3.4)
nuxi: 3.12.0
nypm: 0.3.9
ofetch: 1.3.4
@@ -11576,6 +11685,8 @@ snapshots:
object-hash@3.0.0: {}
obuf@1.1.2: {}
ofetch@1.3.4:
dependencies:
destr: 2.0.3
@@ -11747,6 +11858,58 @@ snapshots:
perfect-debounce@1.0.0: {}
pg-cloudflare@1.1.1:
optional: true
pg-connection-string@2.6.4:
optional: true
pg-int8@1.0.1: {}
pg-numeric@1.0.2: {}
pg-pool@3.6.2(pg@8.12.0):
dependencies:
pg: 8.12.0
optional: true
pg-protocol@1.6.1: {}
pg-types@2.2.0:
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
optional: true
pg-types@4.0.2:
dependencies:
pg-int8: 1.0.1
pg-numeric: 1.0.2
postgres-array: 3.0.2
postgres-bytea: 3.0.0
postgres-date: 2.1.0
postgres-interval: 3.0.0
postgres-range: 1.1.4
pg@8.12.0:
dependencies:
pg-connection-string: 2.6.4
pg-pool: 3.6.2(pg@8.12.0)
pg-protocol: 1.6.1
pg-types: 2.2.0
pgpass: 1.0.5
optionalDependencies:
pg-cloudflare: 1.1.1
optional: true
pgpass@1.0.5:
dependencies:
split2: 4.2.0
optional: true
picocolors@1.0.1: {}
picomatch@2.3.1: {}
@@ -11971,6 +12134,34 @@ snapshots:
picocolors: 1.0.1
source-map-js: 1.2.0
postgres-array@2.0.0:
optional: true
postgres-array@3.0.2: {}
postgres-bytea@1.0.0:
optional: true
postgres-bytea@3.0.0:
dependencies:
obuf: 1.1.2
postgres-date@1.0.7:
optional: true
postgres-date@2.1.0: {}
postgres-interval@1.2.0:
dependencies:
xtend: 4.0.2
optional: true
postgres-interval@3.0.0: {}
postgres-range@1.1.4: {}
postgres@3.4.4: {}
potpack@2.0.0: {}
prebuild-install@7.1.2:
@@ -12516,6 +12707,9 @@ snapshots:
speakingurl@14.0.1: {}
split2@4.2.0:
optional: true
stable-hash@0.0.4: {}
stacktracey@2.1.8:

View File

@@ -1,10 +0,0 @@
import { useValidatedBody, z } from 'h3-zod'
export default defineEventHandler(async (event) => {
const users = await useDB().select().from(tables.users).all()
const { email } = await useValidatedBody(event, {
email: z.string(),
})
const user = users.find(user => user.email === email)
return !!user
})

View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const user = await getUserSession(event)
console.log('session', user)
return useDrizzle().query.categories.findMany({
where: eq(tables.users.id, user.id),
})
})

View File

@@ -1,7 +0,0 @@
CREATE TABLE `users`
(
`id` integer PRIMARY KEY NOT NULL,
`name` text DEFAULT '',
`email` text DEFAULT '',
`created_at` text DEFAULT (CURRENT_DATE)
);

View File

@@ -0,0 +1,73 @@
DO $$ BEGIN
CREATE TYPE "public"."subscription" AS ENUM('free', 'paid');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "categories" (
"id" serial PRIMARY KEY NOT NULL,
"name" text DEFAULT '' NOT NULL,
"name_visible" boolean DEFAULT true NOT NULL,
"icon" text DEFAULT 'i-ph:circle-wavy-question-duotone' NOT NULL,
"color" text DEFAULT 'gray' NOT NULL,
"page_id" integer NOT NULL,
"created_at" timestamp (3) DEFAULT now(),
"updated_at" timestamp (3)
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "pages" (
"id" serial PRIMARY KEY NOT NULL,
"user_id" integer NOT NULL,
"created_at" timestamp (3) DEFAULT now(),
"updated_at" timestamp (3)
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "tabs" (
"id" serial PRIMARY KEY NOT NULL,
"name" text DEFAULT '' NOT NULL,
"name_visible" boolean DEFAULT true NOT NULL,
"icon" text DEFAULT 'i-ph:circle-wavy-question-duotone' NOT NULL,
"color" text DEFAULT 'gray' NOT NULL,
"category_id" integer NOT NULL,
"created_at" timestamp (3) DEFAULT now(),
"updated_at" timestamp (3)
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users" (
"id" serial PRIMARY KEY NOT NULL,
"username" text NOT NULL,
"name" text NOT NULL,
"email" text NOT NULL,
"github_id" text,
"github_token" text,
"google_id" text,
"google_token" text,
"description" text DEFAULT '',
"private" boolean DEFAULT false NOT NULL,
"timezone" text DEFAULT 'undefined' NOT NULL,
"location" text DEFAULT 'undefined' NOT NULL,
"subscription" "subscription" DEFAULT 'free' NOT NULL,
"created_at" timestamp (3) DEFAULT now(),
"updated_at" timestamp (3),
CONSTRAINT "users_email_unique" UNIQUE("email"),
CONSTRAINT "users_github_id_unique" UNIQUE("github_id"),
CONSTRAINT "users_google_id_unique" UNIQUE("google_id")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "categories" ADD CONSTRAINT "categories_page_id_pages_id_fk" FOREIGN KEY ("page_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "pages" ADD CONSTRAINT "pages_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "tabs" ADD CONSTRAINT "tabs_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,4 @@
ALTER TABLE "categories" ALTER COLUMN "id" SET DATA TYPE integer;--> statement-breakpoint
ALTER TABLE "pages" ALTER COLUMN "id" SET DATA TYPE integer;--> statement-breakpoint
ALTER TABLE "tabs" ALTER COLUMN "id" SET DATA TYPE integer;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "id" SET DATA TYPE integer;

View File

@@ -1,2 +0,0 @@
ALTER TABLE `users`
ADD `description` text DEFAULT '';

View File

@@ -0,0 +1,13 @@
ALTER TABLE "categories" ALTER COLUMN "name" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "categories" ALTER COLUMN "name_visible" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "categories" ALTER COLUMN "icon" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "categories" ALTER COLUMN "color" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "tabs" ALTER COLUMN "name" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "tabs" ALTER COLUMN "name_visible" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "tabs" ALTER COLUMN "icon" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "tabs" ALTER COLUMN "color" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "private" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "timezone" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "location" SET DEFAULT 'unknown';--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "location" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "subscription" DROP NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE "users" ADD COLUMN "avatar" text DEFAULT '';

View File

@@ -0,0 +1,2 @@
ALTER TABLE "users" RENAME COLUMN "timezone" TO "language";--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "language" SET DEFAULT 'english';

View File

@@ -0,0 +1 @@
ALTER TABLE "users" ALTER COLUMN "language" SET DEFAULT 'en-EN';

View File

@@ -1,57 +1,357 @@
{
"version": "6",
"dialect": "sqlite",
"id": "a30470ea-8de9-4ff0-b0c9-d6b8a6264726",
"id": "a8ec7e1e-1087-4ab5-be19-459dc9b0a4e0",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"users": {
"name": "users",
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"type": "serial",
"primaryKey": true,
"notNull": true,
"autoincrement": false
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"notNull": true,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'gray'"
},
"page_id": {
"name": "page_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"categories_page_id_pages_id_fk": {
"name": "categories_page_id_pages_id_fk",
"tableFrom": "categories",
"tableTo": "pages",
"columnsFrom": [
"page_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.pages": {
"name": "pages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pages_user_id_users_id_fk": {
"name": "pages_user_id_users_id_fk",
"tableFrom": "pages",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.tabs": {
"name": "tabs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'gray'"
},
"category_id": {
"name": "category_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"tabs_category_id_categories_id_fk": {
"name": "tabs_category_id_categories_id_fk",
"tableFrom": "tabs",
"tableTo": "categories",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "''"
"notNull": true
},
"created_at": {
"name": "created_at",
"github_id": {
"name": "github_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"github_token": {
"name": "github_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_id": {
"name": "google_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_token": {
"name": "google_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_DATE)"
"default": "''"
},
"private": {
"name": "private",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'undefined'"
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'undefined'"
},
"subscription": {
"name": "subscription",
"type": "subscription",
"typeSchema": "public",
"primaryKey": false,
"notNull": true,
"default": "'free'"
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
},
"users_github_id_unique": {
"name": "users_github_id_unique",
"nullsNotDistinct": false,
"columns": [
"github_id"
]
},
"users_google_id_unique": {
"name": "users_google_id_unique",
"nullsNotDistinct": false,
"columns": [
"google_id"
]
}
}
}
},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
"enums": {
"public.subscription": {
"name": "subscription",
"schema": "public",
"values": [
"free",
"paid"
]
}
},
"internal": {
"indexes": {}
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -1,65 +1,357 @@
{
"version": "6",
"dialect": "sqlite",
"id": "77aafe70-876c-4c45-84d6-5261fa288bae",
"prevId": "a30470ea-8de9-4ff0-b0c9-d6b8a6264726",
"id": "0550ff2a-d819-4a38-a515-915d5ef620a6",
"prevId": "a8ec7e1e-1087-4ab5-be19-459dc9b0a4e0",
"version": "7",
"dialect": "postgresql",
"tables": {
"users": {
"name": "users",
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"notNull": true,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'gray'"
},
"page_id": {
"name": "page_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"categories_page_id_pages_id_fk": {
"name": "categories_page_id_pages_id_fk",
"tableFrom": "categories",
"tableTo": "pages",
"columnsFrom": [
"page_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.pages": {
"name": "pages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pages_user_id_users_id_fk": {
"name": "pages_user_id_users_id_fk",
"tableFrom": "pages",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.tabs": {
"name": "tabs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'gray'"
},
"category_id": {
"name": "category_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"tabs_category_id_categories_id_fk": {
"name": "tabs_category_id_categories_id_fk",
"tableFrom": "tabs",
"tableTo": "categories",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "''"
"notNull": true
},
"github_id": {
"name": "github_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"github_token": {
"name": "github_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_id": {
"name": "google_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_token": {
"name": "google_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "''"
},
"private": {
"name": "private",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'undefined'"
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'undefined'"
},
"subscription": {
"name": "subscription",
"type": "subscription",
"typeSchema": "public",
"primaryKey": false,
"notNull": true,
"default": "'free'"
},
"created_at": {
"name": "created_at",
"type": "text",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_DATE)"
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
},
"users_github_id_unique": {
"name": "users_github_id_unique",
"nullsNotDistinct": false,
"columns": [
"github_id"
]
},
"users_google_id_unique": {
"name": "users_google_id_unique",
"nullsNotDistinct": false,
"columns": [
"google_id"
]
}
}
}
},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
"enums": {
"public.subscription": {
"name": "subscription",
"schema": "public",
"values": [
"free",
"paid"
]
}
},
"internal": {
"indexes": {}
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,357 @@
{
"id": "7d4e591a-f6c7-48eb-b9e8-e0e200bfea26",
"prevId": "0550ff2a-d819-4a38-a515-915d5ef620a6",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"page_id": {
"name": "page_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"categories_page_id_pages_id_fk": {
"name": "categories_page_id_pages_id_fk",
"tableFrom": "categories",
"tableTo": "pages",
"columnsFrom": [
"page_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.pages": {
"name": "pages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pages_user_id_users_id_fk": {
"name": "pages_user_id_users_id_fk",
"tableFrom": "pages",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.tabs": {
"name": "tabs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"category_id": {
"name": "category_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"tabs_category_id_categories_id_fk": {
"name": "tabs_category_id_categories_id_fk",
"tableFrom": "tabs",
"tableTo": "categories",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"github_id": {
"name": "github_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"github_token": {
"name": "github_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_id": {
"name": "google_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_token": {
"name": "google_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"private": {
"name": "private",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'undefined'"
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'unknown'"
},
"subscription": {
"name": "subscription",
"type": "subscription",
"typeSchema": "public",
"primaryKey": false,
"notNull": false,
"default": "'free'"
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
},
"users_github_id_unique": {
"name": "users_github_id_unique",
"nullsNotDistinct": false,
"columns": [
"github_id"
]
},
"users_google_id_unique": {
"name": "users_google_id_unique",
"nullsNotDistinct": false,
"columns": [
"google_id"
]
}
}
}
},
"enums": {
"public.subscription": {
"name": "subscription",
"schema": "public",
"values": [
"free",
"paid"
]
}
},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,364 @@
{
"id": "d4ae60ba-5be1-4aa9-90d7-0690a599bf8e",
"prevId": "7d4e591a-f6c7-48eb-b9e8-e0e200bfea26",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"page_id": {
"name": "page_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"categories_page_id_pages_id_fk": {
"name": "categories_page_id_pages_id_fk",
"tableFrom": "categories",
"tableTo": "pages",
"columnsFrom": [
"page_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.pages": {
"name": "pages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pages_user_id_users_id_fk": {
"name": "pages_user_id_users_id_fk",
"tableFrom": "pages",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.tabs": {
"name": "tabs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"category_id": {
"name": "category_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"tabs_category_id_categories_id_fk": {
"name": "tabs_category_id_categories_id_fk",
"tableFrom": "tabs",
"tableTo": "categories",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"github_id": {
"name": "github_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"github_token": {
"name": "github_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_id": {
"name": "google_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_token": {
"name": "google_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"private": {
"name": "private",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'undefined'"
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'unknown'"
},
"subscription": {
"name": "subscription",
"type": "subscription",
"typeSchema": "public",
"primaryKey": false,
"notNull": false,
"default": "'free'"
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
},
"users_github_id_unique": {
"name": "users_github_id_unique",
"nullsNotDistinct": false,
"columns": [
"github_id"
]
},
"users_google_id_unique": {
"name": "users_google_id_unique",
"nullsNotDistinct": false,
"columns": [
"google_id"
]
}
}
}
},
"enums": {
"public.subscription": {
"name": "subscription",
"schema": "public",
"values": [
"free",
"paid"
]
}
},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,364 @@
{
"id": "704c03b2-8d7f-47ce-a551-95289048c5f2",
"prevId": "d4ae60ba-5be1-4aa9-90d7-0690a599bf8e",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"page_id": {
"name": "page_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"categories_page_id_pages_id_fk": {
"name": "categories_page_id_pages_id_fk",
"tableFrom": "categories",
"tableTo": "pages",
"columnsFrom": [
"page_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.pages": {
"name": "pages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pages_user_id_users_id_fk": {
"name": "pages_user_id_users_id_fk",
"tableFrom": "pages",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.tabs": {
"name": "tabs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"category_id": {
"name": "category_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"tabs_category_id_categories_id_fk": {
"name": "tabs_category_id_categories_id_fk",
"tableFrom": "tabs",
"tableTo": "categories",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"github_id": {
"name": "github_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"github_token": {
"name": "github_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_id": {
"name": "google_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_token": {
"name": "google_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"private": {
"name": "private",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"language": {
"name": "language",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'english'"
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'unknown'"
},
"subscription": {
"name": "subscription",
"type": "subscription",
"typeSchema": "public",
"primaryKey": false,
"notNull": false,
"default": "'free'"
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
},
"users_github_id_unique": {
"name": "users_github_id_unique",
"nullsNotDistinct": false,
"columns": [
"github_id"
]
},
"users_google_id_unique": {
"name": "users_google_id_unique",
"nullsNotDistinct": false,
"columns": [
"google_id"
]
}
}
}
},
"enums": {
"public.subscription": {
"name": "subscription",
"schema": "public",
"values": [
"free",
"paid"
]
}
},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,364 @@
{
"id": "e891a8e0-61c1-4351-90fe-caace29457a8",
"prevId": "704c03b2-8d7f-47ce-a551-95289048c5f2",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"page_id": {
"name": "page_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"categories_page_id_pages_id_fk": {
"name": "categories_page_id_pages_id_fk",
"tableFrom": "categories",
"tableTo": "pages",
"columnsFrom": [
"page_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.pages": {
"name": "pages",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pages_user_id_users_id_fk": {
"name": "pages_user_id_users_id_fk",
"tableFrom": "pages",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.tabs": {
"name": "tabs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"name_visible": {
"name": "name_visible",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": true
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'i-ph:circle-wavy-question-duotone'"
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'gray'"
},
"category_id": {
"name": "category_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"tabs_category_id_categories_id_fk": {
"name": "tabs_category_id_categories_id_fk",
"tableFrom": "tabs",
"tableTo": "categories",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"github_id": {
"name": "github_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"github_token": {
"name": "github_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_id": {
"name": "google_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"google_token": {
"name": "google_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "''"
},
"private": {
"name": "private",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"language": {
"name": "language",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'en-EN'"
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'unknown'"
},
"subscription": {
"name": "subscription",
"type": "subscription",
"typeSchema": "public",
"primaryKey": false,
"notNull": false,
"default": "'free'"
},
"created_at": {
"name": "created_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
},
"users_github_id_unique": {
"name": "users_github_id_unique",
"nullsNotDistinct": false,
"columns": [
"github_id"
]
},
"users_google_id_unique": {
"name": "users_google_id_unique",
"nullsNotDistinct": false,
"columns": [
"google_id"
]
}
}
}
},
"enums": {
"public.subscription": {
"name": "subscription",
"schema": "public",
"values": [
"free",
"paid"
]
}
},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -1,19 +1,47 @@
{
"version": "7",
"dialect": "sqlite",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "6",
"when": 1724341642346,
"tag": "0000_salty_thena",
"version": "7",
"when": 1724455773734,
"tag": "0000_wild_luke_cage",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1724343948344,
"tag": "0001_medical_joshua_kane",
"version": "7",
"when": 1724455851539,
"tag": "0001_goofy_dormammu",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1724456130150,
"tag": "0002_slim_whistler",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1724528975297,
"tag": "0003_curious_solo",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1724531645621,
"tag": "0004_sharp_shocker",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1724532003950,
"tag": "0005_tense_the_order",
"breakpoints": true
}
]

View File

@@ -1,10 +1,75 @@
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { sql } from 'drizzle-orm'
import { boolean, integer, pgEnum, pgTable, text } from 'drizzle-orm/pg-core'
import { relations } from 'drizzle-orm'
import { id, timestamps } from '../utils/dbFields'
import { Subscription } from '../../types/types'
export const users = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').default(''),
email: text('email').default(''),
export const subscriptionEnum = pgEnum('subscription', Subscription)
export const users = pgTable('users', {
id,
username: text('username').notNull(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
githubId: text('github_id').unique(),
githubToken: text('github_token'),
googleId: text('google_id').unique(),
googleToken: text('google_token'),
description: text('description').default(''),
createdAt: text('created_at').default(sql`(CURRENT_DATE)`),
avatar: text('avatar').default(''),
private: boolean('private').default(false),
language: text('language').default('en-EN'),
location: text('location').default('unknown'),
subscription: subscriptionEnum('subscription').default('free'),
...timestamps,
})
export const pages = pgTable('pages', {
id,
userId: integer('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
...timestamps,
})
export const categories = pgTable('categories', {
id,
name: text('name').default(''),
nameVisible: boolean('name_visible').default(true),
icon: text('icon').default('i-ph:circle-wavy-question-duotone'),
color: text('color').default('gray'),
pageId: integer('page_id')
.notNull()
.references(() => pages.id, { onDelete: 'cascade' }),
...timestamps,
})
export const tabs = pgTable('tabs', {
id,
name: text('name').default(''),
nameVisible: boolean('name_visible').default(true),
icon: text('icon').default('i-ph:circle-wavy-question-duotone'),
color: text('color').default('gray'),
categoryId: integer('category_id')
.notNull()
.references(() => categories.id, { onDelete: 'cascade' }),
...timestamps,
})
export const usersRelations = relations(users, ({ one }) => ({
page: one(pages, {
fields: [users.id],
references: [pages.userId],
}),
}))
export const pagesRelations = relations(pages, ({ many }) => ({
categories: many(categories),
}))
export const categoriesRelations = relations(categories, ({ one, many }) => ({
page: one(pages, {
fields: [categories.pageId],
references: [pages.id],
}),
tabs: many(tabs),
}))

View File

@@ -1,17 +0,0 @@
import { consola } from 'consola'
import { migrate } from 'drizzle-orm/d1/migrator'
export default defineNitroPlugin(async () => {
if (!import.meta.dev)
return
onHubReady(async () => {
await migrate(useDB(), { migrationsFolder: 'server/database/migrations' })
.then(() => {
consola.success('Database migrations done')
})
.catch((err) => {
consola.error('Database migrations failed', err)
})
})
})

View File

@@ -2,17 +2,85 @@ export default oauthGitHubEventHandler({
config: {
emailRequired: true,
},
async onSuccess(event, { user }) {
await setUserSession(event, {
user: {
email: user.email,
name: user.name,
},
async onSuccess(event, { user: oauthUser, tokens }) {
const userSession = await getUserSession(event)
// If the user is already signed in, link the account
if (userSession?.id) {
const user = await findUserById(userSession.id)
if (user) {
await updateUser(userSession.id, {
githubId: oauthUser.id,
githubToken: tokens.access_token,
})
return sendRedirect(event, '/home')
},
onError(event, error) {
console.error('GitHub OAuth error:', error)
await setUserSession(event, {
id: userSession.id,
user: userSession,
githubId: oauthUser.id,
})
return sendRedirect(event, '/')
}
}
// If the user is not signed in, search for an existing user with that GitHub ID
// If it exists, sign in as that user and refresh the token
let user = await findUserByGitHubId(oauthUser.id)
if (user) {
await updateUser(user.id, {
githubId: oauthUser.id,
githubToken: tokens.access_token,
})
await setUserSession(event, {
id: user.id,
user,
})
return sendRedirect(event, '/')
}
// If the user is not signed in, search for an existing user with that email address without a GitHub ID
// If it exists, tells the user to sign in with that account and link the GitHub account
user = await findUserBy(
and(
eq(tables.users.email, oauthUser.email),
isNull(tables.users.githubId),
),
)
if (user) {
await updateSession(event, {
password: useRuntimeConfig(event).session.password,
}, {
message: 'An existing account for this email already exists. Please login and visit your profile settings to add support for GitHub authentication.',
})
return sendRedirect(event, '/login')
}
// If the user is not signed in and no user exists with that GitHub ID or email address, create a new user
const createdUser = await createUser({
username: oauthUser.login as string,
description: oauthUser.bio as string,
name: oauthUser.name as string,
email: oauthUser.email as string,
avatar: oauthUser.avatar_url as string,
githubId: oauthUser.id as number,
githubToken: tokens.access_token as string,
language: 'en-US',
location: 'unknown',
private: false,
subscription: 'free',
})
await setUserSession(event, {
id: createdUser.id,
user: createdUser,
})
return sendRedirect(event, '/')
},
})

View File

@@ -2,17 +2,85 @@ export default oauthGoogleEventHandler({
config: {
emailRequired: true,
},
async onSuccess(event, { user }) {
await setUserSession(event, {
user: {
email: user.email,
name: user.name,
},
async onSuccess(event, { user: oauthUser, tokens }) {
const userSession = await getUserSession(event)
// If the user is already signed in, link the account
if (userSession?.id) {
const user = await findUserById(userSession.id)
if (user) {
await updateUser(userSession.id, {
googleId: oauthUser.sub,
googleToken: tokens.access_token,
})
return sendRedirect(event, '/home')
},
onError(event, error) {
console.error('Google OAuth error:', error)
await replaceUserSession(event, {
id: userSession.id,
user: userSession,
googleId: oauthUser.sub,
})
return sendRedirect(event, '/')
}
}
// If the user is not signed in, search for an existing user with that Google ID
// If it exists, sign in as that user and refresh the token
let user = await findUserByGoogleId(oauthUser.sub)
if (user) {
await updateUser(user.id, {
googleId: oauthUser.sub,
googleToken: tokens.access_token,
})
await replaceUserSession(event, {
id: user.id,
user,
})
return sendRedirect(event, '/')
}
// If the user is not signed in, search for an existing user with that email address without a Google ID
// If it exists, tells the user to sign in with that account and link the Google account
user = await findUserBy(
and(
eq(tables.users.email, oauthUser.email),
isNull(tables.users.googleId),
),
)
if (user) {
await updateSession(event, {
password: useRuntimeConfig(event).session.password,
}, {
message: 'An existing account for this email already exists. Please login and visit your profile settings to add support for Google authentication.',
})
return sendRedirect(event, '/login')
}
// If the user is not signed in and no user exists with that Google ID or email address, create a new user
const createdUser = await createUser({
username: oauthUser.name as string,
description: '',
name: `${oauthUser.given_name} ${oauthUser.family_name}`,
email: oauthUser.email as string,
avatar: oauthUser.picture as string,
googleId: oauthUser.sub as number,
googleToken: tokens.access_token as string,
language: 'en-US',
location: 'unknown',
private: false,
subscription: 'free',
})
await replaceUserSession(event, {
id: createdUser.id,
user: createdUser,
})
return sendRedirect(event, '/')
},
})

View File

@@ -0,0 +1,5 @@
export default eventHandler(async (event) => {
const { pathname } = getRouterParams(event)
return hubBlob().serve(event, pathname)
})

View File

@@ -1,10 +1,18 @@
import { drizzle } from 'drizzle-orm/d1'
import postgres from 'postgres'
import { drizzle } from 'drizzle-orm/postgres-js'
import * as schema from '../database/schema'
export { sql, eq, and, or, asc, desc, sum } from 'drizzle-orm'
export { sql, eq, and, or, asc, desc, sum, isNull } from 'drizzle-orm'
export const tables = schema
export function useDB() {
return drizzle(hubDatabase(), { schema })
export function useDrizzle() {
const config = useRuntimeConfig()
return drizzle(postgres(config.postgres.url, { prepare: false }), { schema })
}
export type UserType = typeof schema.users.$inferSelect
export type UserInsert = typeof schema.users.$inferInsert
export type TabType = typeof schema.tabs.$inferSelect
export type CategoryType = typeof schema.categories.$inferSelect

20
server/utils/dbFields.ts Normal file
View File

@@ -0,0 +1,20 @@
import * as pg from 'drizzle-orm/pg-core'
/**
* A centralized list of standardized Drizzle ORM schema field definitions to prevent duplication errors
*/
export const createdAt = pg
.timestamp('created_at', { mode: 'date', precision: 3 })
.defaultNow()
export const updatedAt = pg
.timestamp('updated_at', { mode: 'date', precision: 3 })
.$onUpdate(() => new Date())
export const id = pg.integer('id').primaryKey({ autoIncrement: true })
export const timestamps = {
createdAt,
updatedAt,
}

58
server/utils/users.ts Normal file
View File

@@ -0,0 +1,58 @@
import type { SQL } from 'drizzle-orm'
import type { UserInsert } from '~~/server/utils/db'
export async function findUserById(userId: number) {
return useDrizzle()
.query
.users
.findFirst({
where: eq(tables.users.id, userId),
})
}
export async function findUserByGitHubId(githubId: number) {
return useDrizzle()
.query
.users
.findFirst({
where: eq(tables.users.githubId, githubId),
})
}
export async function findUserByGoogleId(googleId: string) {
return useDrizzle()
.query
.users
.findFirst({
where: eq(tables.users.googleId, googleId),
})
}
export async function findUserBy(query: SQL | undefined) {
return useDrizzle()
.query
.users
.findFirst({
where: query,
})
}
export async function createUser(user: UserInsert) {
return useDrizzle()
.insert(tables.users)
.values(user)
.returning()
}
export async function updateUser(userId: number, user: Partial<UserInsert>) {
return useDrizzle()
.update(tables.users)
.set(user)
.where(eq(tables.users.id, userId))
}
export async function deleteProfilePicture(avatar: string) {
if (avatar.startsWith('profile-pictures/')) {
await hubBlob().delete(avatar)
}
}

26
types/auth.d.ts vendored
View File

@@ -1,13 +1,35 @@
// auth.d.ts
import type { Subscription } from '~~/types/types'
declare module '#auth-utils' {
interface User {
email: string
id: number
name: string
username: string
email: string
avatar: string | null
githubId?: number | null
googleId?: string | null
description: string
private: boolean
language: string
location: string
subscription: Subscription
}
interface UserSession {
email: string
id: number
name: string
username: string
email: string
avatar: string | null
githubId?: number | null
googleId?: string | null
description: string
private: boolean
language: string
location: string
subscription: Subscription
}
}

View File

@@ -1,5 +1,8 @@
import type { ParsedContent } from '@nuxt/content'
export const Subscription = ['free', 'paid'] as const
// todo: delete
export interface AppType extends ParsedContent {
primary?: boolean
name: string