chore: format files (#43668)

Format files. Run `pnpm format` at root.

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
This commit is contained in:
Katerina Skroumpelou
2026-03-11 20:40:01 +02:00
committed by GitHub
parent f49ed14dfb
commit 77e5180c5c
32 changed files with 94 additions and 98 deletions

View File

@@ -21,8 +21,10 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
sparse-checkout: |
apps
patches
apps
packages
blocks
patches
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
name: Install pnpm
with:

View File

@@ -19,6 +19,7 @@ Replication currently supports **BigQuery** as the only managed destination. See
We are working on adding more destinations in the future. Availability may continue to vary based on the planned roll-out strategy.
{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
## What happened to Analytics Buckets replication?
We are currently working on a new Supabase Warehouse product designed to address the limitations of the previous Analytics Buckets. Our goal is to build a solution we can confidently stand behind, rather than continuing to support an approach that does not meet the quality and flexibility we want for our users.

View File

@@ -44,10 +44,7 @@ When the rate limit is exceeded, calling another Edge Function throws a `RateLim
```typescript
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
)
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_ANON_KEY')!)
Deno.serve(async (req) => {
try {
@@ -87,17 +84,14 @@ Deno.serve(async (req) => {
```typescript
Deno.serve(async (req) => {
try {
const response = await fetch(
`${Deno.env.get('SUPABASE_URL')}/functions/v1/other-function`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${Deno.env.get('SUPABASE_ANON_KEY')}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ foo: 'bar' }),
}
)
const response = await fetch(`${Deno.env.get('SUPABASE_URL')}/functions/v1/other-function`, {
method: 'POST',
headers: {
Authorization: `Bearer ${Deno.env.get('SUPABASE_ANON_KEY')}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ foo: 'bar' }),
})
return response
} catch (err) {
if (err instanceof Deno.errors.RateLimitError) {
@@ -136,16 +130,9 @@ You can also use `retryAfterMs` to implement automatic retries within your funct
```typescript
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
)
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_ANON_KEY')!)
async function invokeWithRetry(
functionName: string,
payload: object,
maxRetries = 3
) {
async function invokeWithRetry(functionName: string, payload: object, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const { data, error } = await supabase.functions.invoke(functionName, {
@@ -279,15 +266,15 @@ async function processWithDelay(items: any[]) {
## Common patterns and their impact
| Pattern | Budget consumption | Recommendation |
| --- | --- | --- |
| Simple chain (A to B to C) | Low | Generally safe |
| Fan-out (A to B, C, D, E) | Moderate | Limit concurrency |
| Deep recursion (A to A to A...) | High | Set max depth |
| Unbounded loops | Very high | Avoid, use queues |
| Pattern | Budget consumption | Recommendation |
| ------------------------------- | ------------------ | ----------------- |
| Simple chain (A to B to C) | Low | Generally safe |
| Fan-out (A to B, C, D, E) | Moderate | Limit concurrency |
| Deep recursion (A to A to A...) | High | Set max depth |
| Unbounded loops | Very high | Avoid, use queues |
## Increasing rate limits
Currently, all plans have the same rate limit budget. We are working on introducing custom limits for different use cases.
If you need a higher rate limit for your project, [contact support](/dashboard/support/new) with details about your use case.
If you need a higher rate limit for your project, [contact support](/dashboard/support/new) with details about your use case.

View File

@@ -27,11 +27,11 @@ property which gets populated automatically by Supabase Auth if the user logged
The `CurrentUserAvatar` component is designed to be used anywhere in your app. Add the `<CurrentUserAvatar />` component to your page and it will render the avatar of the current user, with a fallback.
```html
```vue
<script setup lang="ts">
// Asumes you have Header component created
import Header from '@/components/Header.vue'
// Assumes you have Header component created
import CurrentUserAvatar from '@/components/CurrentUserAvatar.vue'
import Header from '@/components/Header.vue'
</script>
<template>

View File

@@ -42,18 +42,18 @@ The File Upload component makes it easy to add file uploads to your app, with bu
- Simply add this `<Dropzone />` component to your page and it will handle the rest.
```html
```vue
<script setup>
import { Dropzone, DropzoneContent, DropzoneEmptyState } from '@/components/dropzone'
import { useSupabaseUpload } from '@/composables/use-supabase-upload'
import { Dropzone, DropzoneContent, DropzoneEmptyState } from '@/components/dropzone'
import { useSupabaseUpload } from '@/composables/use-supabase-upload'
const upload = useSupabaseUpload({
bucketName: 'test',
path: 'test',
allowedMimeTypes: ['image/*'],
maxFiles: 2,
maxFileSize: 1000 * 1000 * 10, // 10MB,
})
const upload = useSupabaseUpload({
bucketName: 'test',
path: 'test',
allowedMimeTypes: ['image/*'],
maxFiles: 2,
maxFileSize: 1000 * 1000 * 10, // 10MB,
})
</script>
<template>

View File

@@ -22,9 +22,9 @@ This block assumes that you have already installed a Supabase client for Nuxt fr
The `RealtimeAvatarStack` component renders stacked avatars which are connected to Supabase Realtime. It uses the Presence feature of Supabase Realtime. You can use this to show currently online users in a chatroom, game session or collaborative app.
```html
```vue
<script setup lang="ts">
// Asumes you have Header component created
// Assumes you have Header component created
import Header from '@/components/Header.vue'
import RealtimeAvatarStack from '@/components/RealtimeAvatarStack.vue'
</script>

View File

@@ -37,9 +37,9 @@ The Realtime Cursors component lets users share their cursor position with other
The Realtime Cursor component is designed to be used in a room. It can be used to build real-time collaborative applications. Add the `<RealtimeCursors />` component to your page and it will render realtime cursors from other users in the room.
```html
```vue
<script setup lang="ts">
import RealtimeCursors from '@/components/RealtimeCursors.vue'
import RealtimeCursors from '@/components/RealtimeCursors.vue'
</script>
<template>

View File

@@ -24,11 +24,11 @@ property which gets populated automatically by Supabase Auth if the user logged
The `CurrentUserAvatar` component is designed to be used anywhere in your app. Add the `<CurrentUserAvatar />` component to your page and it will render the avatar of the current user, with a fallback.
```html
```vue
<script setup lang="ts">
// Asumes you have Header component created
import Header from '@/components/Header.vue'
// Assumes you have Header component created
import CurrentUserAvatar from '@/components/CurrentUserAvatar.vue'
import Header from '@/components/Header.vue'
</script>
<template>

View File

@@ -42,18 +42,18 @@ The File Upload component makes it easy to add file uploads to your app, with bu
- Simply add this `<Dropzone />` component to your page and it will handle the rest.
```html
```vue
<script setup>
import { Dropzone, DropzoneContent, DropzoneEmptyState } from '@/components/dropzone'
import { useSupabaseUpload } from '@/composables/use-supabase-upload'
import { Dropzone, DropzoneContent, DropzoneEmptyState } from '@/components/dropzone'
import { useSupabaseUpload } from '@/composables/use-supabase-upload'
const upload = useSupabaseUpload({
bucketName: 'test',
path: 'test',
allowedMimeTypes: ['image/*'],
maxFiles: 2,
maxFileSize: 1000 * 1000 * 10, // 10MB,
})
const upload = useSupabaseUpload({
bucketName: 'test',
path: 'test',
allowedMimeTypes: ['image/*'],
maxFiles: 2,
maxFileSize: 1000 * 1000 * 10, // 10MB,
})
</script>
<template>

View File

@@ -22,9 +22,9 @@ This block assumes that you have already installed a Supabase client for Vue fro
The `RealtimeAvatarStack` component renders stacked avatars which are connected to Supabase Realtime. It uses the Presence feature of Supabase Realtime. You can use this to show currently online users in a chatroom, game session or collaborative app.
```html
```vue
<script setup lang="ts">
// Asumes you have Header component created
// Assumes you have Header component created
import Header from '@/components/Header.vue'
import RealtimeAvatarStack from '@/components/RealtimeAvatarStack.vue'
</script>

View File

@@ -37,9 +37,9 @@ The Realtime Cursors component lets users share their cursor position with other
The Realtime Cursor component is designed to be used in a room. It can be used to build real-time collaborative applications. Add the `<RealtimeCursors />` component to your page and it will render realtime cursors from other users in the room.
```html
```vue
<script setup lang="ts">
import RealtimeCursors from '@/components/RealtimeCursors.vue'
import RealtimeCursors from '@/components/RealtimeCursors.vue'
</script>
<template>

View File

@@ -19,13 +19,13 @@
},
{
"path": "registry/default/current-user-avatar/nuxtjs/app/composables/useCurrentUserName.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"type": "registry:component",
"target": "app/composables/useCurrentUserName.ts"
},
{
"path": "registry/default/current-user-avatar/nuxtjs/app/composables/useCurrentUserImage.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"type": "registry:component",
"target": "app/composables/useCurrentUserImage.ts"
}

View File

@@ -19,13 +19,13 @@
},
{
"path": "registry/default/current-user-avatar/vue/composables/useCurrentUserName.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"type": "registry:component",
"target": "composables/useCurrentUserName.ts"
},
{
"path": "registry/default/current-user-avatar/vue/composables/useCurrentUserImage.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"type": "registry:component",
"target": "composables/useCurrentUserImage.ts"
}

View File

@@ -26,19 +26,19 @@
},
{
"path": "registry/default/realtime-avatar-stack/nuxtjs/app/composables/useCurrentUserImage.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"type": "registry:component",
"target": "app/composables/useCurrentUserImage.ts"
},
{
"path": "registry/default/realtime-avatar-stack/nuxtjs/app/composables/useCurrentUserName.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"type": "registry:component",
"target": "app/composables/useCurrentUserName.ts"
},
{
"path": "registry/default/realtime-avatar-stack/nuxtjs/app/composables/useRealtimePresenceRoom.ts",
"content": "import { ref, watch, onUnmounted } from 'vue'\nimport { REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js'\n\nimport { useCurrentUserImage } from './useCurrentUserImage'\nimport { useCurrentUserName } from './useCurrentUserName'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nconst supabase = createClient()\n\nexport type RealtimeUser = {\n id: string\n name: string\n image: string\n}\n\nexport function useRealtimePresenceRoom(roomName: string) {\n const { image: currentUserImage } = useCurrentUserImage()\n const { name: currentUserName } = useCurrentUserName()\n\n const users = ref<Record<string, RealtimeUser>>({})\n\n let room: ReturnType<typeof supabase.channel> | null = null\n\n function setupRoom() {\n if (!roomName) return\n\n room = supabase.channel(roomName)\n\n room\n .on('presence', { event: 'sync' }, () => {\n const newState =\n room?.presenceState<{ image: string; name: string }>() ?? {}\n\n const newUsers = Object.fromEntries(\n Object.entries(newState).map(([key, values]) => {\n const typedValues = values as Array<{ image: string; name: string }>\n return [\n key,\n {\n id: key,\n name: typedValues[0].name,\n image: typedValues[0].image,\n },\n ]\n })\n ) as Record<string, RealtimeUser>\n\n users.value = newUsers\n })\n .subscribe(async (status: REALTIME_SUBSCRIBE_STATES) => {\n if (status === REALTIME_SUBSCRIBE_STATES.SUBSCRIBED && room) {\n await room.track({\n name: currentUserName.value,\n image: currentUserImage.value,\n })\n } else {\n users.value = {}\n }\n })\n }\n\n function cleanup() {\n if (room) {\n room.unsubscribe()\n room = null\n }\n }\n\n watch(\n [() => roomName, currentUserName, currentUserImage],\n () => {\n cleanup()\n setupRoom()\n },\n { immediate: true }\n )\n\n onUnmounted(() => {\n cleanup()\n })\n\n return { users }\n}\n",
"content": "import { ref, watch, onUnmounted } from 'vue'\nimport { REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js'\n\nimport { useCurrentUserImage } from './useCurrentUserImage'\nimport { useCurrentUserName } from './useCurrentUserName'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nconst supabase = createClient()\n\nexport type RealtimeUser = {\n id: string\n name: string\n image: string\n}\n\nexport function useRealtimePresenceRoom(roomName: string) {\n const { image: currentUserImage } = useCurrentUserImage()\n const { name: currentUserName } = useCurrentUserName()\n\n const users = ref<Record<string, RealtimeUser>>({})\n\n let room: ReturnType<typeof supabase.channel> | null = null\n\n function setupRoom() {\n if (!roomName) return\n\n room = supabase.channel(roomName)\n\n room\n .on('presence', { event: 'sync' }, () => {\n const newState = room?.presenceState<{ image: string; name: string }>() ?? {}\n\n const newUsers = Object.fromEntries(\n Object.entries(newState).map(([key, values]) => {\n const typedValues = values as Array<{ image: string; name: string }>\n return [\n key,\n {\n id: key,\n name: typedValues[0].name,\n image: typedValues[0].image,\n },\n ]\n })\n ) as Record<string, RealtimeUser>\n\n users.value = newUsers\n })\n .subscribe(async (status: REALTIME_SUBSCRIBE_STATES) => {\n if (status === REALTIME_SUBSCRIBE_STATES.SUBSCRIBED && room) {\n await room.track({\n name: currentUserName.value,\n image: currentUserImage.value,\n })\n } else {\n users.value = {}\n }\n })\n }\n\n function cleanup() {\n if (room) {\n room.unsubscribe()\n room = null\n }\n }\n\n watch(\n [() => roomName, currentUserName, currentUserImage],\n () => {\n cleanup()\n setupRoom()\n },\n { immediate: true }\n )\n\n onUnmounted(() => {\n cleanup()\n })\n\n return { users }\n}\n",
"type": "registry:component",
"target": "app/composables/useRealtimePresenceRoom.ts"
}

View File

@@ -26,19 +26,19 @@
},
{
"path": "registry/default/realtime-avatar-stack/vue/composables/useCurrentUserImage.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserImage() {\n const image = ref<string | null>(null)\n\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n image.value = data.session?.user.user_metadata.avatar_url ?? null\n }\n\n onMounted(() => {\n fetchUserImage()\n })\n\n return {\n image,\n }\n}\n",
"type": "registry:component",
"target": "composables/useCurrentUserImage.ts"
},
{
"path": "registry/default/realtime-avatar-stack/vue/composables/useCurrentUserName.ts",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"content": "import { ref, onMounted } from 'vue'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nexport function useCurrentUserName() {\n const name = ref<string | null>(null)\n\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n\n if (error) {\n console.error(error)\n return\n }\n\n name.value = data.session?.user.user_metadata.full_name ?? '?'\n }\n\n onMounted(() => {\n fetchProfileName()\n })\n\n return {\n name,\n }\n}\n",
"type": "registry:component",
"target": "composables/useCurrentUserName.ts"
},
{
"path": "registry/default/realtime-avatar-stack/vue/composables/useRealtimePresenceRoom.ts",
"content": "import { ref, watch, onUnmounted } from 'vue'\nimport { REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js'\n\nimport { useCurrentUserImage } from './useCurrentUserImage'\nimport { useCurrentUserName } from './useCurrentUserName'\n// @ts-ignore\nimport { createClient } from \"@/lib/supabase/client\"\n\nconst supabase = createClient()\n\nexport type RealtimeUser = {\n id: string\n name: string\n image: string\n}\n\nexport function useRealtimePresenceRoom(roomName: string) {\n const { image: currentUserImage } = useCurrentUserImage()\n const { name: currentUserName } = useCurrentUserName()\n\n const users = ref<Record<string, RealtimeUser>>({})\n\n let room: ReturnType<typeof supabase.channel> | null = null\n\n function setupRoom() {\n if (!roomName) return\n\n room = supabase.channel(roomName)\n\n room\n .on('presence', { event: 'sync' }, () => {\n const newState =\n room?.presenceState<{ image: string; name: string }>() ?? {}\n\n const newUsers = Object.fromEntries(\n Object.entries(newState).map(([key, values]) => {\n const typedValues = values as Array<{ image: string; name: string }>\n if (typedValues.length > 0) {\n return [\n key,\n {\n id: key,\n name: typedValues[0].name,\n image: typedValues[0].image,\n },\n ]\n } else {\n return [\n key,\n {\n id: key,\n name: '',\n image: '',\n },\n ]\n }\n })\n ) as Record<string, RealtimeUser>\n\n users.value = newUsers\n })\n .subscribe(async (status: REALTIME_SUBSCRIBE_STATES) => {\n if (status === REALTIME_SUBSCRIBE_STATES.SUBSCRIBED && room) {\n await room.track({\n name: currentUserName.value,\n image: currentUserImage.value,\n })\n } else {\n users.value = {}\n }\n })\n }\n\n function cleanup() {\n if (room) {\n room.unsubscribe()\n room = null\n }\n }\n\n watch(\n [() => roomName, currentUserName, currentUserImage],\n () => {\n cleanup()\n setupRoom()\n },\n { immediate: true }\n )\n\n onUnmounted(() => {\n cleanup()\n })\n\n return { users }\n}\n",
"content": "import { ref, watch, onUnmounted } from 'vue'\nimport { REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js'\n\nimport { useCurrentUserImage } from './useCurrentUserImage'\nimport { useCurrentUserName } from './useCurrentUserName'\n// @ts-ignore\nimport { createClient } from '@/lib/supabase/client'\n\nconst supabase = createClient()\n\nexport type RealtimeUser = {\n id: string\n name: string\n image: string\n}\n\nexport function useRealtimePresenceRoom(roomName: string) {\n const { image: currentUserImage } = useCurrentUserImage()\n const { name: currentUserName } = useCurrentUserName()\n\n const users = ref<Record<string, RealtimeUser>>({})\n\n let room: ReturnType<typeof supabase.channel> | null = null\n\n function setupRoom() {\n if (!roomName) return\n\n room = supabase.channel(roomName)\n\n room\n .on('presence', { event: 'sync' }, () => {\n const newState = room?.presenceState<{ image: string; name: string }>() ?? {}\n\n const newUsers = Object.fromEntries(\n Object.entries(newState).map(([key, values]) => {\n const typedValues = values as Array<{ image: string; name: string }>\n if (typedValues.length > 0) {\n return [\n key,\n {\n id: key,\n name: typedValues[0].name,\n image: typedValues[0].image,\n },\n ]\n } else {\n return [\n key,\n {\n id: key,\n name: '',\n image: '',\n },\n ]\n }\n })\n ) as Record<string, RealtimeUser>\n\n users.value = newUsers\n })\n .subscribe(async (status: REALTIME_SUBSCRIBE_STATES) => {\n if (status === REALTIME_SUBSCRIBE_STATES.SUBSCRIBED && room) {\n await room.track({\n name: currentUserName.value,\n image: currentUserImage.value,\n })\n } else {\n users.value = {}\n }\n })\n }\n\n function cleanup() {\n if (room) {\n room.unsubscribe()\n room = null\n }\n }\n\n watch(\n [() => roomName, currentUserName, currentUserImage],\n () => {\n cleanup()\n setupRoom()\n },\n { immediate: true }\n )\n\n onUnmounted(() => {\n cleanup()\n })\n\n return { users }\n}\n",
"type": "registry:component",
"target": "composables/useRealtimePresenceRoom.ts"
}

View File

@@ -3,4 +3,4 @@ import { type RegistryItem } from 'shadcn/schema'
import nuxtjs from './default/current-user-avatar/nuxtjs/registry-item.json' with { type: 'json' }
import vue from './default/current-user-avatar/vue/registry-item.json' with { type: 'json' }
export const currentUserAvatar = [nuxtjs, vue] as RegistryItem[]
export const currentUserAvatar = [nuxtjs, vue] as RegistryItem[]

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserImage() {
const image = ref<string | null>(null)

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserName() {
const name = ref<string | null>(null)

View File

@@ -22,4 +22,4 @@
}
],
"dependencies": ["@supabase/supabase-js@latest"]
}
}

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserImage() {
const image = ref<string | null>(null)

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserName() {
const name = ref<string | null>(null)

View File

@@ -22,4 +22,4 @@
}
],
"dependencies": ["@supabase/supabase-js@latest"]
}
}

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserImage() {
const image = ref<string | null>(null)

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserName() {
const name = ref<string | null>(null)

View File

@@ -4,7 +4,7 @@ import { REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js'
import { useCurrentUserImage } from './useCurrentUserImage'
import { useCurrentUserName } from './useCurrentUserName'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
const supabase = createClient()
@@ -29,8 +29,7 @@ export function useRealtimePresenceRoom(roomName: string) {
room
.on('presence', { event: 'sync' }, () => {
const newState =
room?.presenceState<{ image: string; name: string }>() ?? {}
const newState = room?.presenceState<{ image: string; name: string }>() ?? {}
const newUsers = Object.fromEntries(
Object.entries(newState).map(([key, values]) => {

View File

@@ -32,4 +32,4 @@
}
],
"dependencies": ["@supabase/supabase-js@latest"]
}
}

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserImage() {
const image = ref<string | null>(null)

View File

@@ -1,6 +1,6 @@
import { ref, onMounted } from 'vue'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
export function useCurrentUserName() {
const name = ref<string | null>(null)

View File

@@ -4,7 +4,7 @@ import { REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js'
import { useCurrentUserImage } from './useCurrentUserImage'
import { useCurrentUserName } from './useCurrentUserName'
// @ts-ignore
import { createClient } from "@/lib/supabase/client"
import { createClient } from '@/lib/supabase/client'
const supabase = createClient()
@@ -29,8 +29,7 @@ export function useRealtimePresenceRoom(roomName: string) {
room
.on('presence', { event: 'sync' }, () => {
const newState =
room?.presenceState<{ image: string; name: string }>() ?? {}
const newState = room?.presenceState<{ image: string; name: string }>() ?? {}
const newUsers = Object.fromEntries(
Object.entries(newState).map(([key, values]) => {

View File

@@ -32,4 +32,4 @@
}
],
"dependencies": ["@supabase/supabase-js@latest"]
}
}

View File

@@ -6,6 +6,14 @@ import { socialAuth } from './social-auth'
import { currentUserAvatar } from './current-user-avatar'
import { realtimeAvatarStack } from './realtime-avatar-stack'
const blocks = [...clients, ...passwordBasedAuth, ...socialAuth, ...dropzone, ...realtimeCursor, ...currentUserAvatar, ...realtimeAvatarStack]
const blocks = [
...clients,
...passwordBasedAuth,
...socialAuth,
...dropzone,
...realtimeCursor,
...currentUserAvatar,
...realtimeAvatarStack,
]
export { blocks }

View File

@@ -3,4 +3,4 @@ import { type RegistryItem } from 'shadcn/schema'
import nuxtjs from './default/realtime-avatar-stack/nuxtjs/registry-item.json' with { type: 'json' }
import vue from './default/realtime-avatar-stack/vue/registry-item.json' with { type: 'json' }
export const realtimeAvatarStack = [nuxtjs, vue] as RegistryItem[]
export const realtimeAvatarStack = [nuxtjs, vue] as RegistryItem[]