@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.
Files changed (99) hide show
  1. package/.agents/skills/nuxt/GENERATION.md +5 -0
  2. package/.agents/skills/nuxt/SKILL.md +55 -0
  3. package/.agents/skills/nuxt/references/advanced-hooks.md +289 -0
  4. package/.agents/skills/nuxt/references/advanced-layers.md +299 -0
  5. package/.agents/skills/nuxt/references/advanced-module-authoring.md +554 -0
  6. package/.agents/skills/nuxt/references/best-practices-data-fetching.md +357 -0
  7. package/.agents/skills/nuxt/references/best-practices-ssr.md +355 -0
  8. package/.agents/skills/nuxt/references/core-cli.md +263 -0
  9. package/.agents/skills/nuxt/references/core-config.md +162 -0
  10. package/.agents/skills/nuxt/references/core-data-fetching.md +236 -0
  11. package/.agents/skills/nuxt/references/core-deployment.md +224 -0
  12. package/.agents/skills/nuxt/references/core-directory-structure.md +269 -0
  13. package/.agents/skills/nuxt/references/core-modules.md +292 -0
  14. package/.agents/skills/nuxt/references/core-routing.md +226 -0
  15. package/.agents/skills/nuxt/references/features-components-autoimport.md +328 -0
  16. package/.agents/skills/nuxt/references/features-components.md +264 -0
  17. package/.agents/skills/nuxt/references/features-composables.md +276 -0
  18. package/.agents/skills/nuxt/references/features-server.md +265 -0
  19. package/.agents/skills/nuxt/references/features-state.md +194 -0
  20. package/.agents/skills/nuxt/references/rendering-modes.md +237 -0
  21. package/.agents/skills/nuxt-ui/SKILL.md +334 -0
  22. package/.agents/skills/nuxt-ui/references/components.md +377 -0
  23. package/.agents/skills/nuxt-ui/references/composables.md +127 -0
  24. package/.agents/skills/nuxt-ui/references/layouts/chat.md +195 -0
  25. package/.agents/skills/nuxt-ui/references/layouts/dashboard.md +220 -0
  26. package/.agents/skills/nuxt-ui/references/layouts/docs.md +141 -0
  27. package/.agents/skills/nuxt-ui/references/layouts/editor.md +167 -0
  28. package/.agents/skills/nuxt-ui/references/layouts/page.md +260 -0
  29. package/.agents/skills/nuxt-ui/references/theming.md +427 -0
  30. package/.agents/skills/supabase-postgres-best-practices/AGENTS.md +68 -0
  31. package/.agents/skills/supabase-postgres-best-practices/CLAUDE.md +1 -0
  32. package/.agents/skills/supabase-postgres-best-practices/README.md +116 -0
  33. package/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  34. package/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  35. package/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  36. package/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  37. package/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  38. package/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  39. package/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  40. package/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  41. package/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  42. package/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  43. package/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  44. package/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  45. package/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  46. package/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  47. package/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  48. package/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  49. package/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  50. package/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  51. package/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  52. package/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  53. package/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  54. package/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  55. package/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  56. package/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  57. package/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  58. package/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  59. package/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  60. package/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  61. package/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  62. package/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  63. package/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  64. package/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
  65. package/.editorconfig +12 -0
  66. package/.env.example +2 -0
  67. package/.eslintignore +1 -0
  68. package/.prettierrc +9 -0
  69. package/.vscode/extensions.json +10 -0
  70. package/.vscode/settings.json +61 -0
  71. package/README.md +62 -0
  72. package/app/components/navbar/NavbarAdmin.vue +169 -0
  73. package/app/composables/auth.ts +81 -0
  74. package/app/layouts/setup.vue +13 -0
  75. package/app/middleware/auth.ts +27 -0
  76. package/app/middleware/setup-check.ts +25 -0
  77. package/app/pages/admin/(auth)/login.vue +84 -0
  78. package/app/pages/admin/(auth)/signup.vue +128 -0
  79. package/app/pages/admin/settings.vue +116 -0
  80. package/app/pages/admin/setup.vue +300 -0
  81. package/app/pages/admin.vue +38 -0
  82. package/bun.lock +2685 -0
  83. package/eslint.config.mjs +88 -0
  84. package/nuxt.config.ts +55 -0
  85. package/package.json +44 -0
  86. package/public/schema.sql +103 -0
  87. package/scripts/supabase-typegen.ts +36 -0
  88. package/server/api/category/list.get.ts +9 -0
  89. package/server/api/category/new.post.ts +31 -0
  90. package/server/api/settings/first_setup.get.ts +39 -0
  91. package/server/api/settings/index.get.ts +27 -0
  92. package/server/api/settings/update.post.ts +36 -0
  93. package/server/api/setup/create.post.ts +58 -0
  94. package/server/api/signup.post.ts +28 -0
  95. package/server/api/users/[id].get.ts +21 -0
  96. package/server/api/users/index.get.ts +16 -0
  97. package/shared/types/supabase.ts +406 -0
  98. package/skills-lock.json +20 -0
  99. package/tsconfig.json +18 -0
