Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/atrium-telegram/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Main database
DATABASE_URL=

# Main API
NUXT_PUBLIC_CORE_API_URL=

# Telegram
NUXT_TELEGRAM_ADMIN_ID=
NUXT_TELEGRAM_ATRIUM_BOT_ID=
Expand Down
2 changes: 1 addition & 1 deletion apps/atrium-telegram/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:tooltip="{ delayDuration: 0 }"
:toaster="{
position: 'top-center',
class: 'mt-16',
class: 'mt-20',
}"
class="min-h-svh"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ const emit = defineEmits(['success', 'submitted'])

type FormMember = { label: string, value: string, avatar: { src: string | undefined, alt: string } }

const { t } = useI18n()
const { vibrate } = useFeedback()
const actionToast = useActionToast()

const userStore = useUserStore()
const epicStore = useEpicStore()
Expand Down Expand Up @@ -94,11 +92,10 @@ watch(selectedMembers, () => {
})

async function onSubmit(event: FormSubmitEvent<CreateBeacon>) {
const toastId = actionToast.start()
emit('submitted')

try {
await $fetch(`https://atrium.sushi-love.ru/api/epic/comment/id/${commentId}/beacon`, {
await $fetch(`/api/epic/comment/id/${commentId}/beacon`, {
method: 'POST',
body: event.data,
})
Expand All @@ -109,12 +106,10 @@ async function onSubmit(event: FormSubmitEvent<CreateBeacon>) {
notificationStore.update(),
])

actionToast.success(toastId, t('toast.beacon-created'))
vibrate('success')
emit('success')
} catch (error) {
console.error(error)
actionToast.error(toastId)
vibrate('error')
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,10 @@ async function onSubmit(event: FormSubmitEvent<UploadMedia>) {
const formData = new FormData()
formData.append('file', event.data.file)

await $fetch(`/api/user/id/${userStore.id}/image`, {
const { public: publicEnv } = useRuntimeConfig()

await $fetch(`${publicEnv.coreApiUrl}/user/id/${userStore.id}/image`, {
method: 'POST',
headers: {
Authorization: `tma ${userStore.initDataRaw}`,
},
body: formData,
})
Comment on lines +67 to 72
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Auth regression: cross-origin request sends no credentials.

Switching to coreApiUrl without Authorization or credentials will 401. Either route via a local proxy endpoint or include credentials.

Apply minimal fix:

-    await $fetch(`${publicEnv.coreApiUrl}/user/id/${userStore.id}/image`, {
+    await $fetch(`${publicEnv.coreApiUrl}/user/id/${userStore.id}/image`, {
       method: 'POST',
       body: formData,
+      credentials: 'include',
     })

If cookies aren’t first-party to coreApiUrl, prefer a Nuxt server proxy (e.g., POST /api/user/id/[id]/image) to avoid CORS + cookies pitfalls.


🏁 Script executed:

#!/bin/bash
# Confirm no remaining direct calls to core API that need credentials
rg -nP --type=vue --type=ts '\$\s*fetch\(\s*`?\${?publicEnv\.coreApiUrl' -C2

Length of output: 106


🏁 Script executed:

#!/bin/bash
# Confirm no other direct $fetch calls to coreApiUrl without credentials
rg -nP '\$fetch\(\s*`.*publicEnv\.coreApiUrl' -C2 --glob '*.vue'
rg -nP '\$fetch\(\s*`.*publicEnv\.coreApiUrl' -C2 --glob '*.ts'

Length of output: 1197


Auth regression: include credentials or proxy for all coreApiUrl fetch calls

Two direct $fetch calls to publicEnv.coreApiUrl lack credentials/authorization and will 401:

  • apps/atrium-telegram/app/components/form/UploadUserAvatar.vue (lines 69–72)
  • apps/atrium-telegram/server/api/epic/comment/id/[commentId]/beacon.post.ts (lines 22–24)

Apply minimal fixes:

# File: UploadUserAvatar.vue
 await $fetch(`${publicEnv.coreApiUrl}/user/id/${userStore.id}/image`, {
   method: 'POST',
   body: formData,
+  credentials: 'include',
 })

# File: beacon.post.ts
 await $fetch(`${publicEnv.coreApiUrl}/epic/comment/id/${commentId}/beacon`, {
   method: 'POST',
   body: data,
+  credentials: 'include',
 })

If cookies aren’t first-party to coreApiUrl, route client calls via a Nuxt server proxy endpoint to avoid CORS and cookie pitfalls.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { public: publicEnv } = useRuntimeConfig()
await $fetch(`${publicEnv.coreApiUrl}/user/id/${userStore.id}/image`, {
method: 'POST',
headers: {
Authorization: `tma ${userStore.initDataRaw}`,
},
body: formData,
})
const { public: publicEnv } = useRuntimeConfig()
await $fetch(`${publicEnv.coreApiUrl}/user/id/${userStore.id}/image`, {
method: 'POST',
body: formData,
credentials: 'include',
})
🤖 Prompt for AI Agents
In apps/atrium-telegram/app/components/form/UploadUserAvatar.vue around lines 67
to 72, the client $fetch to publicEnv.coreApiUrl is missing credentials and will
401; either add credentials to the client request (e.g., pass credentials:
"include" / appropriate auth headers via useFetch/$fetch options) or, if
coreApiUrl cookies are not first‑party, replace the direct call with a Nuxt
server proxy endpoint: create a server API route that receives the form data
from the client and forwards the POST to coreApiUrl including server-side
cookies/authorization, then call that internal endpoint from the component.
Ensure the chosen fix propagates formData correctly and handles/forwards errors.


Expand Down
3 changes: 3 additions & 0 deletions apps/atrium-telegram/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export default defineNuxtConfig({
adminId: '',
teamGroupId: '',
},
public: {
coreApiUrl: '',
},
},
ui: {
colorMode: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createBeaconSchema } from '#shared/services/notification'
import { type } from 'arktype'

export default defineEventHandler(async (event) => {
try {
const commentId = getRouterParam(event, 'commentId')
if (!commentId) {
throw createError({
statusCode: 400,
message: 'Id is required',
})
}

const body = await readBody(event)
const data = createBeaconSchema(body)
if (data instanceof type.errors) {
throw data
}

const { public: publicEnv } = useRuntimeConfig()

await $fetch(`${publicEnv.coreApiUrl}/epic/comment/id/${commentId}/beacon`, {
method: 'POST',
body: data,
})

return {
ok: true,
}
} catch (error) {
throw errorResolver(error)
}
Comment on lines +30 to +32
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure errorResolver is available/imported

errorResolver isn’t a Nitro/H3 builtin. If not globally auto-imported, this will throw at runtime. Please verify and add an explicit import if needed.

Run to locate its definition:

If it lives under a util path, import it explicitly at the top of this file.


🏁 Script executed:

#!/bin/bash
rg -nP -C2 '\b(errorResolver)\b' --type=ts --type=js

Length of output: 44144


🏁 Script executed:

#!/bin/bash
head -n 20 apps/atrium-telegram/server/api/epic/comment/id/[commentId]/beacon.post.ts

Length of output: 620


Import errorResolver at the top of beacon.post.ts
This handler calls errorResolver (from apps/atrium-telegram/server/utils/error.ts) but never imports it. Add, for example, immediately after the existing imports:

import { errorResolver } from '../../../../../utils/error'

—adjust the relative path or alias to match your project’s resolver.

🤖 Prompt for AI Agents
In apps/atrium-telegram/server/api/epic/comment/id/[commentId]/beacon.post.ts
around lines 30 to 32 the file uses errorResolver but never imports it; add an
import for errorResolver from the utils/error module at the top of the file (for
example: import { errorResolver } from '../../../../../utils/error') or adjust
the path/alias to match the project, then ensure the import is included with the
other imports so the catch block can call errorResolver without a
ReferenceError.

})
2 changes: 2 additions & 0 deletions apps/atrium-telegram/shared/services/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const ACCEPTED_IMAGE_TYPES = [
'image/png',
'image/webp',
'image/gif',
'image/avif',
'image/heif',
Comment on lines +10 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add image/heic to accepted MIME types (iOS default).

Mirror the web-app change; otherwise HEIC uploads from iOS will be rejected client-side.

Apply:

   'image/gif',
   'image/avif',
   'image/heif',
+  'image/heic',
 ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'image/avif',
'image/heif',
'image/gif',
'image/avif',
'image/heif',
'image/heic',
]
🤖 Prompt for AI Agents
In apps/atrium-telegram/shared/services/media.ts around lines 10 to 11, the
accepted MIME types array is missing 'image/heic' (iOS default) which causes
HEIC uploads to be rejected; add the string 'image/heic' to the list of accepted
MIME types (e.g., alongside 'image/heif' and 'image/avif') so the client will
allow HEIC images.

]

const FileSchema = type('File')
Expand Down
2 changes: 1 addition & 1 deletion apps/web-app/server/api/user/id/[userId]/image.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const USER_AVATARS_DIRECTORY = 'users'

const IMAGE_SIZES = [256, 512]
const IMAGE_FORMATS = ['jpg', 'webp'] as const
const ACCEPTED_IMAGE_FORMATS = ['jpeg', 'jpg', 'png', 'webp']
const ACCEPTED_IMAGE_FORMATS = ['jpeg', 'jpg', 'png', 'webp', 'heif', 'avif']
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Include ‘heic’ and confirm runtime decode support.

  • Add 'heic' for broader HEIF coverage.
  • Ensure the deployment’s sharp/libvips build supports HEIF/AVIF decode; otherwise uploads will fail at metadata().

Apply:

-const ACCEPTED_IMAGE_FORMATS = ['jpeg', 'jpg', 'png', 'webp', 'heif', 'avif']
+const ACCEPTED_IMAGE_FORMATS = ['jpeg', 'jpg', 'png', 'webp', 'heif', 'heic', 'avif'] as const

To verify support and avoid regressions, run:

And confirm environment support:


🏁 Script executed:

#!/bin/bash
# Find all places that mention HEIF/AVIF and ensure consistency
rg -nC2 -i 'heif|heic|avif|ACCEPTED_IMAGE_FORMATS|ACCEPTED_IMAGE_TYPES'

# Optional: check sharp version used (lockfile)
fd lock | xargs -I{} rg -n 'sharp@' {}

Length of output: 5647


🌐 Web query:

Does the current sharp version used by Nuxt/Nitro support decoding HEIF/HEIC and AVIF by default, or does it require libvips/OS dependencies?

💡 Result:

Short answer: You still need libvips / OS libs for full HEIF/HEIC (HEVC) support; AVIF is supported by sharp’s prebuilt binaries. sharp’s docs/state that AVIF is included in prebuilt binaries, but HEIF/HEIC using HEVC requires a globally installed libvips compiled with libheif (and codecs like libde265/x265). [1][2]

Sources:

  • sharp API (HEIF notes). [1]
  • sharp changelog (AVIF/prebuilt binaries; HEIF requires libvips compiled with libheif). [2]

Add HEIC support and verify HEIF/HEIC decode dependencies

  • Update apps/web-app/server/api/user/id/[userId]/image.post.ts (line 10): include 'heic' in ACCEPTED_IMAGE_FORMATS (e.g. ['jpeg','jpg','png','webp','heif','heic','avif']) and consider appending as const.
  • Mirror in apps/web-app/shared/services/media.ts (line 10): add 'image/heic' to ACCEPTED_IMAGE_TYPES.
  • Confirm your deployment’s libvips build is compiled with libheif and HEVC codecs (sharp’s prebuilt binaries include AVIF but not full HEIF/HEIC support).
🤖 Prompt for AI Agents
In apps/web-app/server/api/user/id/[userId]/image.post.ts around line 10, add
'heic' to ACCEPTED_IMAGE_FORMATS (e.g.
['jpeg','jpg','png','webp','heif','heic','avif']) and consider marking the array
as readonly (as const); in apps/web-app/shared/services/media.ts around line 10,
add 'image/heic' to ACCEPTED_IMAGE_TYPES to mirror the change; finally, ensure
your deployment's libvips/sharp build includes libheif and required HEVC codecs
(or document fallback behavior) because sharp’s prebuilt binaries may not
provide full HEIF/HEIC support.


export default defineEventHandler(async (event) => {
let sharpStream
Expand Down
2 changes: 2 additions & 0 deletions apps/web-app/shared/services/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const ACCEPTED_IMAGE_TYPES = [
'image/png',
'image/webp',
'image/gif',
'image/avif',
'image/heif',
Comment on lines +10 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add image/heic to accepted MIME types (iOS default).

Many devices (notably iOS) upload HEIC as image/heic; current schema will reject them.

Apply:

   'image/gif',
   'image/avif',
   'image/heif',
+  'image/heic',
 ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'image/avif',
'image/heif',
'image/gif',
'image/avif',
'image/heif',
'image/heic',
]
🤖 Prompt for AI Agents
In apps/web-app/shared/services/media.ts around lines 10-11 the accepted MIME
types list is missing the iOS default 'image/heic', so uploads from many iOS
devices will be rejected; add 'image/heic' to the array of accepted MIME types
alongside the existing image/avif and image/heif entries, and run/update any
related validation/schema tests or type definitions that reference this list to
include the new value.

]

const FileSchema = type('File')
Expand Down