diff --git a/README.md b/README.md
index 52fc704..182cd1b 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,8 @@ AI-powered static blog generator with ATProto integration, part of the ai.ai eco
| Command | Description |
|---------|-------------|
-| `./run.zsh c` | Enable Cloudflare tunnel (xxxcard.syui.ai) for OAuth |
-| `./run.zsh o` | Start OAuth web server (port:4173 = xxxcard.syui.ai) |
+| `./run.zsh c` | Enable Cloudflare tunnel (log.syui.ai) for OAuth |
+| `./run.zsh o` | Start OAuth web server (port:4173 = log.syui.ai) |
| `./run.zsh co` | Start comment system (ATProto stream monitor) |
## 🏗️ Architecture (Pure Rust + HTML + JS)
diff --git a/aicard-web-oauth/.env b/aicard-web-oauth/.env
new file mode 100644
index 0000000..dbfe579
--- /dev/null
+++ b/aicard-web-oauth/.env
@@ -0,0 +1,4 @@
+# Default environment variables (fallback)
+VITE_APP_HOST=https://log.syui.ai
+VITE_OAUTH_CLIENT_ID=https://log.syui.ai/client-metadata.json
+VITE_OAUTH_REDIRECT_URI=https://log.syui.ai/oauth/callback
\ No newline at end of file
diff --git a/aicard-web-oauth/.env.development b/aicard-web-oauth/.env.development
new file mode 100644
index 0000000..97c77d4
--- /dev/null
+++ b/aicard-web-oauth/.env.development
@@ -0,0 +1,4 @@
+# Development environment variables
+VITE_APP_HOST=http://localhost:4173
+VITE_OAUTH_CLIENT_ID=http://localhost:4173/client-metadata.json
+VITE_OAUTH_REDIRECT_URI=http://localhost:4173/oauth/callback
\ No newline at end of file
diff --git a/aicard-web-oauth/.env.production b/aicard-web-oauth/.env.production
new file mode 100644
index 0000000..15692f4
--- /dev/null
+++ b/aicard-web-oauth/.env.production
@@ -0,0 +1,4 @@
+# Production environment variables
+VITE_APP_HOST=https://log.syui.ai
+VITE_OAUTH_CLIENT_ID=https://log.syui.ai/client-metadata.json
+VITE_OAUTH_REDIRECT_URI=https://log.syui.ai/oauth/callback
\ No newline at end of file
diff --git a/aicard-web-oauth/package.json b/aicard-web-oauth/package.json
index 4cff1b2..f6430cc 100644
--- a/aicard-web-oauth/package.json
+++ b/aicard-web-oauth/package.json
@@ -6,6 +6,7 @@
"dev": "vite --mode development",
"build": "vite build --mode production",
"build:dev": "vite build --mode development",
+ "build:local": "VITE_APP_HOST=http://localhost:4173 vite build --mode development",
"preview": "vite preview"
},
"dependencies": {
diff --git a/aicard-web-oauth/public/client-metadata.json b/aicard-web-oauth/public/client-metadata.json
index 4d79d3d..8af8db1 100644
--- a/aicard-web-oauth/public/client-metadata.json
+++ b/aicard-web-oauth/public/client-metadata.json
@@ -1,13 +1,13 @@
{
- "client_id": "https://xxxcard.syui.ai/client-metadata.json",
+ "client_id": "https://log.syui.ai/client-metadata.json",
"client_name": "ai.card",
- "client_uri": "https://xxxcard.syui.ai",
- "logo_uri": "https://xxxcard.syui.ai/favicon.ico",
- "tos_uri": "https://xxxcard.syui.ai/terms",
- "policy_uri": "https://xxxcard.syui.ai/privacy",
+ "client_uri": "https://log.syui.ai",
+ "logo_uri": "https://log.syui.ai/favicon.ico",
+ "tos_uri": "https://log.syui.ai/terms",
+ "policy_uri": "https://log.syui.ai/privacy",
"redirect_uris": [
- "https://xxxcard.syui.ai/oauth/callback",
- "https://xxxcard.syui.ai/"
+ "https://log.syui.ai/oauth/callback",
+ "https://log.syui.ai/"
],
"response_types": [
"code"
diff --git a/aicard-web-oauth/src/App.tsx b/aicard-web-oauth/src/App.tsx
index 3d105c2..8a37b5c 100644
--- a/aicard-web-oauth/src/App.tsx
+++ b/aicard-web-oauth/src/App.tsx
@@ -99,9 +99,9 @@ function App() {
return false;
};
- // キャッシュがなければ、ATProtoから取得
+ // キャッシュがなければ、ATProtoから取得(認証状態に関係なく)
if (!loadCachedComments()) {
- loadAllComments(window.location.href);
+ loadAllComments(); // URLフィルタリングを無効にして全コメント表示
}
// Handle popstate events for mock OAuth flow
@@ -142,7 +142,8 @@ function App() {
setUser(userProfile);
// Load all comments for display (this will be the default view)
- loadAllComments(window.location.href);
+ // Temporarily disable URL filtering to see all comments
+ loadAllComments();
// Load user list records if admin
if (userProfile.did === 'did:plc:uqzpqmrjnptsxezjx4xuh2mn') {
@@ -161,7 +162,8 @@ function App() {
setUser(verifiedUser);
// Load all comments for display (this will be the default view)
- loadAllComments(window.location.href);
+ // Temporarily disable URL filtering to see all comments
+ loadAllComments();
// Load user list records if admin
if (verifiedUser.did === 'did:plc:uqzpqmrjnptsxezjx4xuh2mn') {
@@ -169,6 +171,9 @@ function App() {
}
}
setIsLoading(false);
+
+ // 認証状態に関係なく、コメントを読み込む
+ loadAllComments();
};
checkAuth();
@@ -265,17 +270,20 @@ function App() {
try {
// 管理者のユーザーリストを取得 (ai.syui.log.user collection)
const adminDid = 'did:plc:uqzpqmrjnptsxezjx4xuh2mn'; // syui.ai
+ console.log('Fetching user list from admin DID:', adminDid);
const response = await fetch(`https://bsky.social/xrpc/com.atproto.repo.listRecords?repo=${encodeURIComponent(adminDid)}&collection=ai.syui.log.user&limit=100`);
if (!response.ok) {
- console.warn('Failed to fetch user list from admin, using default users');
+ console.warn('Failed to fetch user list from admin, using default users. Status:', response.status);
return getDefaultUsers();
}
const data = await response.json();
const userRecords = data.records || [];
+ console.log('User records found:', userRecords.length);
if (userRecords.length === 0) {
+ console.log('No user records found, using default users');
return getDefaultUsers();
}
@@ -349,20 +357,33 @@ function App() {
};
const getDefaultUsers = () => {
- return [
+ const defaultUsers = [
// bsky.social - 実際のDIDを使用
{ did: 'did:plc:uqzpqmrjnptsxezjx4xuh2mn', handle: 'syui.ai', pds: 'https://bsky.social' },
- // 他のユーザーは実際のDIDが不明なので、実在するユーザーのみ含める
];
+
+ // 現在ログインしているユーザーも追加(重複チェック)
+ if (user && user.did && user.handle && !defaultUsers.find(u => u.did === user.did)) {
+ defaultUsers.push({
+ did: user.did,
+ handle: user.handle,
+ pds: user.handle.endsWith('.syu.is') ? 'https://syu.is' : 'https://bsky.social'
+ });
+ }
+
+ console.log('Default users list (including current user):', defaultUsers);
+ return defaultUsers;
};
// 新しい関数: 全ユーザーからコメントを収集
const loadAllComments = async (pageUrl?: string) => {
try {
console.log('Loading comments from all users...');
+ console.log('Page URL filter:', pageUrl);
// ユーザーリストを動的に取得
const knownUsers = await loadUsersFromRecord();
+ console.log('Known users for comment fetching:', knownUsers);
const allComments = [];
@@ -388,7 +409,8 @@ function App() {
? userComments.filter(record => record.value.url === pageUrl)
: userComments;
- console.log(`After URL filtering: ${filteredComments.length} comments from ${user.handle}`);
+ console.log(`After URL filtering (${pageUrl}): ${filteredComments.length} comments from ${user.handle}`);
+ console.log('All comments from this user:', userComments.map(r => ({ url: r.value.url, text: r.value.text })));
allComments.push(...filteredComments);
} catch (err) {
console.warn(`Failed to load comments from ${user.handle}:`, err);
@@ -859,14 +881,16 @@ function App() {
diff --git a/aicard-web-oauth/src/services/atproto-oauth.ts b/aicard-web-oauth/src/services/atproto-oauth.ts
index 0a1235e..e4851bf 100644
--- a/aicard-web-oauth/src/services/atproto-oauth.ts
+++ b/aicard-web-oauth/src/services/atproto-oauth.ts
@@ -188,13 +188,15 @@ class AtprotoOAuthService {
}
private getClientId(): string {
- const origin = window.location.origin;
-
- // For production (xxxcard.syui.ai), use the actual URL
- if (origin.includes('xxxcard.syui.ai')) {
- return `${origin}/client-metadata.json`;
+ // Use environment variable if available
+ const envClientId = import.meta.env.VITE_OAUTH_CLIENT_ID;
+ if (envClientId) {
+ console.log('Using client ID from environment:', envClientId);
+ return envClientId;
}
+ const origin = window.location.origin;
+
// For localhost development, use undefined for loopback client
// The BrowserOAuthClient will handle this automatically
if (origin.includes('localhost') || origin.includes('127.0.0.1')) {
diff --git a/aicard-web-oauth/src/utils/oauth-keys.ts b/aicard-web-oauth/src/utils/oauth-keys.ts
index 85282d2..9be43d6 100644
--- a/aicard-web-oauth/src/utils/oauth-keys.ts
+++ b/aicard-web-oauth/src/utils/oauth-keys.ts
@@ -157,40 +157,19 @@ export class OAuthKeyManager {
* Generate dynamic client metadata based on current URL
*/
export function generateClientMetadata(): any {
- const origin = window.location.origin;
- const clientId = `${origin}/client-metadata.json`;
+ // Use environment variables if available, fallback to current origin
+ const host = import.meta.env.VITE_APP_HOST || window.location.origin;
+ const clientId = import.meta.env.VITE_OAUTH_CLIENT_ID || `${host}/client-metadata.json`;
+ const redirectUri = import.meta.env.VITE_OAUTH_REDIRECT_URI || `${host}/oauth/callback`;
- // Use static production metadata for xxxcard.syui.ai
- if (origin === 'https://xxxcard.syui.ai') {
- return {
- client_id: 'https://xxxcard.syui.ai/client-metadata.json',
- client_name: 'ai.card',
- client_uri: 'https://xxxcard.syui.ai',
- logo_uri: 'https://xxxcard.syui.ai/favicon.ico',
- tos_uri: 'https://xxxcard.syui.ai/terms',
- policy_uri: 'https://xxxcard.syui.ai/privacy',
- redirect_uris: ['https://xxxcard.syui.ai/oauth/callback'],
- response_types: ['code'],
- grant_types: ['authorization_code', 'refresh_token'],
- token_endpoint_auth_method: 'private_key_jwt',
- token_endpoint_auth_signing_alg: 'ES256',
- scope: 'atproto transition:generic',
- subject_type: 'public',
- application_type: 'web',
- dpop_bound_access_tokens: true,
- jwks_uri: 'https://xxxcard.syui.ai/.well-known/jwks.json'
- };
- }
-
- // Dynamic metadata for development
return {
client_id: clientId,
client_name: 'ai.card',
- client_uri: origin,
- logo_uri: `${origin}/favicon.ico`,
- tos_uri: `${origin}/terms`,
- policy_uri: `${origin}/privacy`,
- redirect_uris: [`${origin}/oauth/callback`],
+ client_uri: host,
+ logo_uri: `${host}/favicon.ico`,
+ tos_uri: `${host}/terms`,
+ policy_uri: `${host}/privacy`,
+ redirect_uris: [redirectUri, host],
response_types: ['code'],
grant_types: ['authorization_code', 'refresh_token'],
token_endpoint_auth_method: 'private_key_jwt',
@@ -199,6 +178,6 @@ export function generateClientMetadata(): any {
subject_type: 'public',
application_type: 'web',
dpop_bound_access_tokens: true,
- jwks_uri: `${origin}/.well-known/jwks.json`
+ jwks_uri: `${host}/.well-known/jwks.json`
};
}
\ No newline at end of file
diff --git a/aicard-web-oauth/vite.config.ts b/aicard-web-oauth/vite.config.ts
index 0fb8cad..0707304 100644
--- a/aicard-web-oauth/vite.config.ts
+++ b/aicard-web-oauth/vite.config.ts
@@ -1,31 +1,58 @@
-import { defineConfig } from 'vite'
+import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
+import fs from 'fs'
+import path from 'path'
-export default defineConfig({
- plugins: [react()],
- build: {
- // Keep console.log in production for debugging
- minify: 'esbuild',
- },
- esbuild: {
- drop: [], // Don't drop console.log
- },
- server: {
- port: 5173,
- host: '127.0.0.1',
- allowedHosts: ['localhost', '127.0.0.1', 'xxxcard.syui.ai'],
- proxy: {
- '/api': {
- target: 'http://127.0.0.1:8000',
- changeOrigin: true,
- secure: false,
+export default defineConfig(({ mode }) => {
+ // Load env file based on `mode` in the current working directory.
+ const env = loadEnv(mode, process.cwd(), '')
+
+ return {
+ plugins: [
+ react(),
+ // Custom plugin to replace variables in public files during build
+ {
+ name: 'replace-env-vars',
+ writeBundle() {
+ const host = env.VITE_APP_HOST || 'https://log.syui.ai'
+ const clientId = env.VITE_OAUTH_CLIENT_ID || `${host}/client-metadata.json`
+ const redirectUri = env.VITE_OAUTH_REDIRECT_URI || `${host}/oauth/callback`
+
+ // Replace variables in client-metadata.json
+ const clientMetadataPath = path.resolve(__dirname, 'dist/client-metadata.json')
+ if (fs.existsSync(clientMetadataPath)) {
+ let content = fs.readFileSync(clientMetadataPath, 'utf-8')
+ content = content.replace(/https:\/\/log\.syui\.ai/g, host)
+ fs.writeFileSync(clientMetadataPath, content)
+ console.log(`Updated client-metadata.json with host: ${host}`)
+ }
+ }
}
+ ],
+ build: {
+ // Keep console.log in production for debugging
+ minify: 'esbuild',
},
- // Handle OAuth callback routing
- historyApiFallback: {
- rewrites: [
- { from: /^\/oauth\/callback/, to: '/index.html' }
- ]
+ esbuild: {
+ drop: [], // Don't drop console.log
+ },
+ server: {
+ port: 5173,
+ host: '127.0.0.1',
+ allowedHosts: ['localhost', '127.0.0.1', 'log.syui.ai'],
+ proxy: {
+ '/api': {
+ target: 'http://127.0.0.1:8000',
+ changeOrigin: true,
+ secure: false,
+ }
+ },
+ // Handle OAuth callback routing
+ historyApiFallback: {
+ rewrites: [
+ { from: /^\/oauth\/callback/, to: '/index.html' }
+ ]
+ }
}
}
})
\ No newline at end of file
diff --git a/run.zsh b/run.zsh
index 580bff7..798da70 100755
--- a/run.zsh
+++ b/run.zsh
@@ -18,7 +18,8 @@ function _server() {
function _server_public() {
_env
- cloudflared tunnel --config $d/aicard-web-oauth/cloudflared-config.yml run
+ #cloudflared tunnel --config $d/aicard-web-oauth/cloudflared-config.yml run
+ cloudflared tunnel --config $d/cloudflared-config.yml run
}
function _oauth_build() {
@@ -29,6 +30,12 @@ function _oauth_build() {
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
nvm use 21
npm i
+
+ # Build with production environment variables
+ export VITE_APP_HOST="https://log.syui.ai"
+ export VITE_OAUTH_CLIENT_ID="https://log.syui.ai/client-metadata.json"
+ export VITE_OAUTH_REDIRECT_URI="https://log.syui.ai/oauth/callback"
+
npm run build
npm run preview
}