@plutocms/supabase 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/nuxt/GENERATION.md +5 -0
- package/.agents/skills/nuxt/SKILL.md +55 -0
- package/.agents/skills/nuxt/references/advanced-hooks.md +289 -0
- package/.agents/skills/nuxt/references/advanced-layers.md +299 -0
- package/.agents/skills/nuxt/references/advanced-module-authoring.md +554 -0
- package/.agents/skills/nuxt/references/best-practices-data-fetching.md +357 -0
- package/.agents/skills/nuxt/references/best-practices-ssr.md +355 -0
- package/.agents/skills/nuxt/references/core-cli.md +263 -0
- package/.agents/skills/nuxt/references/core-config.md +162 -0
- package/.agents/skills/nuxt/references/core-data-fetching.md +236 -0
- package/.agents/skills/nuxt/references/core-deployment.md +224 -0
- package/.agents/skills/nuxt/references/core-directory-structure.md +269 -0
- package/.agents/skills/nuxt/references/core-modules.md +292 -0
- package/.agents/skills/nuxt/references/core-routing.md +226 -0
- package/.agents/skills/nuxt/references/features-components-autoimport.md +328 -0
- package/.agents/skills/nuxt/references/features-components.md +264 -0
- package/.agents/skills/nuxt/references/features-composables.md +276 -0
- package/.agents/skills/nuxt/references/features-server.md +265 -0
- package/.agents/skills/nuxt/references/features-state.md +194 -0
- package/.agents/skills/nuxt/references/rendering-modes.md +237 -0
- package/.agents/skills/nuxt-ui/SKILL.md +334 -0
- package/.agents/skills/nuxt-ui/references/components.md +377 -0
- package/.agents/skills/nuxt-ui/references/composables.md +127 -0
- package/.agents/skills/nuxt-ui/references/layouts/chat.md +195 -0
- package/.agents/skills/nuxt-ui/references/layouts/dashboard.md +220 -0
- package/.agents/skills/nuxt-ui/references/layouts/docs.md +141 -0
- package/.agents/skills/nuxt-ui/references/layouts/editor.md +167 -0
- package/.agents/skills/nuxt-ui/references/layouts/page.md +260 -0
- package/.agents/skills/nuxt-ui/references/theming.md +427 -0
- package/.agents/skills/supabase-postgres-best-practices/AGENTS.md +68 -0
- package/.agents/skills/supabase-postgres-best-practices/CLAUDE.md +1 -0
- package/.agents/skills/supabase-postgres-best-practices/README.md +116 -0
- package/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
- package/.editorconfig +12 -0
- package/.env.example +2 -0
- package/.eslintignore +1 -0
- package/.prettierrc +9 -0
- package/.vscode/extensions.json +10 -0
- package/.vscode/settings.json +61 -0
- package/README.md +62 -0
- package/app/components/navbar/NavbarAdmin.vue +169 -0
- package/app/composables/auth.ts +81 -0
- package/app/layouts/setup.vue +13 -0
- package/app/middleware/auth.ts +27 -0
- package/app/middleware/setup-check.ts +25 -0
- package/app/pages/admin/(auth)/login.vue +84 -0
- package/app/pages/admin/(auth)/signup.vue +128 -0
- package/app/pages/admin/settings.vue +116 -0
- package/app/pages/admin/setup.vue +300 -0
- package/app/pages/admin.vue +38 -0
- package/bun.lock +2685 -0
- package/eslint.config.mjs +88 -0
- package/nuxt.config.ts +55 -0
- package/package.json +44 -0
- package/public/schema.sql +103 -0
- package/scripts/supabase-typegen.ts +36 -0
- package/server/api/category/list.get.ts +9 -0
- package/server/api/category/new.post.ts +31 -0
- package/server/api/settings/first_setup.get.ts +39 -0
- package/server/api/settings/index.get.ts +27 -0
- package/server/api/settings/update.post.ts +36 -0
- package/server/api/setup/create.post.ts +58 -0
- package/server/api/signup.post.ts +28 -0
- package/server/api/users/[id].get.ts +21 -0
- package/server/api/users/index.get.ts +16 -0
- package/shared/types/supabase.ts +406 -0
- package/skills-lock.json +20 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { StepperItem } from '@nuxt/ui'
|
|
3
|
+
|
|
4
|
+
definePageMeta({
|
|
5
|
+
middleware: ['setup-check'],
|
|
6
|
+
layout: 'setup',
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
useHead({
|
|
10
|
+
title: 'Setup Wizard',
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const config = useRuntimeConfig()
|
|
14
|
+
const projectId = config.public.supabase.url
|
|
15
|
+
?.split('https://')[1]
|
|
16
|
+
?.split('.')[0]
|
|
17
|
+
|
|
18
|
+
const toast = useToast()
|
|
19
|
+
|
|
20
|
+
const items = ref<StepperItem[]>([
|
|
21
|
+
{
|
|
22
|
+
title: 'Database Setup',
|
|
23
|
+
icon: 'i-lucide-database',
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/* {
|
|
27
|
+
title: 'Admin Account',
|
|
28
|
+
icon: 'i-lucide-user',
|
|
29
|
+
}, */
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
title: 'Complete Setup',
|
|
33
|
+
icon: 'i-lucide-check',
|
|
34
|
+
},
|
|
35
|
+
])
|
|
36
|
+
|
|
37
|
+
const stepper = useTemplateRef('stepper')
|
|
38
|
+
|
|
39
|
+
const currentStep = ref<number>(0)
|
|
40
|
+
|
|
41
|
+
const isSettingUpDatabase = ref(false)
|
|
42
|
+
|
|
43
|
+
const databaseForm = ref({
|
|
44
|
+
connectionString: '',
|
|
45
|
+
password: '',
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const currentLoading = computed(() => {
|
|
49
|
+
if (currentStep.value === 0) {
|
|
50
|
+
return isSettingUpDatabase.value
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return false
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const currentStepId = computed(() => {
|
|
57
|
+
if (currentStep.value === 0) {
|
|
58
|
+
return 'database-setup-form'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return undefined
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
async function completeSetup() {
|
|
65
|
+
try {
|
|
66
|
+
isSettingUpDatabase.value = true
|
|
67
|
+
|
|
68
|
+
const data = await $fetch<any>('/api/setup/create', {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
body: {
|
|
71
|
+
baseUrl: window.location.origin,
|
|
72
|
+
connectionString: databaseForm.value.connectionString.replace(
|
|
73
|
+
'[YOUR-PASSWORD]',
|
|
74
|
+
encodeURIComponent(databaseForm.value.password)
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if (data.success === false) {
|
|
80
|
+
toast.add({
|
|
81
|
+
title: 'Database setup failed',
|
|
82
|
+
description: 'Please check your password and try again.',
|
|
83
|
+
icon: 'lucide:circle-x',
|
|
84
|
+
color: 'error',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
toast.add({
|
|
91
|
+
title: 'Database setup complete',
|
|
92
|
+
description: 'Your database has been set up successfully.',
|
|
93
|
+
icon: 'lucide:check-circle',
|
|
94
|
+
color: 'success',
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
stepper.value?.next()
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (import.meta.dev) {
|
|
100
|
+
console.error('Error setting up the database:', error)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
toast.add({
|
|
104
|
+
title: 'Error setting up the database',
|
|
105
|
+
description: 'Please check the console for more details.',
|
|
106
|
+
icon: 'lucide:circle-x',
|
|
107
|
+
color: 'error',
|
|
108
|
+
})
|
|
109
|
+
} finally {
|
|
110
|
+
isSettingUpDatabase.value = false
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function handleStepChange(step: number) {
|
|
115
|
+
if (step === 1) {
|
|
116
|
+
completeSetup()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<template>
|
|
122
|
+
<UApp>
|
|
123
|
+
<div class="flex justify-center items-center h-screen">
|
|
124
|
+
<UCard class="w-[500px]">
|
|
125
|
+
<div class="flex flex-col gap-y-8">
|
|
126
|
+
<UStepper
|
|
127
|
+
ref="stepper"
|
|
128
|
+
v-model="currentStep"
|
|
129
|
+
:items="items"
|
|
130
|
+
disabled
|
|
131
|
+
linear
|
|
132
|
+
/>
|
|
133
|
+
|
|
134
|
+
<div>
|
|
135
|
+
<section v-if="currentStep === 0">
|
|
136
|
+
<UForm
|
|
137
|
+
id="database-setup-form"
|
|
138
|
+
class="flex flex-col gap-y-4"
|
|
139
|
+
@submit="handleStepChange(currentStep + 1)"
|
|
140
|
+
>
|
|
141
|
+
<UFormField label="Supabase connection string" required>
|
|
142
|
+
<UInput
|
|
143
|
+
v-model="databaseForm.connectionString"
|
|
144
|
+
:disabled="isSettingUpDatabase"
|
|
145
|
+
placeholder="postgresql://"
|
|
146
|
+
autofocus
|
|
147
|
+
required
|
|
148
|
+
/>
|
|
149
|
+
|
|
150
|
+
<template #help>
|
|
151
|
+
You can find your connection string
|
|
152
|
+
<ULink
|
|
153
|
+
:to="`https://supabase.com/dashboard/project/${projectId}/database/settings?showConnect=true&method=transaction`"
|
|
154
|
+
target="_blank"
|
|
155
|
+
class="underline"
|
|
156
|
+
external
|
|
157
|
+
>
|
|
158
|
+
clicking here </ULink
|
|
159
|
+
>.
|
|
160
|
+
</template>
|
|
161
|
+
</UFormField>
|
|
162
|
+
|
|
163
|
+
<UFormField label="Database password" required>
|
|
164
|
+
<UInput
|
|
165
|
+
v-model="databaseForm.password"
|
|
166
|
+
:disabled="isSettingUpDatabase"
|
|
167
|
+
type="password"
|
|
168
|
+
placeholder="• • • • •"
|
|
169
|
+
required
|
|
170
|
+
/>
|
|
171
|
+
</UFormField>
|
|
172
|
+
|
|
173
|
+
<UAlert
|
|
174
|
+
color="secondary"
|
|
175
|
+
icon="lucide:badge-info"
|
|
176
|
+
variant="outline"
|
|
177
|
+
>
|
|
178
|
+
<template #description>
|
|
179
|
+
Your password is created when you create your Supabase
|
|
180
|
+
project. You can change it in the
|
|
181
|
+
<ULink
|
|
182
|
+
to="https://supabase.com/dashboard/project/_/database/settings"
|
|
183
|
+
target="_blank"
|
|
184
|
+
>
|
|
185
|
+
Supabase Database Settings </ULink
|
|
186
|
+
>.
|
|
187
|
+
</template>
|
|
188
|
+
</UAlert>
|
|
189
|
+
|
|
190
|
+
<UAlert
|
|
191
|
+
color="warning"
|
|
192
|
+
variant="outline"
|
|
193
|
+
title="Why do I need to provide a database password?"
|
|
194
|
+
icon="lucide:info"
|
|
195
|
+
>
|
|
196
|
+
<template #description>
|
|
197
|
+
<div class="flex flex-col gap-y-4">
|
|
198
|
+
<p>
|
|
199
|
+
It will be used to create your database structure. It
|
|
200
|
+
won't be stored anywhere. That's a
|
|
201
|
+
<UTooltip
|
|
202
|
+
text="Click on the 'Technical details' button for more info"
|
|
203
|
+
>
|
|
204
|
+
<span class="underline decoration-dotted cursor-help">
|
|
205
|
+
promise</span
|
|
206
|
+
></UTooltip
|
|
207
|
+
>! 😉
|
|
208
|
+
</p>
|
|
209
|
+
|
|
210
|
+
<div>
|
|
211
|
+
<UPopover :content="{ side: 'right' }" arrow>
|
|
212
|
+
<UButton
|
|
213
|
+
icon="lucide:lightbulb"
|
|
214
|
+
label="Technical details"
|
|
215
|
+
color="info"
|
|
216
|
+
variant="subtle"
|
|
217
|
+
class="w-fit"
|
|
218
|
+
size="sm"
|
|
219
|
+
/>
|
|
220
|
+
|
|
221
|
+
<template #content>
|
|
222
|
+
<div
|
|
223
|
+
class="flex flex-col gap-y-4 max-w-xs p-4 text-white text-sm"
|
|
224
|
+
>
|
|
225
|
+
<p>
|
|
226
|
+
When you click "Next", a request to
|
|
227
|
+
<ULink
|
|
228
|
+
to="https://github.com/plutocms/supabase/blob/feat/setup-wizard/server/api/setup/create.post.ts"
|
|
229
|
+
target="_blank"
|
|
230
|
+
class="underline"
|
|
231
|
+
>
|
|
232
|
+
a server route</ULink
|
|
233
|
+
>
|
|
234
|
+
will be made with the database password you
|
|
235
|
+
provided. This API will then use this password
|
|
236
|
+
to make a direct PostgreSQL connection to your
|
|
237
|
+
Supabase database and run the SQL queries from
|
|
238
|
+
this
|
|
239
|
+
<ULink
|
|
240
|
+
to="https://github.com/plutocms/supabase/blob/feat/setup-wizard/public/schema.sql"
|
|
241
|
+
target="_blank"
|
|
242
|
+
class="underline"
|
|
243
|
+
>
|
|
244
|
+
SQL file</ULink
|
|
245
|
+
>.
|
|
246
|
+
</p>
|
|
247
|
+
|
|
248
|
+
<p>
|
|
249
|
+
After the setup is complete, the password will
|
|
250
|
+
NOT be stored or used for any other purpose.
|
|
251
|
+
</p>
|
|
252
|
+
</div>
|
|
253
|
+
</template>
|
|
254
|
+
</UPopover>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</template>
|
|
258
|
+
</UAlert>
|
|
259
|
+
</UForm>
|
|
260
|
+
</section>
|
|
261
|
+
|
|
262
|
+
<section v-else-if="currentStep === 1">
|
|
263
|
+
<div class="flex flex-col gap-y-4">
|
|
264
|
+
<h1 class="text-2xl font-bold text-center">
|
|
265
|
+
Setup Complete 🎉
|
|
266
|
+
</h1>
|
|
267
|
+
|
|
268
|
+
<p>
|
|
269
|
+
Your database has been set up successfully! 🎉 You can now log
|
|
270
|
+
in to the admin panel using your Supabase credentials.
|
|
271
|
+
</p>
|
|
272
|
+
|
|
273
|
+
<p class="text-center">
|
|
274
|
+
<ULink to="/admin/login" class="underline">
|
|
275
|
+
Go to login page</ULink
|
|
276
|
+
>
|
|
277
|
+
</p>
|
|
278
|
+
</div>
|
|
279
|
+
</section>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div class="flex justify-end">
|
|
283
|
+
<div>
|
|
284
|
+
<UButton
|
|
285
|
+
v-if="stepper?.hasNext"
|
|
286
|
+
:form="currentStepId"
|
|
287
|
+
:loading="currentLoading"
|
|
288
|
+
leading-icon="lucide:check"
|
|
289
|
+
trailing-icon="lucide:arrow-right"
|
|
290
|
+
type="submit"
|
|
291
|
+
>
|
|
292
|
+
Submit and continue
|
|
293
|
+
</UButton>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
</UCard>
|
|
298
|
+
</div>
|
|
299
|
+
</UApp>
|
|
300
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
definePageMeta({
|
|
3
|
+
middleware: ['setup-check', 'auth'],
|
|
4
|
+
layout: 'admin',
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
const route = useRoute()
|
|
8
|
+
const { isLoggedIn, logout } = await useAuth()
|
|
9
|
+
const toast = useToast()
|
|
10
|
+
|
|
11
|
+
const visibility = useDocumentVisibility()
|
|
12
|
+
|
|
13
|
+
watch(visibility, async (current, previous) => {
|
|
14
|
+
if (current === 'visible' && previous === 'hidden') {
|
|
15
|
+
if (
|
|
16
|
+
!isLoggedIn.value &&
|
|
17
|
+
route.path.startsWith('/admin/') &&
|
|
18
|
+
route.path !== '/admin/login' &&
|
|
19
|
+
route.path !== '/admin/signup'
|
|
20
|
+
) {
|
|
21
|
+
await logout({ redirectTo: route.path })
|
|
22
|
+
|
|
23
|
+
toast.add({
|
|
24
|
+
title: 'You are not logged in',
|
|
25
|
+
description: 'Please log in to continue.',
|
|
26
|
+
icon: 'lucide:circle-x',
|
|
27
|
+
color: 'error',
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div class="light:text-zinc-800 h-full dark:text-white">
|
|
36
|
+
<NuxtPage />
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|