@@ -0,0 +1,88 @@
1
+ // @ts-check
2
+ import antfu from '@antfu/eslint-config'
3
+ import withNuxt from './.nuxt/eslint.config.mjs'
4
+
5
+ // See: https://eslint.vuejs.org/rules
6
+ export default withNuxt(
7
+ // @ts-ignore - Antfu's config is ESM only, but Nuxt's ESLint config is CJS --- IGNORE ---
8
+ antfu({
9
+ rules: {
10
+ 'node/prefer-global/process': ['off', 'never'],
11
+
12
+ 'style/indent-binary-ops': 'off',
13
+ 'style/arrow-parens': ['warn', 'always'],
14
+ 'style/brace-style': ['warn', '1tbs'],
15
+
16
+ 'vue/block-order': [
17
+ 'warn',
18
+ {
19
+ order: ['script', 'template', 'style'],
20
+ },
21
+ ],
22
+
23
+ 'vue/multiline-html-element-content-newline': 'off',
24
+ 'vue/html-closing-bracket-newline': 'off',
25
+
26
+ 'vue/html-self-closing': [
27
+ 'warn',
28
+ {
29
+ html: {
30
+ void: 'always',
31
+ normal: 'always',
32
+ component: 'always',
33
+ },
34
+ svg: 'always',
35
+ math: 'always',
36
+ },
37
+ ],
38
+
39
+ 'vue/attributes-order': [
40
+ 'warn',
41
+ {
42
+ order: [
43
+ 'DEFINITION',
44
+ 'LIST_RENDERING',
45
+ 'CONDITIONALS',
46
+ 'RENDER_MODIFIERS',
47
+ 'GLOBAL',
48
+ 'UNIQUE',
49
+ 'TWO_WAY_BINDING',
50
+ 'SLOT',
51
+ 'OTHER_DIRECTIVES',
52
+ 'ATTR_DYNAMIC',
53
+ 'ATTR_STATIC',
54
+ 'ATTR_SHORTHAND_BOOL',
55
+ 'EVENTS',
56
+ 'CONTENT',
57
+ ],
58
+ },
59
+ ],
60
+
61
+ 'vue/multi-word-component-names': 'off',
62
+
63
+ 'vue/eqeqeq': ['error', 'always'],
64
+
65
+ 'style/comma-dangle': [
66
+ 'warn',
67
+ {
68
+ arrays: 'always-multiline',
69
+ objects: 'always-multiline',
70
+ functions: 'never',
71
+ },
72
+ ],
73
+
74
+ 'vue/comma-dangle': [
75
+ 'warn',
76
+ {
77
+ arrays: 'always-multiline',
78
+ objects: 'always-multiline',
79
+ functions: 'never',
80
+ },
81
+ ],
82
+
83
+ 'style/operator-linebreak': 'off',
84
+
85
+ 'vue/singleline-html-element-content-newline': 'off',
86
+ },
87
+ })
88
+ )
package/nuxt.config.ts ADDED
@@ -0,0 +1,55 @@
1
+ const cwd = process.cwd()
2
+
3
+ const isDev = cwd.includes('supabase')
4
+
5
+ export default defineNuxtConfig({
6
+ extends: [['@plutocms/pluto', { install: true }], '@plutocms/utils'],
7
+
8
+ modules: ['@nuxt/eslint', '@nuxtjs/supabase'],
9
+
10
+ $meta: {
11
+ name: 'supabase',
12
+ },
13
+
14
+ runtimeConfig: {
15
+ supabaseUrl: process.env.SUPABASE_URL,
16
+ supabaseKey: process.env.SUPABASE_KEY,
17
+ },
18
+
19
+ alias: {
20
+ cookie: 'cookie-es',
21
+ },
22
+
23
+ ignore: ['./scripts/**', './supabase/**'],
24
+
25
+ nitro: {
26
+ alias: {
27
+ cookie: 'cookie-es',
28
+ },
29
+ },
30
+
31
+ eslint: {
32
+ config: {
33
+ nuxt: {
34
+ sortConfigKeys: true,
35
+ },
36
+ standalone: false,
37
+ },
38
+ },
39
+
40
+ supabase: !isDev
41
+ ? {
42
+ types: '#shared',
43
+ cookiePrefix: 'access_token',
44
+
45
+ redirectOptions: {
46
+ login: '/admin/login',
47
+ callback: '/auth/confirm',
48
+ include: ['/admin/signup'],
49
+ saveRedirectToCookie: false,
50
+ },
51
+
52
+ redirect: false,
53
+ }
54
+ : undefined,
55
+ })
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@plutocms/supabase",
3
+ "type": "module",
4
+ "version": "0.0.1-alpha.1",
5
+ "main": "./nuxt.config.ts",
6
+ "scripts": {
7
+ "build": "nuxt build",
8
+ "dev": "nuxt dev",
9
+ "generate": "nuxt generate",
10
+ "preview": "nuxt preview",
11
+ "postinstall": "nuxt prepare",
12
+ "prettier": "prettier --write .",
13
+ "lint": "eslint .",
14
+ "lint:fix": "eslint . --fix && prettier --write .",
15
+ "supabase-types": "bun ./scripts/supabase-typegen.ts"
16
+ },
17
+ "dependencies": {
18
+ "@nuxtjs/supabase": "2.0.3",
19
+ "postgres": "^3.4.8",
20
+ "supabase": "^2.76.15",
21
+ "yup": "1.7.1"
22
+ },
23
+ "devDependencies": {
24
+ "@antfu/eslint-config": "^6.2.0",
25
+ "@nuxt/eslint": "^1.15.1",
26
+ "@nuxt/ui": "^4.4.0",
27
+ "@plutocms/pluto": "^0.0.1-alpha.3",
28
+ "@plutocms/utils": "^0.0.1-alpha.4",
29
+ "@types/bun": "^1.3.9",
30
+ "@vueuse/nuxt": "^14.2.1",
31
+ "eslint": "^9.39.1",
32
+ "nuxt": "^4.3.1",
33
+ "prettier": "^3.8.1",
34
+ "vue": "^3.5.28",
35
+ "vue-router": "^5.0.2"
36
+ },
37
+ "trustedDependencies": [
38
+ "@parcel/watcher",
39
+ "esbuild",
40
+ "supabase",
41
+ "unrs-resolver",
42
+ "vue-demi"
43
+ ]
44
+ }
@@ -0,0 +1,103 @@
1
+ -- Supabase Schema SQL
2
+ -- Settings
3
+ --- Create enum type for settings
4
+ do $$
5
+ begin
6
+ if not exists (select 1 from pg_type where typname = 'tsettings') then
7
+ create type TSettings as enum (
8
+ 'website_title',
9
+ 'website_url',
10
+ 'website_description'
11
+ );
12
+ end if;
13
+ end
14
+ $$;
15
+
16
+ --- Create settings table
17
+ create table public.settings (
18
+ id bigint generated by default as identity not null,
19
+ setting_name public.TSettings not null,
20
+ setting_value text not null,
21
+ constraint settings_pkey primary key (id),
22
+ constraint settings_setting_name_key unique (setting_name)
23
+ ) TABLESPACE pg_default;
24
+
25
+ --- Insert default settings (website_title, website_url, website_description)
26
+ insert into public.settings (setting_name, setting_value) values
27
+ ('website_title', 'My Website'),
28
+ ('website_url', 'https://mywebsite.test'),
29
+ ('website_description', 'This is my website.');
30
+
31
+ alter table public.settings enable row level security;
32
+
33
+ -- Policies for settings table
34
+ create policy "Enable insert for authenticated users only"
35
+ on public.settings
36
+ to authenticated, dashboard_user
37
+ with check (true);
38
+
39
+ --- Create enum type for healthcheck names
40
+ do $$
41
+ begin
42
+ if not exists (select 1 from pg_type where typname = 'thealthcheck') then
43
+ create type Healthcheck as enum (
44
+ 'first_setup'
45
+ );
46
+ end if;
47
+ end
48
+ $$;
49
+
50
+ --- Create healthcheck table (name/value format like settings)
51
+ create table public.healthcheck (
52
+ id bigint generated by default as identity not null,
53
+ check_name public.Healthcheck not null,
54
+ check_value text not null,
55
+ constraint healthcheck_pkey primary key (id),
56
+ constraint healthcheck_check_name_key unique (check_name)
57
+ ) TABLESPACE pg_default;
58
+
59
+ --- Insert default healthcheck values
60
+ insert into public.healthcheck (check_name, check_value) values
61
+ ('first_setup', 'true');
62
+
63
+ alter table public.healthcheck enable row level security;
64
+
65
+ -- Allow read access to healthcheck for public and dashboard_user (no login required)
66
+ create policy "Enable read access for healthcheck to public and dashboard_user"
67
+ on public.healthcheck
68
+ for select
69
+ to public, dashboard_user
70
+ using (true);
71
+
72
+ -- Profiles
73
+ create table profiles (
74
+ id uuid references auth.users on delete cascade not null primary key,
75
+ updated_at timestamp with time zone,
76
+ first_name text,
77
+ last_name text,
78
+ constraint first_name_length check (char_length(first_name) >= 3)
79
+ );
80
+
81
+ alter table public.profiles enable row level security;
82
+
83
+ create policy "Enable read access for authenticated users"
84
+ on public.profiles
85
+ to authenticated, dashboard_user
86
+ for select using (true);
87
+
88
+ --- inserts a row into public.profiles
89
+ create function public.handle_new_user()
90
+ returns trigger
91
+ language plpgsql
92
+ security definer set search_path = ''
93
+ as $$
94
+ begin
95
+ insert into public.profiles (id, first_name, last_name)
96
+ values (new.id, new.raw_user_meta_data ->> 'first_name', new.raw_user_meta_data ->> 'last_name');
97
+ return new;
98
+ end;
99
+ $$;
100
+ --- trigger the function every time a user is created
101
+ create trigger on_auth_user_created
102
+ after insert on auth.users
103
+ for each row execute procedure public.handle_new_user();
@@ -0,0 +1,36 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import { cwd } from 'node:process'
4
+ import { $ } from 'bun'
5
+ import { consola } from 'consola'
6
+
7
+ const projectUrl = process.env.SUPABASE_URL
8
+ const projectId = projectUrl?.split('.supabase.co')[0]?.replace('https://', '')
9
+ const _path = path
10
+ .resolve(cwd(), './shared/types/supabase.ts')
11
+ .replace(/\\/g, '/')
12
+
13
+ ;(async () => {
14
+ consola.info(`Generating Supabase types for project: ${projectId}`)
15
+
16
+ // Create file if it doesn't exist
17
+ if (!fs.existsSync(_path)) {
18
+ consola.info('Types file does not exist. Creating a new one.')
19
+
20
+ fs.mkdirSync(path.dirname(_path), { recursive: true })
21
+ fs.writeFileSync(_path, '', 'utf-8')
22
+ }
23
+
24
+ const args = [
25
+ `--project-id=${projectId || ''}`,
26
+ '--schema=public',
27
+ '>',
28
+ `"${_path}"`,
29
+ ]
30
+
31
+ try {
32
+ await $`bunx supabase gen types typescript ${{ raw: args.join(' ') }}`
33
+ } catch (error) {
34
+ consola.error('Unhandled error:', error)
35
+ }
36
+ })()
@@ -0,0 +1,9 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const client = await serverSupabaseClient<Database>(event)
5
+
6
+ const { data } = await client.from('categories').select('*')
7
+
8
+ return { data }
9
+ })
@@ -0,0 +1,31 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const client = await serverSupabaseClient<Database>(event)
5
+
6
+ const body = await readBody(event)
7
+
8
+ if (!body) {
9
+ throw createError({
10
+ message: 'No file sent.',
11
+ })
12
+ }
13
+
14
+ const { data, error } = await client
15
+ .from('categories')
16
+ .insert(body)
17
+ .select()
18
+ .single()
19
+
20
+ if (error) {
21
+ throw createError({
22
+ message: error.message,
23
+ })
24
+ }
25
+
26
+ if (error) {
27
+ throw createError({ message: 'error' })
28
+ }
29
+
30
+ return { data }
31
+ })
@@ -0,0 +1,39 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ type HealthcheckSettingKey =
4
+ Database['public']['Tables']['healthcheck']['Row']['config_name']
5
+
6
+ export default defineEventHandler(async (event) => {
7
+ const client = await serverSupabaseClient<Database>(event)
8
+
9
+ const { data, error } = await client.from('healthcheck').select('*')
10
+
11
+ if (error) {
12
+ return {
13
+ success: false,
14
+ message: 'Error retrieving healthcheck settings',
15
+ error: error.message,
16
+ }
17
+ }
18
+
19
+ // @ts-expect-error: Object.fromEntries may not infer the correct type
20
+ const isFirstSetup: Record<HealthcheckSettingKey, string> = {
21
+ ...Object.fromEntries(
22
+ data?.map((item) => [item.config_name, item.config_value]) || []
23
+ ),
24
+ }
25
+
26
+ data?.forEach((item) => {
27
+ if (!item.config_name || !item.config_value) {
28
+ return
29
+ }
30
+
31
+ isFirstSetup[item.config_name] = item.config_value
32
+ })
33
+
34
+ return {
35
+ success: true,
36
+ message: 'Healthcheck settings retrieved successfully',
37
+ is_first_setup: isFirstSetup.first_setup === 'true',
38
+ }
39
+ })
@@ -0,0 +1,27 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const client = await serverSupabaseClient<Database>(event)
5
+
6
+ const { data } = await client.from('settings').select('*')
7
+
8
+ type SettingsKey =
9
+ Database['public']['Tables']['settings']['Row']['setting_name']
10
+
11
+ // @ts-expect-error: Object.fromEntries may not infer the correct type for settings
12
+ const settings: Record<SettingsKey, string> = {
13
+ ...Object.fromEntries(
14
+ data?.map((item) => [item.setting_name, item.setting_value]) || []
15
+ ),
16
+ }
17
+
18
+ data?.forEach((item) => {
19
+ if (!item.setting_name || !item.setting_value) {
20
+ return
21
+ }
22
+
23
+ settings[item.setting_name] = item.setting_value
24
+ })
25
+
26
+ return { settings }
27
+ })
@@ -0,0 +1,36 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ type SettingName =
5
+ Database['public']['Tables']['settings']['Insert']['setting_name']
6
+ type FormBody = Record<SettingName, string>
7
+
8
+ const client = await serverSupabaseClient<Database>(event)
9
+ const body = await readBody<FormBody>(event)
10
+
11
+ if (!body) {
12
+ throw createError({ statusMessage: 'No payload sent.' })
13
+ }
14
+
15
+ const transformed = [
16
+ ...Object.entries(body).map(([key, value]) => ({
17
+ setting_name: key as SettingName,
18
+ setting_value: value,
19
+ })),
20
+ ]
21
+
22
+ const { data, error } = await client
23
+ .from('settings')
24
+ .upsert(transformed, { onConflict: 'setting_name' })
25
+ .select()
26
+
27
+ if (error) {
28
+ throw createError({ statusMessage: error.message })
29
+ }
30
+
31
+ return {
32
+ message: 'Settings updated successfully.',
33
+ statusCode: 200,
34
+ data,
35
+ }
36
+ })
@@ -0,0 +1,58 @@
1
+ import postgres from 'postgres'
2
+
3
+ interface Payload {
4
+ baseUrl: string
5
+ connectionString: string
6
+ }
7
+
8
+ export default defineEventHandler(async (event) => {
9
+ const body = await readBody<Payload>(event)
10
+
11
+ let schema = await $fetch<string | Blob>('/schema.sql', {
12
+ baseURL: body.baseUrl,
13
+ })
14
+
15
+ if (typeof schema !== 'string') {
16
+ schema = await schema.text()
17
+ }
18
+
19
+ const supabaseUrl = process.env.SUPABASE_URL
20
+ const supabaseKey = process.env.SUPABASE_KEY
21
+
22
+ if (!supabaseUrl || !supabaseKey) {
23
+ throw new Error(
24
+ 'Supabase URL or Key is not defined in environment variables.'
25
+ )
26
+ }
27
+
28
+ const connectionString = body.connectionString
29
+
30
+ const sql = postgres(connectionString)
31
+
32
+ try {
33
+ /* await sql.begin(async (sql) => {
34
+ await sql.unsafe(schema)
35
+ }) */
36
+
37
+ // Set the first_setup flag in the healthcheck table to false
38
+ await sql`
39
+ UPDATE healthcheck
40
+ SET config_value = 'false'
41
+ WHERE config_name = 'first_setup';
42
+ `
43
+
44
+ return {
45
+ success: true,
46
+ message: 'Database setup completed successfully.',
47
+ }
48
+ } catch (error: any) {
49
+ console.error('Error setting up database:', error)
50
+
51
+ return {
52
+ success: false,
53
+ error: error.message,
54
+ }
55
+ } finally {
56
+ sql.end()
57
+ }
58
+ })
@@ -0,0 +1,28 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const client = await serverSupabaseClient<Database>(event)
5
+
6
+ const body = await readBody(event)
7
+
8
+ const { data, error } = await client.auth.signUp({
9
+ email: body.email,
10
+ password: body.password,
11
+ options: {
12
+ data: {
13
+ first_name: body.first_name,
14
+ last_name: body.last_name,
15
+ },
16
+ },
17
+ })
18
+
19
+ if (error) {
20
+ throw createError({
21
+ statusCode: Number.parseInt(error.code ?? '500'),
22
+ cause: error.cause,
23
+ message: error.message,
24
+ })
25
+ }
26
+
27
+ return { message: 'User registered successfully', data }
28
+ })
@@ -0,0 +1,21 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const client = await serverSupabaseClient<Database>(event)
5
+
6
+ const id = event.context.params?.id as string
7
+
8
+ const { data: user, error } = await client
9
+ .from('profiles')
10
+ .select('*')
11
+ .eq('id', id)
12
+
13
+ if (error) {
14
+ throw createError({
15
+ statusCode: 500,
16
+ statusMessage: `Error fetching user: ${error.message}`,
17
+ })
18
+ }
19
+
20
+ return user
21
+ })
@@ -0,0 +1,16 @@
1
+ import { serverSupabaseClient } from '#supabase/server'
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const client = await serverSupabaseClient<Database>(event)
5
+
6
+ const { data: users, error } = await client.from('profiles').select('*')
7
+
8
+ if (error) {
9
+ throw createError({
10
+ statusCode: 500,
11
+ statusMessage: `Error fetching users: ${error.message}`,
12
+ })
13
+ }
14
+
15
+ return users
16
+ })