@windrun-huaiin/diaomao 11.2.0 → 12.0.0

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.
package/.gitignore CHANGED
@@ -9,6 +9,7 @@ lerna-debug.log*
9
9
  .pnpm-debug.log*
10
10
  .claude*
11
11
  .codex*
12
+ .gemini*
12
13
 
13
14
  # Diagnostic reports (https://nodejs.org/api/report.html)
14
15
  report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "scan": {
8
8
  "include": ["src/**/*.{tsx,ts,jsx,js}"],
9
- "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/**/*.d.ts", "node_modules/**"]
9
+ "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/**/*.d.ts", "node_modules/**", ".claude/**", ".gemini/**", ".codex/**", ".vscode/**", ".clerk/**"]
10
10
  },
11
11
  "blog": {
12
12
  "mdxDir": "src/mdx/blog",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/diaomao",
3
- "version": "11.2.0",
3
+ "version": "12.0.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -27,10 +27,10 @@
27
27
  "@radix-ui/react-slot": "^1.2.4",
28
28
  "@tailwindcss/typography": "^0.5.19",
29
29
  "@types/mdx": "^2.0.13",
30
- "@windrun-huaiin/backend-core": "^11.0.3",
31
- "@windrun-huaiin/base-ui": "^11.0.1",
32
- "@windrun-huaiin/lib": "^11.0.1",
33
- "@windrun-huaiin/third-ui": "^11.1.0",
30
+ "@windrun-huaiin/backend-core": "^12.0.0",
31
+ "@windrun-huaiin/base-ui": "^12.0.0",
32
+ "@windrun-huaiin/lib": "^12.0.0",
33
+ "@windrun-huaiin/third-ui": "^12.0.0",
34
34
  "autoprefixer": "^10.4.22",
35
35
  "class-variance-authority": "^0.7.1",
36
36
  "clsx": "^2.1.1",
@@ -77,7 +77,7 @@
77
77
  "@types/react-medium-image-zoom": "^3.0.3",
78
78
  "@types/uuid": "^10.0.0",
79
79
  "@typescript-eslint/parser": "^8.46.4",
80
- "@windrun-huaiin/dev-scripts": "^11.0.3",
80
+ "@windrun-huaiin/dev-scripts": "^12.0.0",
81
81
  "eslint": "^9.39.1",
82
82
  "eslint-config-next": "^16.0.0",
83
83
  "eslint-plugin-unused-imports": "^4.3.0",
@@ -7,26 +7,29 @@ import { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
7
7
  import { getTranslations } from 'next-intl/server';
8
8
  import { CreditPopover } from '@/components/credit-popover';
9
9
  import { ExtendedLinkItem, HomeTitle } from '@windrun-huaiin/third-ui/fuma/base';
10
+ import { getOptionalAuth } from '@windrun-huaiin/third-ui/clerk/patch/optional-auth';
11
+ import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
10
12
 
11
13
  // home page normal menu
12
14
  export async function homeNavLinks(locale: string): Promise<ExtendedLinkItem[]> {
13
15
  const t1 = await getTranslations({ locale: locale, namespace: 'linkPreview' });
16
+ const { userId } = await getOptionalAuth();
14
17
  return [
15
18
  {
16
19
  icon: <icons.BugOff />,
17
20
  text: t1('blog'),
18
- url: `/${locale}/blog`,
21
+ url: getAsNeededLocalizedUrl(locale, '/blog'),
19
22
  },
20
23
  {
21
24
  icon: <icons.BTC />,
22
25
  text: t1('pricing'),
23
- url: `/${locale}/pricing`,
26
+ url: getAsNeededLocalizedUrl(locale, '/pricing'),
24
27
  },
25
28
  {
26
29
  type: 'custom',
27
30
  secondary: true,
28
31
  mobilePinned: true,
29
- children: <CreditPopover locale={locale} />,
32
+ children: userId ? <CreditPopover locale={locale} /> : null,
30
33
  },
31
34
  {
32
35
  type: 'custom',
@@ -49,7 +52,7 @@ export async function baseOptions(locale: string): Promise<BaseLayoutProps> {
49
52
  const t = await getTranslations({ locale: locale, namespace: 'home' });
50
53
  return {
51
54
  nav: {
52
- url: `/${locale}`,
55
+ url: getAsNeededLocalizedUrl(locale, '/'),
53
56
  title: (
54
57
  <>
55
58
  <SiteIcon />
@@ -8,6 +8,7 @@ import { RootProvider } from "fumadocs-ui/provider/next";
8
8
  import { ClerkProviderClient } from '@windrun-huaiin/third-ui/clerk';
9
9
  import { NextIntlClientProvider } from 'next-intl';
10
10
  import { getMessages, getTranslations, setRequestLocale } from 'next-intl/server';
11
+ import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
11
12
  import React from 'react';
12
13
  import './globals.css';
13
14
 
@@ -27,9 +28,10 @@ export async function generateMetadata({
27
28
  keywords: t('keywords'),
28
29
  metadataBase: new URL(appConfig.baseUrl),
29
30
  alternates: {
30
- canonical: `${appConfig.baseUrl}/${locale}`,
31
+ canonical: `${appConfig.baseUrl}${getAsNeededLocalizedUrl(locale, '/')}`,
31
32
  languages: {
32
- "en": `${appConfig.baseUrl}/en`,
33
+ "en": `${appConfig.baseUrl}${getAsNeededLocalizedUrl('en', '/')}`,
34
+ "zh": `${appConfig.baseUrl}${getAsNeededLocalizedUrl('zh', '/')}`,
33
35
  }
34
36
  },
35
37
  icons: [
@@ -7,6 +7,7 @@ import { CreditOverview, buildMoneyPriceData } from '@windrun-huaiin/third-ui/ma
7
7
  import { moneyPriceConfig } from '@windrun-huaiin/backend-core/lib';
8
8
  import { buildInitUserContextFromEntities } from '@windrun-huaiin/backend-core/context';
9
9
  import { getTranslations } from 'next-intl/server';
10
+ import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
10
11
 
11
12
  interface CreditPopoverProps {
12
13
  locale: string;
@@ -88,7 +89,7 @@ export async function CreditPopover({ locale }: CreditPopoverProps) {
88
89
  : [])
89
90
  ];
90
91
 
91
- const pricingPageBaseUrl = `/${locale}/pricing`;
92
+ const pricingPageBaseUrl = getAsNeededLocalizedUrl(locale, "/pricing");
92
93
 
93
94
  const data: CreditOverviewData = {
94
95
  totalBalance,
package/src/i18n.ts CHANGED
@@ -5,6 +5,7 @@ import type { I18nConfig } from 'fumadocs-core/i18n';
5
5
  export const i18n: I18nConfig = {
6
6
  defaultLanguage: appConfig.i18n.defaultLocale,
7
7
  languages: appConfig.i18n.locales as unknown as string[],
8
+ hideLocale: appConfig.i18n.localPrefixAsNeeded ? "default-locale" : "never",
8
9
  }
9
10
 
10
11
  // Can be imported from a shared config
@@ -14,6 +14,8 @@ export const appConfig = {
14
14
  // export i18n helpers
15
15
  export const { isSupportedLocale, getValidLocale, generatedLocales } = createI18nHelpers(appConfig.i18n);
16
16
 
17
+ export const { localPrefixAsNeeded, defaultLocale } = appConfig.i18n;
18
+
17
19
  // export shortcuts
18
20
  export const { iconColor, watermark, showBanner, clerkPageBanner, clerkAuthInModal, placeHolderImage } = appConfig.shortcuts;
19
21
 
@@ -2,13 +2,13 @@
2
2
  title: Blog
3
3
  description: Articles and thoughts about various topics.
4
4
  icon: Rss
5
- date: 2025-12-21
5
+ date: 2025-12-22
6
6
  ---
7
7
 
8
8
  ## Past List
9
9
 
10
10
  <Cards>
11
- <ZiaCard icon={<Gift />} href="blog/nextjs-architecture" title="About Project Structure">
11
+ <ZiaCard icon={<Gift />} href="blog/readme" title="About Project Structure">
12
12
  2025-12-21
13
13
  </ZiaCard>
14
14
  <ZiaCard href="blog/async-architecture" title="异步处理架构升级方案">
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  title: Monthly Summary
3
3
  description: Index and Summary
4
- date: 2025-12-21
4
+ date: 2025-12-22
5
5
  ---
6
6
 
7
7
 
8
8
  ## Overview
9
9
  <Files>
10
10
  <ZiaFolder name="2025-12(1)" defaultOpen>
11
- <ZiaFile name="2025-12-21(About Project Structure)" href="./nextjs-architecture" />
11
+ <ZiaFile name="2025-12-21(About Project Structure)" href="./readme" />
12
12
  </ZiaFolder>
13
13
  <ZiaFolder name="2025-08(1)">
14
14
  <ZiaFile name="2025-08-02(异步处理架构升级方案)" href="./async-architecture" />
@@ -8,11 +8,11 @@ date: 2025-06-23
8
8
  # Legal is very important
9
9
 
10
10
  <Cards>
11
- <Card icon={<ReceiptText />} title="Term Service">
11
+ <ZiaCard icon={<ReceiptText />} href="legal/terms" title="Term Service">
12
12
  Know your rights and obligations, and what services we provide
13
- </Card>
14
- <Card icon={<ShieldUser />} title="Privacy">
13
+ </ZiaCard>
14
+ <ZiaCard icon={<ShieldUser />} href="legal/privacy" title="Privacy">
15
15
  Know your personal information and how we use it
16
- </Card>
16
+ </ZiaCard>
17
17
  </Cards>
18
18
 
package/src/proxy.ts CHANGED
@@ -11,12 +11,10 @@ import createMiddleware from "next-intl/middleware";
11
11
  import { NextRequest, NextResponse } from "next/server";
12
12
 
13
13
  const intlMiddleware = createMiddleware({
14
- // 多语言配置
15
14
  locales: appConfig.i18n.locales,
16
- // 默认语言配置
17
15
  defaultLocale: appConfig.i18n.defaultLocale,
18
- localePrefix: "always", // 改为 always,确保始终使用语言前缀
19
- localeDetection: false // 添加此配置以禁用自动语言检测
16
+ localePrefix: appConfig.i18n.localPrefixAsNeeded ? "as-needed" : "always",
17
+ localeDetection: false
20
18
  });
21
19
 
22
20
  // 需要身份认证的路由(页面路由)
@@ -54,6 +52,29 @@ const publicApiRoutes = createRouteMatcher([
54
52
  // 完全不需要再包一层函数,也不需要手动 (req)
55
53
  export default clerkMiddleware(
56
54
  async (auth, req: NextRequest) => {
55
+ const { defaultLocale, locales } = appConfig.i18n;
56
+ const pathname = req.nextUrl.pathname;
57
+ const hasLocalePrefix = locales.some(
58
+ (loc) => pathname === `/${loc}` || pathname.startsWith(`/${loc}/`)
59
+ );
60
+
61
+ // 对于无语言前缀的页面请求,根据配置进行处理
62
+ // 避免落不到 [locale] 路由。
63
+ if (!hasLocalePrefix && !pathname.startsWith('/api/')) {
64
+ const url = req.nextUrl.clone();
65
+ url.pathname = `/${defaultLocale}${pathname}`;
66
+
67
+ if (appConfig.i18n.localPrefixAsNeeded) {
68
+ // as-needed: 内部rewrite,用户URL保持无前缀
69
+ console.log('[middleware rewrite]', { from: pathname, to: url.pathname });
70
+ return NextResponse.rewrite(url);
71
+ } else {
72
+ // always: 重定向给用户,让他们看到前缀URL
73
+ console.log('[middleware redirect]', { from: pathname, to: url.pathname });
74
+ return NextResponse.redirect(url);
75
+ }
76
+ }
77
+
57
78
  // 1. 处理需要认证的页面路由
58
79
  if (protectedPageRoutes(req)) {
59
80
  const { userId: clerkUserId } = await auth();
@@ -93,13 +114,6 @@ export default clerkMiddleware(
93
114
  }
94
115
 
95
116
  // 5. 其他路由使用默认的国际化中间件处理
96
- // handle root path to default locale permanent redirect
97
- if (req.nextUrl.pathname === "/") {
98
- return NextResponse.redirect(
99
- new URL(`/${appConfig.i18n.defaultLocale}`, req.url),
100
- 301
101
- );
102
- }
103
117
 
104
118
  // handle trailing slash redirect
105
119
  if (req.nextUrl.pathname.length > 1 && req.nextUrl.pathname.endsWith("/")) {
@@ -117,7 +131,7 @@ export default clerkMiddleware(
117
131
  export const config = {
118
132
  matcher: [
119
133
  // Skip Next.js internals and all static files, but include API routes
120
- "/((?!_next|sitemap.xml?|robots.txt?|[^?]*.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
134
+ "/((?!_next|sitemap.xml?|robots.txt?|[^?]*.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|txt|webmanifest)).*)",
121
135
  // Include API routes explicitly
122
136
  "/api/(.*)",
123
137
  ],