From 13204670490fa7e576e21f796ced20954d61c2cc Mon Sep 17 00:00:00 2001 From: NandkishorJadoun <183695114+NandkishorJadoun@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:33:12 +0530 Subject: [PATCH 1/3] feat(oauth): support dynamic client URI for Vercel preview deployments --- modules/oauth.ts | 25 ++++++++++++++++++++++++- server/utils/atproto/oauth.ts | 5 +++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/modules/oauth.ts b/modules/oauth.ts index ad0c8fbbc8..a7fc10e062 100644 --- a/modules/oauth.ts +++ b/modules/oauth.ts @@ -1,4 +1,4 @@ -import { defineNuxtModule, useNuxt } from 'nuxt/kit' +import { defineNuxtModule, useNuxt, addTemplate } from 'nuxt/kit' import { join } from 'node:path' import { appendFileSync, existsSync, readFileSync } from 'node:fs' import { randomUUID } from 'node:crypto' @@ -9,6 +9,29 @@ export default defineNuxtModule({ }, setup() { const nuxt = useNuxt() + + const env = process.env.NUXT_ENV_VERCEL_ENV + const previewUrl = process.env.NUXT_ENV_VERCEL_URL + const prodUrl = process.env.NUXT_ENV_VERCEL_PROJECT_PRODUCTION_URL + + let clientUri: string + if (env === 'preview' && previewUrl) { + clientUri = `https://${previewUrl}` + } else if (env === 'production' && prodUrl) { + clientUri = `https://${prodUrl}` + } else { + clientUri = 'http://127.0.0.1:3000' + } + + // bake it into a virtual file + const template = addTemplate({ + filename: 'oauth-config.mjs', + getContents: () => `export const clientUri = ${JSON.stringify(clientUri)};`, + write: true, + }) + + nuxt.options.alias['#oauth/config'] = template.dst + if (nuxt.options._prepare || process.env.NUXT_SESSION_PASSWORD) { return } diff --git a/server/utils/atproto/oauth.ts b/server/utils/atproto/oauth.ts index 845b36569d..020d76e0f6 100644 --- a/server/utils/atproto/oauth.ts +++ b/server/utils/atproto/oauth.ts @@ -6,14 +6,15 @@ import { getOAuthLock } from '#server/utils/atproto/lock' import { useOAuthStorage } from '#server/utils/atproto/storage' import { UNSET_NUXT_SESSION_PASSWORD } from '#shared/utils/constants' import { OAuthMetadataSchema } from '#shared/schemas/oauth' +// @ts-ignore: virtual file from oauth module +import { clientUri } from '#oauth/config' // TODO: limit scope as features gets added. atproto just allows login so no scary login screen till we have scopes export const scope = 'atproto' export function getOauthClientMetadata() { const dev = import.meta.dev - // on dev, match in nuxt.config.ts devServer: { host: "127.0.0.1" } - const client_uri = dev ? `http://127.0.0.1:3000` : 'https://npmx.dev' + const client_uri = clientUri const redirect_uri = `${client_uri}/api/auth/atproto` const client_id = dev From c33a8e71d16350ba81279b487c16f670c163c611 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 2 Feb 2026 16:20:29 +0000 Subject: [PATCH 2/3] refactor: addServerTemplate --- modules/oauth.ts | 9 +++------ server/utils/atproto/oauth.ts | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/modules/oauth.ts b/modules/oauth.ts index a7fc10e062..9e03d309e3 100644 --- a/modules/oauth.ts +++ b/modules/oauth.ts @@ -1,4 +1,4 @@ -import { defineNuxtModule, useNuxt, addTemplate } from 'nuxt/kit' +import { defineNuxtModule, useNuxt, addServerTemplate } from 'nuxt/kit' import { join } from 'node:path' import { appendFileSync, existsSync, readFileSync } from 'node:fs' import { randomUUID } from 'node:crypto' @@ -24,14 +24,11 @@ export default defineNuxtModule({ } // bake it into a virtual file - const template = addTemplate({ - filename: 'oauth-config.mjs', + addServerTemplate({ + filename: '#oauth/config', getContents: () => `export const clientUri = ${JSON.stringify(clientUri)};`, - write: true, }) - nuxt.options.alias['#oauth/config'] = template.dst - if (nuxt.options._prepare || process.env.NUXT_SESSION_PASSWORD) { return } diff --git a/server/utils/atproto/oauth.ts b/server/utils/atproto/oauth.ts index 020d76e0f6..fed470666d 100644 --- a/server/utils/atproto/oauth.ts +++ b/server/utils/atproto/oauth.ts @@ -6,7 +6,7 @@ import { getOAuthLock } from '#server/utils/atproto/lock' import { useOAuthStorage } from '#server/utils/atproto/storage' import { UNSET_NUXT_SESSION_PASSWORD } from '#shared/utils/constants' import { OAuthMetadataSchema } from '#shared/schemas/oauth' -// @ts-ignore: virtual file from oauth module +// @ts-expect-error virtual file from oauth module import { clientUri } from '#oauth/config' // TODO: limit scope as features gets added. atproto just allows login so no scary login screen till we have scopes export const scope = 'atproto' From 6e0682212e010079c238adf527528127bc7539d1 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 2 Feb 2026 16:22:20 +0000 Subject: [PATCH 3/3] chore: update knip config --- knip.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knip.json b/knip.json index 52016f8d92..aa76f1bd6e 100644 --- a/knip.json +++ b/knip.json @@ -36,7 +36,7 @@ "vite-plugin-pwa", "vue-router" ], - "ignoreUnresolved": ["#components"] + "ignoreUnresolved": ["#components", "#oauth/config"] }, "cli": { "project": ["src/**/*.ts"]