phase 1
This commit is contained in:
parent
6f5313f990
commit
dd5255ba69
15 changed files with 80 additions and 78 deletions
|
|
@ -1,7 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<UApp>
|
<NuxtLayout>
|
||||||
<NuxtLayout>
|
<NuxtPage />
|
||||||
<NuxtPage />
|
</NuxtLayout>
|
||||||
</NuxtLayout>
|
|
||||||
</UApp>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "@nuxt/ui";
|
@import "@nuxt/ui";
|
||||||
|
|
||||||
|
@source "../../pages/admin";
|
||||||
|
@source "../../components/admin";
|
||||||
|
@source "../../layouts/admin.vue";
|
||||||
|
|
||||||
@theme static {
|
@theme static {
|
||||||
--font-sans: 'Public Sans', sans-serif;
|
--font-sans: 'Public Sans', sans-serif;
|
||||||
|
|
||||||
6
app/assets/styles/main.scss
Normal file
6
app/assets/styles/main.scss
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Public site stylesheet entry point.
|
||||||
|
// Phase 1 will `@use` the ported CUBE CSS partials here
|
||||||
|
// (tokens, base/reset, composition, blocks, utilities).
|
||||||
|
//
|
||||||
|
// For Phase 0 this is intentionally empty so the public layout
|
||||||
|
// has something to import without producing CSS.
|
||||||
|
|
@ -25,8 +25,9 @@ watch(() => route.path, () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen bg-(--ui-bg) text-(--ui-text)">
|
<UApp>
|
||||||
<!-- Mobile top bar -->
|
<div class="min-h-screen bg-(--ui-bg) text-(--ui-text)">
|
||||||
|
<!-- Mobile top bar -->
|
||||||
<header class="lg:hidden bg-(--ui-bg-elevated) border-b border-(--ui-border) py-3 px-4 sticky top-0 z-40 flex items-center justify-between">
|
<header class="lg:hidden bg-(--ui-bg-elevated) border-b border-(--ui-border) py-3 px-4 sticky top-0 z-40 flex items-center justify-between">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<UButton
|
<UButton
|
||||||
|
|
@ -126,4 +127,7 @@ watch(() => route.path, () => {
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</UApp>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style src="~/assets/css/admin.css"></style>
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,5 @@
|
||||||
<script setup lang="ts">
|
|
||||||
const { user } = useAuth()
|
|
||||||
const config = useRuntimeConfig()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen bg-(--ui-bg) text-(--ui-text)">
|
<slot />
|
||||||
<header class="bg-(--ui-bg-elevated) border-b border-(--ui-border) py-4 sticky top-0 z-50">
|
|
||||||
<div class="max-w-7xl mx-auto px-4 flex justify-between items-center">
|
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<slot name="header-left">
|
|
||||||
<NuxtLink to="/" class="text-xl font-semibold hover:text-(--ui-text-muted) transition-colors">
|
|
||||||
{{ config.public.appName }}
|
|
||||||
</NuxtLink>
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<slot name="header-right">
|
|
||||||
<span class="text-(--ui-text-muted) text-sm hidden sm:inline">
|
|
||||||
{{ user?.display_name || user?.email }}
|
|
||||||
</span>
|
|
||||||
<UButton to="/profile" variant="ghost" size="sm">
|
|
||||||
Profile
|
|
||||||
</UButton>
|
|
||||||
<ThemeToggle />
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main class="max-w-7xl mx-auto px-4 py-8">
|
|
||||||
<slot />
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" src="~/assets/styles/main.scss"></style>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
|
layout: 'admin',
|
||||||
middleware: 'auth'
|
middleware: 'auth'
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,11 @@
|
||||||
<script setup lang="ts">
|
|
||||||
definePageMeta({
|
|
||||||
layout: false
|
|
||||||
})
|
|
||||||
|
|
||||||
const { isLoggedIn } = useAuth()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen bg-(--ui-bg)">
|
<div style="padding: 2rem; font-family: system-ui, sans-serif;">
|
||||||
<div class="flex justify-end p-4">
|
<h1>Doxa</h1>
|
||||||
<ThemeToggle />
|
<p>
|
||||||
</div>
|
Marketing-rebuild scaffold. The real homepage is ported in Phase 3.
|
||||||
<div class="text-center py-16 px-4">
|
</p>
|
||||||
<h1 class="text-4xl font-bold text-(--ui-text) mb-4">Welcome</h1>
|
<p>
|
||||||
<p class="text-(--ui-text-muted) mb-8 max-w-lg mx-auto">
|
<a href="/admin">Admin →</a>
|
||||||
Get started by customizing this page.
|
</p>
|
||||||
</p>
|
|
||||||
<div v-if="!isLoggedIn" class="flex items-center justify-center gap-3">
|
|
||||||
<UButton to="/login" size="lg">
|
|
||||||
Sign in
|
|
||||||
</UButton>
|
|
||||||
<UButton to="/register" size="lg" variant="outline">
|
|
||||||
Create an account
|
|
||||||
</UButton>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<UButton to="/dashboard" size="lg">
|
|
||||||
Go to dashboard
|
|
||||||
</UButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
|
layout: 'admin',
|
||||||
middleware: 'auth'
|
middleware: 'auth'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
9
bun.lock
9
bun.lock
|
|
@ -27,6 +27,7 @@
|
||||||
"@types/nodemailer": "^7.0.1",
|
"@types/nodemailer": "^7.0.1",
|
||||||
"@types/nodemailer-mailgun-transport": "^1.4.6",
|
"@types/nodemailer-mailgun-transport": "^1.4.6",
|
||||||
"eslint": "^10.2.0",
|
"eslint": "^10.2.0",
|
||||||
|
"sass": "^1.99.0",
|
||||||
"typescript": "^6.0.2",
|
"typescript": "^6.0.2",
|
||||||
"vue-tsc": "^3.2.6",
|
"vue-tsc": "^3.2.6",
|
||||||
},
|
},
|
||||||
|
|
@ -1455,6 +1456,8 @@
|
||||||
|
|
||||||
"image-meta": ["image-meta@0.2.2", "", {}, "sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA=="],
|
"image-meta": ["image-meta@0.2.2", "", {}, "sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA=="],
|
||||||
|
|
||||||
|
"immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="],
|
||||||
|
|
||||||
"impound": ["impound@1.1.5", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "es-module-lexer": "2.0.0", "pathe": "2.0.3", "unplugin": "3.0.0", "unplugin-utils": "0.3.1" } }, "sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA=="],
|
"impound": ["impound@1.1.5", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "es-module-lexer": "2.0.0", "pathe": "2.0.3", "unplugin": "3.0.0", "unplugin-utils": "0.3.1" } }, "sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA=="],
|
||||||
|
|
||||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||||
|
|
@ -1949,6 +1952,8 @@
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
|
"sass": ["sass@1.99.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q=="],
|
||||||
|
|
||||||
"sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
|
"sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
|
||||||
|
|
||||||
"scslre": ["scslre@0.3.0", "", { "dependencies": { "@eslint-community/regexpp": "4.12.2", "refa": "0.12.1", "regexp-ast-analysis": "0.7.1" } }, "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ=="],
|
"scslre": ["scslre@0.3.0", "", { "dependencies": { "@eslint-community/regexpp": "4.12.2", "refa": "0.12.1", "regexp-ast-analysis": "0.7.1" } }, "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ=="],
|
||||||
|
|
@ -2369,6 +2374,8 @@
|
||||||
|
|
||||||
"rollup-plugin-visualizer/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "5.5.0", "define-lazy-prop": "3.0.0", "is-in-ssh": "1.0.0", "is-inside-container": "1.0.0", "powershell-utils": "0.1.0", "wsl-utils": "0.3.1" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
|
"rollup-plugin-visualizer/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "5.5.0", "define-lazy-prop": "3.0.0", "is-in-ssh": "1.0.0", "is-inside-container": "1.0.0", "powershell-utils": "0.1.0", "wsl-utils": "0.3.1" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
|
||||||
|
|
||||||
|
"sass/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "4.1.2" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||||
|
|
||||||
"send/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
"send/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
||||||
|
|
||||||
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||||
|
|
@ -2457,6 +2464,8 @@
|
||||||
|
|
||||||
"rollup-plugin-visualizer/open/wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "3.1.1", "powershell-utils": "0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="],
|
"rollup-plugin-visualizer/open/wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "3.1.1", "powershell-utils": "0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="],
|
||||||
|
|
||||||
|
"sass/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||||
|
|
||||||
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,39 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||||
|
|
||||||
|
// Guardrail: Nuxt UI components (`<U*>`) and their CSS only load inside the
|
||||||
|
// admin layout. Using a `<U*>` component on a public page would render
|
||||||
|
// unstyled because `admin.css` isn't imported there. This rule blocks that
|
||||||
|
// at lint time. Admin pages/components are exempt via overrides below.
|
||||||
|
const forbidNuxtUI = {
|
||||||
|
rules: {
|
||||||
|
'vue/no-restricted-syntax': ['error', {
|
||||||
|
selector: "VElement[rawName=/^U[A-Z]/]",
|
||||||
|
message: 'Nuxt UI components (<U*>) are only allowed inside app/pages/admin/** and app/components/admin/**. Public pages must use ported SCSS components.'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default withNuxt(
|
export default withNuxt(
|
||||||
// Your custom configs here
|
{
|
||||||
|
files: ['app/pages/**/*.vue', 'app/components/**/*.vue', 'app/layouts/**/*.vue'],
|
||||||
|
...forbidNuxtUI
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'app/pages/admin/**/*.vue',
|
||||||
|
'app/components/admin/**/*.vue',
|
||||||
|
'app/components/ThemeToggle.vue',
|
||||||
|
'app/layouts/admin.vue',
|
||||||
|
'app/layouts/auth.vue',
|
||||||
|
'app/pages/login.vue',
|
||||||
|
'app/pages/register.vue',
|
||||||
|
'app/pages/reset-password.vue',
|
||||||
|
'app/pages/dashboard.vue',
|
||||||
|
'app/pages/profile.vue'
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'vue/no-restricted-syntax': 'off'
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ export default defineNuxtConfig({
|
||||||
|
|
||||||
ssr: false,
|
ssr: false,
|
||||||
|
|
||||||
css: ['~/assets/css/main.css'],
|
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
theme: {
|
theme: {
|
||||||
colors: ['primary', 'secondary', 'info', 'success', 'warning', 'error', 'neutral']
|
colors: ['primary', 'secondary', 'info', 'success', 'warning', 'error', 'neutral']
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
"@types/nodemailer": "^7.0.1",
|
"@types/nodemailer": "^7.0.1",
|
||||||
"@types/nodemailer-mailgun-transport": "^1.4.6",
|
"@types/nodemailer-mailgun-transport": "^1.4.6",
|
||||||
"eslint": "^10.2.0",
|
"eslint": "^10.2.0",
|
||||||
|
"sass": "^1.99.0",
|
||||||
"typescript": "^6.0.2",
|
"typescript": "^6.0.2",
|
||||||
"vue-tsc": "^3.2.6"
|
"vue-tsc": "^3.2.6"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export default defineEventHandler(async (event) => {
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.where('token', '=', sanitizedToken)
|
.where('token', '=', sanitizedToken)
|
||||||
.where('used', '=', false)
|
.where('used', '=', false)
|
||||||
.where('expires', '>', new Date().toISOString())
|
.where('expires', '>', new Date())
|
||||||
.executeTakeFirst()
|
.executeTakeFirst()
|
||||||
|
|
||||||
if (!resetRequest) {
|
if (!resetRequest) {
|
||||||
|
|
@ -72,7 +72,7 @@ export default defineEventHandler(async (event) => {
|
||||||
.where((eb) =>
|
.where((eb) =>
|
||||||
eb.or([
|
eb.or([
|
||||||
eb('used', '=', true),
|
eb('used', '=', true),
|
||||||
eb('expires', '<=', new Date().toISOString()),
|
eb('expires', '<=', new Date()),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.execute()
|
.execute()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { db } from './database'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import type { Kysely } from 'kysely'
|
import type { Kysely } from 'kysely'
|
||||||
import type { Database } from '~/server/database/schema'
|
import type { Database } from '../database/schema'
|
||||||
import { getAuthUser } from './auth'
|
import { getAuthUser } from './auth'
|
||||||
|
|
||||||
interface LogEventOptions {
|
interface LogEventOptions {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Kysely, sql } from 'kysely'
|
import { Kysely, sql } from 'kysely'
|
||||||
import { PostgresJSDialect } from 'kysely-postgres-js'
|
import { PostgresJSDialect } from 'kysely-postgres-js'
|
||||||
import postgres from 'postgres'
|
import postgres from 'postgres'
|
||||||
import type { Database } from '~/server/database/schema'
|
import type { Database } from '../database/schema'
|
||||||
|
|
||||||
let _db: Kysely<Database> | null = null
|
let _db: Kysely<Database> | null = null
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue