mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
🔧 chore: update eslint v2 configuration and suppressions (#12133)
* v2 init * chore: update eslint suppressions and package dependencies - Removed several eslint suppressions related to array sorting and reversing from eslint-suppressions.json to clean up the configuration. - Updated @lobehub/lint package version from 2.0.0-beta.6 to 2.0.0-beta.7 in package.json for improvements and bug fixes. - Made minor formatting adjustments in vitest.config.mts and various SKILL.md files for better readability and consistency. Signed-off-by: Innei <tukon479@gmail.com> * fix: clean up import statements and formatting - Removed unnecessary whitespace in replaceComponentImports.ts for improved readability. - Standardized import statements in contextEngineering.ts and createAgentExecutors.ts by adding missing spaces for consistency. Signed-off-by: Innei <tukon479@gmail.com> * chore: update eslint suppressions and clean up code formatting * 🐛 fix: use vi.hoisted for mock variable initialization Fix TDZ error in persona service test by using vi.hoisted() to ensure mock variables are available when vi.mock factory runs. --------- Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
import { Sitemap } from '@/server/sitemap';
|
||||
|
||||
dotenv.config();
|
||||
@@ -13,5 +14,4 @@ const genSitemap = async () => {
|
||||
writeFileSync(filename, sitemapIndexXML);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||
genSitemap().catch(console.error);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { consola } from 'consola';
|
||||
import { writeJSONSync } from 'fs-extra';
|
||||
import matter from 'gray-matter';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { writeJSONSync } from 'fs-extra';
|
||||
import matter from 'gray-matter';
|
||||
import pMap from 'p-map';
|
||||
|
||||
import { uploader } from './uploader';
|
||||
@@ -63,7 +64,7 @@ class ImageCDNUploader {
|
||||
const links: string[][] = posts.map((post) => {
|
||||
const mdx = readFileSync(post, 'utf8');
|
||||
const { content, data } = matter(mdx);
|
||||
let inlineLinks: string[] = extractHttpsLinks(content);
|
||||
const inlineLinks: string[] = extractHttpsLinks(content);
|
||||
|
||||
// 添加特定字段中的图片链接
|
||||
if (data?.image) inlineLinks.push(data.image);
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import {
|
||||
GetObjectCommand,
|
||||
PutObjectCommand,
|
||||
PutObjectCommandOutput,
|
||||
S3Client,
|
||||
S3ClientConfig,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import type { PutObjectCommandOutput, S3ClientConfig } from '@aws-sdk/client-s3';
|
||||
import { GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
|
||||
import type { ImgInfo, S3UserConfig, UploadResult } from './types';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import CryptoJS from 'crypto-js';
|
||||
import mime from 'mime';
|
||||
|
||||
import { ImgInfo } from './types';
|
||||
import type { ImgInfo } from './types';
|
||||
|
||||
class FileNameGenerator {
|
||||
date: Date;
|
||||
|
||||
@@ -9,19 +9,19 @@ dotenv.config();
|
||||
|
||||
if (!process.env.DOC_S3_ACCESS_KEY_ID) {
|
||||
consola.error('请配置 Doc S3 存储的环境变量: DOC_S3_ACCESS_KEY_ID');
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!process.env.DOC_S3_SECRET_ACCESS_KEY) {
|
||||
consola.error('请配置 Doc S3 存储的环境变量: DOC_S3_SECRET_ACCESS_KEY');
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!process.env.DOC_S3_PUBLIC_DOMAIN) {
|
||||
consola.error('请配置 Doc S3 存储的环境变量: DOC_S3_PUBLIC_DOMAIN');
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { readJSONSync } from 'fs-extra';
|
||||
import { globSync } from 'glob';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { opimized, opimizedGif } from './optimized';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { consola } from 'consola';
|
||||
import { readJsonSync, writeJSONSync } from 'fs-extra';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { readJsonSync, writeJSONSync } from 'fs-extra';
|
||||
import semver from 'semver';
|
||||
|
||||
import { markdownToTxt } from '@/utils/markdownToTxt';
|
||||
@@ -18,7 +19,7 @@ export interface ChangelogStaticItem {
|
||||
|
||||
class BuildStaticChangelog {
|
||||
private removeDetailsTag = (changelog: string): string => {
|
||||
const detailsRegex: RegExp = /<details\b[^>]*>[\S\s]*?<\/details>/gi;
|
||||
const detailsRegex: RegExp = /<details\b[^>]*>[\s\S]*?<\/details>/gi;
|
||||
return changelog.replaceAll(detailsRegex, '');
|
||||
};
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ const checkConsoleLogs = () => {
|
||||
}
|
||||
|
||||
const lines = output.trim().split('\n');
|
||||
const violations: Array<{ content: string, file: string; line: string; }> = [];
|
||||
const violations: Array<{ content: string; file: string; line: string }> = [];
|
||||
|
||||
for (const line of lines) {
|
||||
// Parse git grep output: filename:lineNumber:content
|
||||
@@ -105,7 +105,9 @@ const checkConsoleLogs = () => {
|
||||
}
|
||||
|
||||
if (violations.length === 0) {
|
||||
console.log('✅ No console.log violations found (all matches are whitelisted or in comments)!');
|
||||
console.log(
|
||||
'✅ No console.log violations found (all matches are whitelisted or in comments)!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,7 +120,9 @@ const checkConsoleLogs = () => {
|
||||
for (const violation of violations) {
|
||||
if (isCI) {
|
||||
// GitHub Actions warning annotation format
|
||||
console.log(`::warning file=${violation.file},line=${violation.line}::console.log found: ${violation.content}`);
|
||||
console.log(
|
||||
`::warning file=${violation.file},line=${violation.line}::console.log found: ${violation.content}`,
|
||||
);
|
||||
} else {
|
||||
console.log(` ${violation.file}:${violation.line}`);
|
||||
console.log(` ${violation.content}\n`);
|
||||
@@ -126,9 +130,7 @@ const checkConsoleLogs = () => {
|
||||
}
|
||||
|
||||
console.log(`\n💡 Total violations: ${violations.length}`);
|
||||
console.log(
|
||||
`\n📝 To whitelist files, add them to ${WHITELIST_PATH} in the following format:`,
|
||||
);
|
||||
console.log(`\n📝 To whitelist files, add them to ${WHITELIST_PATH} in the following format:`);
|
||||
console.log(`{
|
||||
"files": ["path/to/file.ts"],
|
||||
"patterns": ["scripts/**/*.mts", "**/*.test.ts"]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import './env';
|
||||
|
||||
import type { ClerkToBetterAuthMode, DatabaseDriver } from './types';
|
||||
|
||||
const DEFAULT_MODE: ClerkToBetterAuthMode = 'test';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Pool as NeonPool, neonConfig } from '@neondatabase/serverless';
|
||||
import { neonConfig, Pool as NeonPool } from '@neondatabase/serverless';
|
||||
import { drizzle as neonDrizzle } from 'drizzle-orm/neon-serverless';
|
||||
import { drizzle as nodeDrizzle } from 'drizzle-orm/node-postgres';
|
||||
import { Pool as NodePool } from 'pg';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
|
||||
import { resolveDataPaths } from './config';
|
||||
import { CSVUserRow, ClerkUser } from './types';
|
||||
import type { ClerkUser, CSVUserRow } from './types';
|
||||
|
||||
export function parseCsvLine(line: string): string[] {
|
||||
const cells: string[] = [];
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await, unicorn/no-process-exit */
|
||||
import './_internal/env';
|
||||
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
|
||||
import { getClerkSecret, getMigrationMode, resolveDataPaths } from './_internal/config';
|
||||
import './_internal/env';
|
||||
import { ClerkApiUser, ClerkUser } from './_internal/types';
|
||||
import type { ClerkApiUser, ClerkUser } from './_internal/types';
|
||||
|
||||
/**
|
||||
* Fetch all Clerk users via REST API and persist them into a local JSON file.
|
||||
@@ -150,10 +150,7 @@ async function fetchAllClerkUsers(secretKey: string): Promise<ClerkUser[]> {
|
||||
const userMap = new Map<string, ClerkUser>();
|
||||
|
||||
// Get total count first
|
||||
const countResponse = await fetchClerkApi<{ total_count: number }>(
|
||||
secretKey,
|
||||
'/users/count',
|
||||
);
|
||||
const countResponse = await fetchClerkApi<{ total_count: number }>(secretKey, '/users/count');
|
||||
const totalCount = countResponse.total_count;
|
||||
const totalPages = Math.ceil(totalCount / PAGE_SIZE);
|
||||
const offsets = Array.from({ length: totalPages }, (_, pageIndex) => pageIndex * PAGE_SIZE);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
import { getMigrationMode } from './_internal/config';
|
||||
import { db, pool, schema } from './_internal/db';
|
||||
import { loadCSVData, loadClerkUsersFromFile } from './_internal/load-data-from-files';
|
||||
import { ClerkExternalAccount } from './_internal/types';
|
||||
import { loadClerkUsersFromFile, loadCSVData } from './_internal/load-data-from-files';
|
||||
import type { ClerkExternalAccount } from './_internal/types';
|
||||
import { generateBackupCodes, safeDateConversion } from './_internal/utils';
|
||||
|
||||
const BATCH_SIZE = Number(process.env.CLERK_TO_BETTERAUTH_BATCH_SIZE) || 300;
|
||||
@@ -81,7 +80,7 @@ async function migrateFromClerk() {
|
||||
let processed = 0;
|
||||
let accountAttempts = 0;
|
||||
let twoFactorAttempts = 0;
|
||||
let skipped = csvUsers.length - unprocessedUsers.length;
|
||||
const skipped = csvUsers.length - unprocessedUsers.length;
|
||||
const startedAt = Date.now();
|
||||
const accountCounts: Record<string, number> = {};
|
||||
let missingScopeNonCredential = 0;
|
||||
@@ -154,7 +153,7 @@ async function migrateFromClerk() {
|
||||
createdAt: safeDateConversion(externalAccount.created_at),
|
||||
id: externalAccount.id,
|
||||
providerId,
|
||||
scope: externalAccount.approved_scopes?.replace(/\s+/g, ',') || undefined,
|
||||
scope: externalAccount.approved_scopes?.replaceAll(/\s+/g, ',') || undefined,
|
||||
updatedAt: safeDateConversion(externalAccount.updated_at),
|
||||
userId: user.id,
|
||||
});
|
||||
@@ -306,10 +305,15 @@ async function main() {
|
||||
try {
|
||||
await migrateFromClerk();
|
||||
console.log('');
|
||||
console.log(`${GREEN_BOLD}✅ Migration success!${RESET} (${formatDuration(Date.now() - startedAt)})`);
|
||||
console.log(
|
||||
`${GREEN_BOLD}✅ Migration success!${RESET} (${formatDuration(Date.now() - startedAt)})`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log('');
|
||||
console.error(`${RED_BOLD}❌ Migration failed${RESET} (${formatDuration(Date.now() - startedAt)}):`, error);
|
||||
console.error(
|
||||
`${RED_BOLD}❌ Migration failed${RESET} (${formatDuration(Date.now() - startedAt)}):`,
|
||||
error,
|
||||
);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
await pool.end();
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import { getMigrationMode, resolveDataPaths } from './_internal/config';
|
||||
import { db, pool, schema } from './_internal/db';
|
||||
import { loadCSVData, loadClerkUsersFromFile } from './_internal/load-data-from-files';
|
||||
import { ClerkExternalAccount, ClerkUser } from './_internal/types';
|
||||
import { loadClerkUsersFromFile, loadCSVData } from './_internal/load-data-from-files';
|
||||
import type { ClerkExternalAccount, ClerkUser } from './_internal/types';
|
||||
|
||||
type ExpectedAccount = {
|
||||
accountId?: string;
|
||||
@@ -48,7 +47,7 @@ function buildExpectedAccounts(
|
||||
expectedAccounts.push({
|
||||
accountId: external.provider_user_id,
|
||||
providerId: providerIdFromExternal(external),
|
||||
scope: external.approved_scopes?.replace(/\s+/g, ','),
|
||||
scope: external.approved_scopes?.replaceAll(/\s+/g, ','),
|
||||
userId: user.id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { pgGenerate } from 'drizzle-dbml-generator';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { pgGenerate } from 'drizzle-dbml-generator';
|
||||
|
||||
import * as schema from '../../packages/database/src/schemas';
|
||||
|
||||
const out = join(__dirname, '../../docs/development/database-schema.dbml');
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { consola } from 'consola';
|
||||
import matter from 'gray-matter';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import matter from 'gray-matter';
|
||||
import pMap from 'p-map';
|
||||
|
||||
import { uploader } from '../cdnWorkflow/uploader';
|
||||
@@ -60,7 +61,7 @@ class ImageCDNUploader {
|
||||
const links: string[][] = posts.map((post) => {
|
||||
const mdx = readFileSync(post, 'utf8');
|
||||
const { content, data } = matter(mdx);
|
||||
let inlineLinks: string[] = extractHttpsLinks(content);
|
||||
const inlineLinks: string[] = extractHttpsLinks(content);
|
||||
|
||||
// 添加特定字段中的图片链接
|
||||
if (data?.image) inlineLinks.push(data.image);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { globSync } from 'glob';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { globSync } from 'glob';
|
||||
|
||||
export const WIKI_URL = 'https://github.com/lobehub/lobe-chat/wiki/';
|
||||
export const ROOT = resolve(__dirname, '../..');
|
||||
export const DOCS_DIR = resolve(ROOT, 'contributing');
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { consola } from 'consola';
|
||||
import { relative, resolve } from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import pMap from 'p-map';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
import { DOCS_DIR, HOME_PATH, SIDEBAR_PATH, WIKI_URL, docsFiles } from './const';
|
||||
import { DOCS_DIR, docsFiles, HOME_PATH, SIDEBAR_PATH, WIKI_URL } from './const';
|
||||
import toc from './toc';
|
||||
import { genMdLink, getTitle, updateDocs } from './utils';
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { globSync } from 'glob';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { globSync } from 'glob';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import remarkParse from 'remark-parse';
|
||||
import { unified } from 'unified';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable unicorn/no-process-exit */
|
||||
import fs from 'fs-extra';
|
||||
import { execSync } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
|
||||
import fs from 'fs-extra';
|
||||
|
||||
type ReleaseChannel = 'stable' | 'beta' | 'nightly';
|
||||
|
||||
const rootDir = path.resolve(__dirname, '../..');
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable unicorn/no-process-exit */
|
||||
import { execSync } from 'node:child_process';
|
||||
import os from 'node:os';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable unicorn/no-process-exit, unicorn/prefer-top-level-await */
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import YAML from 'yaml';
|
||||
|
||||
// 配置
|
||||
|
||||
@@ -166,7 +166,7 @@ export const modifyNextConfig = async (TEMP_DIR: string) => {
|
||||
edits.push({
|
||||
end: range.start.index + 1,
|
||||
start: range.start.index + 1,
|
||||
text: "\n outputFileTracingRoot: process.env.ELECTRON_BUILD_PROJECT_ROOT || process.cwd(),",
|
||||
text: '\n outputFileTracingRoot: process.env.ELECTRON_BUILD_PROJECT_ROOT || process.cwd(),',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,11 @@ const removeSuspenseWrapper = (code: string): string => {
|
||||
|
||||
for (const child of children) {
|
||||
const kind = child.kind();
|
||||
if (kind === 'jsx_element' || kind === 'jsx_self_closing_element' || kind === 'jsx_fragment') {
|
||||
if (
|
||||
kind === 'jsx_element' ||
|
||||
kind === 'jsx_self_closing_element' ||
|
||||
kind === 'jsx_fragment'
|
||||
) {
|
||||
childrenText = child.text();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ const isBusinessFeaturesEnabled = () => {
|
||||
const extractDynamicImportsFromMap = (code: string): DynamicImportInfo[] => {
|
||||
const results: DynamicImportInfo[] = [];
|
||||
|
||||
const regex = /\[SettingsTabs\.(\w+)]:\s*dynamic\(\s*\(\)\s*=>\s*import\(\s*["']([^"']+)["']\s*\)/g;
|
||||
const regex =
|
||||
/\[SettingsTabs\.(\w+)]:\s*dynamic\(\s*\(\)\s*=>\s*import\(\s*["']([^"']+)["']\s*\)/g;
|
||||
|
||||
let match;
|
||||
while ((match = regex.exec(code)) !== null) {
|
||||
@@ -99,10 +100,7 @@ export const convertSettingsContentToStatic = async (TEMP_DIR: string) => {
|
||||
|
||||
let result = code;
|
||||
|
||||
result = result.replace(
|
||||
/import dynamic from ["']@\/libs\/next\/dynamic["'];\n?/,
|
||||
'',
|
||||
);
|
||||
result = result.replace(/import dynamic from ["']@\/libs\/next\/dynamic["'];\n?/, '');
|
||||
|
||||
result = result.replace(
|
||||
/import Loading from ["']@\/components\/Loading\/BrandTextLoading["'];\n?/,
|
||||
@@ -112,11 +110,13 @@ export const convertSettingsContentToStatic = async (TEMP_DIR: string) => {
|
||||
const ast = parse(Lang.Tsx, result);
|
||||
const root = ast.root();
|
||||
|
||||
const lastImport = root.findAll({
|
||||
rule: {
|
||||
kind: 'import_statement',
|
||||
},
|
||||
}).at(-1);
|
||||
const lastImport = root
|
||||
.findAll({
|
||||
rule: {
|
||||
kind: 'import_statement',
|
||||
},
|
||||
})
|
||||
.at(-1);
|
||||
|
||||
invariant(
|
||||
lastImport,
|
||||
@@ -124,7 +124,11 @@ export const convertSettingsContentToStatic = async (TEMP_DIR: string) => {
|
||||
);
|
||||
|
||||
const insertPos = lastImport!.range().end.index;
|
||||
result = result.slice(0, insertPos) + '\nimport type React from \'react\';\n' + staticImports + result.slice(insertPos);
|
||||
result =
|
||||
result.slice(0, insertPos) +
|
||||
"\nimport type React from 'react';\n" +
|
||||
staticImports +
|
||||
result.slice(insertPos);
|
||||
|
||||
const componentMapRegex = /const componentMap = {[\S\s]*?\n};/;
|
||||
invariant(
|
||||
|
||||
@@ -10,8 +10,10 @@ export const wrapChildrenWithClientOnly = async (TEMP_DIR: string) => {
|
||||
|
||||
await updateFile({
|
||||
assertAfter: (code) => {
|
||||
const hasClientOnlyImport = /import ClientOnly from ["']@\/components\/client\/ClientOnly["']/.test(code);
|
||||
const hasLoadingImport = /import Loading from ["']@\/components\/Loading\/BrandTextLoading["']/.test(code);
|
||||
const hasClientOnlyImport =
|
||||
/import ClientOnly from ["']@\/components\/client\/ClientOnly["']/.test(code);
|
||||
const hasLoadingImport =
|
||||
/import Loading from ["']@\/components\/Loading\/BrandTextLoading["']/.test(code);
|
||||
const hasClientOnlyWrapper = /<ClientOnly fallback={<Loading/.test(code);
|
||||
return hasClientOnlyImport && hasLoadingImport && hasClientOnlyWrapper;
|
||||
},
|
||||
@@ -23,16 +25,23 @@ export const wrapChildrenWithClientOnly = async (TEMP_DIR: string) => {
|
||||
|
||||
let result = code;
|
||||
|
||||
const hasClientOnlyImport = /import ClientOnly from ["']@\/components\/client\/ClientOnly["']/.test(code);
|
||||
const hasLoadingImport = /import Loading from ["']@\/components\/Loading\/BrandTextLoading["']/.test(code);
|
||||
const hasClientOnlyImport =
|
||||
/import ClientOnly from ["']@\/components\/client\/ClientOnly["']/.test(code);
|
||||
const hasLoadingImport =
|
||||
/import Loading from ["']@\/components\/Loading\/BrandTextLoading["']/.test(code);
|
||||
|
||||
const lastImport = root.findAll({
|
||||
rule: {
|
||||
kind: 'import_statement',
|
||||
},
|
||||
}).at(-1);
|
||||
const lastImport = root
|
||||
.findAll({
|
||||
rule: {
|
||||
kind: 'import_statement',
|
||||
},
|
||||
})
|
||||
.at(-1);
|
||||
|
||||
invariant(lastImport, '[wrapChildrenWithClientOnly] No import statements found in layout.tsx');
|
||||
invariant(
|
||||
lastImport,
|
||||
'[wrapChildrenWithClientOnly] No import statements found in layout.tsx',
|
||||
);
|
||||
|
||||
const insertPos = lastImport!.range().end.index;
|
||||
let importsToAdd = '';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'node:path';
|
||||
|
||||
import fs from 'fs-extra';
|
||||
|
||||
const rootDir = path.resolve(__dirname, '../..');
|
||||
|
||||
const exportSourceDir = path.join(rootDir, 'out');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable unicorn/no-process-exit */
|
||||
import fs from 'fs-extra';
|
||||
import path from 'node:path';
|
||||
|
||||
import fs from 'fs-extra';
|
||||
|
||||
type ReleaseType = 'stable' | 'beta' | 'nightly';
|
||||
|
||||
// 获取脚本的命令行参数
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { glob } from 'glob';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
import { IGNORED_FILES, PROTECTED_KEY_PATTERNS } from './protectedPatterns';
|
||||
|
||||
@@ -83,7 +83,7 @@ function loadAllI18nKeys(): I18nKey[] {
|
||||
|
||||
try {
|
||||
// Use require to load the TypeScript file (after it's compiled)
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
|
||||
const loadedModule = require(filePath);
|
||||
const translations = loadedModule.default || loadedModule;
|
||||
|
||||
@@ -130,43 +130,43 @@ async function findAllTranslationCalls(): Promise<Set<string>> {
|
||||
pattern: RegExp; // Whether pattern can capture namespace
|
||||
}> = [
|
||||
// Static patterns
|
||||
{ pattern: /\bt[A-Z]?\w*\(\s*["'`]([^"'`]+)["'`]/g },
|
||||
{ pattern: /\bt\w*\(\s*["'`]([^"'`]+)["'`]/g },
|
||||
{
|
||||
captureNs: true,
|
||||
pattern: /\bt[A-Z]?\w*\(\s*["'`]([^"'`]+)["'`]\s*,\s*{[^}]*ns:\s*["'`]([^"'`]+)["'`]/g,
|
||||
pattern: /\bt\w*\(\s*["'`]([^"'`]+)["'`]\s*,\s*\{[^}]*ns:\s*["'`]([^"'`]+)["'`]/g,
|
||||
},
|
||||
{ pattern: /i18n\.t\(\s*["'`]([^"'`]+)["'`]/g },
|
||||
{ pattern: /\bt[A-Z]?\w*\([^)]*\?\s*["'`]([^"'`]+)["'`]/g },
|
||||
{ pattern: /\bt[A-Z]?\w*\([^)]*:\s*["'`]([^"'`]+)["'`]/g },
|
||||
{ pattern: /\bt\w*\([^)]*\?\s*["'`]([^"'`]+)["'`]/g },
|
||||
{ pattern: /\bt\w*\([^)]*:\s*["'`]([^"'`]+)["'`]/g },
|
||||
{ pattern: /<Trans[^>]+i18nKey=["']([^"']+)["']/g },
|
||||
{ pattern: /<Trans[^>]+i18nKey={["']([^"']+)["']}/g },
|
||||
{ captureNs: true, pattern: /<Trans[^>]+i18nKey=["']([^"']+)["'][\S\s]*?ns=["']([^"']+)["']/g },
|
||||
{ pattern: /<Trans[^>]+i18nKey=\{["']([^"']+)["']\}/g },
|
||||
{ captureNs: true, pattern: /<Trans[^>]+i18nKey=["']([^"']+)["'][\s\S]*?ns=["']([^"']+)["']/g },
|
||||
{
|
||||
captureNs: true,
|
||||
pattern: /<Trans[^>]+i18nKey={["']([^"']+)["']}[\S\s]*?ns={["']([^"']+)["']}/g,
|
||||
pattern: /<Trans[^>]+i18nKey=\{["']([^"']+)["']\}[\s\S]*?ns=\{["']([^"']+)["']\}/g,
|
||||
},
|
||||
|
||||
// Dynamic patterns (template strings, concatenations, etc.)
|
||||
// Pattern 1: t(`prefix.${var}.suffix`) - variable in the middle
|
||||
{ captureNs: false, isDynamic: true, pattern: /\bt[A-Z]?\w*\(\s*`([^$`]+)\${[^}]+}([^`]*)`/g },
|
||||
{ captureNs: false, isDynamic: true, pattern: /\bt\w*\(\s*`([^$`]+)\$\{[^}]+\}([^`]*)`/g },
|
||||
// Pattern 2: t(`${var}.suffix`) - variable at the start
|
||||
{ captureNs: false, isDynamic: true, pattern: /\bt[A-Z]?\w*\(\s*`\${[^}]+}([^`]+)`/g },
|
||||
{ captureNs: false, isDynamic: true, pattern: /\bt\w*\(\s*`\$\{[^}]+\}([^`]+)`/g },
|
||||
// Pattern 3: t(`prefix.${var}.suffix`, { ns: 'namespace' }) - with explicit ns
|
||||
{
|
||||
captureNs: true,
|
||||
isDynamic: true,
|
||||
pattern: /\bt[A-Z]?\w*\(\s*`([^$`]*)\${[^}]+}([^`]*)`\s*,\s*{[^}]*ns:\s*["'`]([^"'`]+)["'`]/g,
|
||||
pattern: /\bt\w*\(\s*`([^$`]*)\$\{[^}]+\}([^`]*)`\s*,\s*\{[^}]*ns:\s*["'`]([^"'`]+)["'`]/g,
|
||||
},
|
||||
// Pattern 4: t(`${var}.suffix`, { ns: 'namespace' }) - variable at start with ns
|
||||
{
|
||||
captureNs: true,
|
||||
isDynamic: true,
|
||||
pattern: /\bt[A-Z]?\w*\(\s*`\${[^}]+}([^`]+)`\s*,\s*{[^}]*ns:\s*["'`]([^"'`]+)["'`]/g,
|
||||
pattern: /\bt\w*\(\s*`\$\{[^}]+\}([^`]+)`\s*,\s*\{[^}]*ns:\s*["'`]([^"'`]+)["'`]/g,
|
||||
},
|
||||
// Pattern 5: String concatenation
|
||||
{ isDynamic: true, pattern: /\bt[A-Z]?\w*\(\s*["'`]([^"'`]+)["'`]\s*\+/g },
|
||||
{ isDynamic: true, pattern: /\bt\w*\(\s*["'`]([^"'`]+)["'`]\s*\+/g },
|
||||
// Pattern 6: <Trans> with dynamic keys
|
||||
{ isDynamic: true, pattern: /<Trans[^>]+i18nKey={`([^$`]+)\${[^}]+}([^`]*)`}/g },
|
||||
{ isDynamic: true, pattern: /<Trans[^>]+i18nKey=\{`([^$`]+)\$\{[^}]+\}([^`]*)`\}/g },
|
||||
];
|
||||
|
||||
let totalMatches = 0;
|
||||
@@ -176,11 +176,11 @@ async function findAllTranslationCalls(): Promise<Set<string>> {
|
||||
|
||||
// Extract namespace from useTranslation hook
|
||||
const useTranslationMatch = content.match(/useTranslation\(\s*["'`]([^"'`]+)["'`]\s*\)/g);
|
||||
const useTranslationMultiMatch = content.match(/useTranslation\(\s*\[([^\]]+)]\s*\)/g);
|
||||
const useTranslationMultiMatch = content.match(/useTranslation\(\s*\[([^\]]+)\]\s*\)/g);
|
||||
|
||||
// Extract aliases: const { t: tAuth } = useTranslation('auth')
|
||||
const aliasPattern =
|
||||
/const\s*{\s*t\s*:\s*(\w+)\s*}\s*=\s*useTranslation\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
|
||||
/const\s*\{\s*t\s*:\s*(\w+)\s*\}\s*=\s*useTranslation\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
|
||||
const aliasMatches = content.matchAll(aliasPattern);
|
||||
|
||||
const namespacesInFile = new Set<string>();
|
||||
@@ -197,7 +197,7 @@ async function findAllTranslationCalls(): Promise<Set<string>> {
|
||||
// Extract namespaces from useTranslation(['ns1', 'ns2'])
|
||||
if (useTranslationMultiMatch) {
|
||||
for (const match of useTranslationMultiMatch) {
|
||||
const nsArray = match.match(/\[([^\]]+)]/)?.[1];
|
||||
const nsArray = match.match(/\[([^\]]+)\]/)?.[1];
|
||||
if (nsArray) {
|
||||
const namespaces = nsArray.match(/["'`]([^"'`]+)["'`]/g);
|
||||
if (namespaces) {
|
||||
@@ -240,7 +240,7 @@ async function findAllTranslationCalls(): Promise<Set<string>> {
|
||||
if (!key) continue;
|
||||
|
||||
// Extract function name (t, tAuth, tCommon, etc.)
|
||||
const funcNameMatch = fullMatch.match(/\b(t[A-Z]?\w*)\(/);
|
||||
const funcNameMatch = fullMatch.match(/\b(t\w*)\(/);
|
||||
const funcName = funcNameMatch?.[1] || 't';
|
||||
|
||||
// Check if it's an alias with known namespace
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
|
||||
import { IGNORED_FILES } from './protectedPatterns';
|
||||
|
||||
interface UnusedKey {
|
||||
@@ -105,7 +105,6 @@ function cleanDefaultLocaleFiles(unusedKeys: UnusedKey[], dryRun: boolean = true
|
||||
}
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const loadedModule = require(filePath);
|
||||
const translations = loadedModule.default || loadedModule;
|
||||
|
||||
@@ -131,7 +130,7 @@ function cleanDefaultLocaleFiles(unusedKeys: UnusedKey[], dryRun: boolean = true
|
||||
|
||||
if (!dryRun) {
|
||||
// Generate new content
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
|
||||
const newContent = generateTypeScriptContent(updatedTranslations);
|
||||
|
||||
// Write back to file
|
||||
@@ -233,7 +232,7 @@ function needsQuotes(key: string): boolean {
|
||||
// - Contains special characters (-, ., spaces, etc.)
|
||||
// - Starts with a number
|
||||
// - Is a reserved keyword
|
||||
return !/^[$A-Z_a-z][\w$]*$/.test(key);
|
||||
return !/^[$_a-z][\w$]*$/i.test(key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
import prettier from '@prettier/sync';
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
import { toLodashPath } from '../../src/locales/utils';
|
||||
import { localeDir, localeDirJsonList, localesDir, srcDefaultLocales } from './const';
|
||||
@@ -134,6 +134,6 @@ const run = async () => {
|
||||
|
||||
run().catch((error) => {
|
||||
consola.error(error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { unset } from 'es-toolkit/compat';
|
||||
import { diff } from 'just-diff';
|
||||
import { existsSync } from 'node:fs';
|
||||
|
||||
import {
|
||||
entryLocaleJsonFilepath,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import prettier from "@prettier/sync";
|
||||
|
||||
import prettier from '@prettier/sync';
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
|
||||
import i18nConfig from './i18nConfig';
|
||||
|
||||
let prettierOptions = prettier.resolveConfig(
|
||||
resolve(__dirname, '../../.prettierrc.js')
|
||||
);
|
||||
const prettierOptions = prettier.resolveConfig(resolve(__dirname, '../../.prettierrc.js'));
|
||||
|
||||
export const readJSON = (filePath: string) => {
|
||||
const data = readFileSync(filePath, 'utf8');
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { globSync } from 'glob';
|
||||
import matter from 'gray-matter';
|
||||
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
const fixWinPath = (path: string) => path.replaceAll('\\', '/');
|
||||
|
||||
@@ -32,7 +33,7 @@ const run = () => {
|
||||
.replaceAll('}> width', '} width')
|
||||
.replaceAll("'[https", "'https")
|
||||
.replaceAll('"[https', '"https')
|
||||
.replaceAll(/]\(http(.*)\/>\)/g, '')
|
||||
.replaceAll(/\]\(http(.*)\/>\)/g, '')
|
||||
.replaceAll(`\\*\\* `, '** ')
|
||||
.replaceAll(` \\*\\*`, ' **')
|
||||
.replaceAll(/\n{2,}/g, '\n\n');
|
||||
|
||||
@@ -42,7 +42,7 @@ async function migrateFile(relativePath: string): Promise<MigrationResult | null
|
||||
|
||||
// Check what hooks are being imported from @/libs/next/navigation
|
||||
const importMatch = content.match(
|
||||
/import\s*{([^}]+)}\s*from\s*["']@\/libs\/next\/navigation["']/,
|
||||
/import\s*\{([^}]+)\}\s*from\s*["']@\/libs\/next\/navigation["']/,
|
||||
);
|
||||
|
||||
if (!importMatch) {
|
||||
@@ -97,7 +97,7 @@ async function migrateFile(relativePath: string): Promise<MigrationResult | null
|
||||
|
||||
// Replace the old import with new imports
|
||||
newContent = newContent.replace(
|
||||
/import\s*{[^}]+}\s*from\s*["']@\/libs\/next\/navigation["'];?\n?/,
|
||||
/import\s*\{[^}]+\}\s*from\s*["']@\/libs\/next\/navigation["'];?\n?/,
|
||||
newImports.join('\n') + '\n',
|
||||
);
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { join } from 'node:path';
|
||||
|
||||
import * as dotenv from 'dotenv';
|
||||
import dotenvExpand from 'dotenv-expand';
|
||||
import { migrate as neonMigrate } from 'drizzle-orm/neon-serverless/migrator';
|
||||
import { migrate as nodeMigrate } from 'drizzle-orm/node-postgres/migrator';
|
||||
import { join } from 'node:path';
|
||||
|
||||
// @ts-ignore tsgo handle esm import cjs and compatibility issues
|
||||
import { DB_FAIL_INIT_HINT, DUPLICATE_EMAIL_HINT, PGVECTOR_HINT } from './errorHint';
|
||||
@@ -32,15 +33,14 @@ const runMigrations = async () => {
|
||||
}
|
||||
|
||||
console.log('✅ database migration pass. use: %s ms', Date.now() - time);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
let connectionString = process.env.DATABASE_URL;
|
||||
const connectionString = process.env.DATABASE_URL;
|
||||
|
||||
// only migrate database if the connection string is available
|
||||
if (!isDesktop && connectionString) {
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||
runMigrations().catch((err) => {
|
||||
console.error('❌ Database migrate failed:', err);
|
||||
|
||||
@@ -56,7 +56,6 @@ if (!isDesktop && connectionString) {
|
||||
console.info(DB_FAIL_INIT_HINT);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Pool as NeonPool, neonConfig } from '@neondatabase/serverless';
|
||||
import { neonConfig, Pool as NeonPool } from '@neondatabase/serverless';
|
||||
import { drizzle as neonDrizzle } from 'drizzle-orm/neon-serverless';
|
||||
import { drizzle as nodeDrizzle } from 'drizzle-orm/node-postgres';
|
||||
import { Pool as NodePool } from 'pg';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
import { getBatchSize, getMigrationMode, isDryRun } from './_internal/config';
|
||||
@@ -213,10 +212,15 @@ async function main() {
|
||||
try {
|
||||
await migrateFromNextAuth();
|
||||
console.log('');
|
||||
console.log(`${GREEN_BOLD}✅ Migration success!${RESET} (${formatDuration(Date.now() - startedAt)})`);
|
||||
console.log(
|
||||
`${GREEN_BOLD}✅ Migration success!${RESET} (${formatDuration(Date.now() - startedAt)})`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log('');
|
||||
console.error(`${RED_BOLD}❌ Migration failed${RESET} (${formatDuration(Date.now() - startedAt)}):`, error);
|
||||
console.error(
|
||||
`${RED_BOLD}❌ Migration failed${RESET} (${formatDuration(Date.now() - startedAt)}):`,
|
||||
error,
|
||||
);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
await pool.end();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable unicorn/prefer-top-level-await */
|
||||
import { getMigrationMode } from './_internal/config';
|
||||
import { db, pool, schema } from './_internal/db';
|
||||
|
||||
|
||||
+23
-12
@@ -1,9 +1,9 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import { createRequire } from 'node:module';
|
||||
import * as dotenv from 'dotenv';
|
||||
import dotenvExpand from 'dotenv-expand';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { rm } from 'node:fs/promises';
|
||||
import { createRequire } from 'node:module';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
@@ -22,8 +22,10 @@ if (isDesktop) {
|
||||
dotenvExpand.expand(dotenv.config());
|
||||
}
|
||||
|
||||
const AUTH_SECRET_DOC_URL = 'https://lobehub.com/docs/self-hosting/environment-variables/auth#auth-secret';
|
||||
const KEY_VAULTS_SECRET_DOC_URL = 'https://lobehub.com/docs/self-hosting/environment-variables/basic#key-vaults-secret';
|
||||
const AUTH_SECRET_DOC_URL =
|
||||
'https://lobehub.com/docs/self-hosting/environment-variables/auth#auth-secret';
|
||||
const KEY_VAULTS_SECRET_DOC_URL =
|
||||
'https://lobehub.com/docs/self-hosting/environment-variables/basic#key-vaults-secret';
|
||||
|
||||
/**
|
||||
* Check for required environment variables in server database mode
|
||||
@@ -51,13 +53,14 @@ const checkRequiredEnvVars = () => {
|
||||
console.error(` 📖 Documentation: ${docUrl}\n`);
|
||||
}
|
||||
console.error('Please configure these environment variables and redeploy.');
|
||||
console.error('\n💡 TIP: If you previously used NEXT_AUTH_SECRET, simply rename it to AUTH_SECRET.');
|
||||
console.error(
|
||||
'\n💡 TIP: If you previously used NEXT_AUTH_SECRET, simply rename it to AUTH_SECRET.',
|
||||
);
|
||||
console.error('═'.repeat(70) + '\n');
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getCommandVersion = (command: string): string | null => {
|
||||
try {
|
||||
return execSync(`${command} --version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] })
|
||||
@@ -87,7 +90,9 @@ const printEnvInfo = () => {
|
||||
console.log(` APP_URL: ${process.env.APP_URL ?? '(not set)'}`);
|
||||
console.log(` VERCEL_URL: ${process.env.VERCEL_URL ?? '(not set)'}`);
|
||||
console.log(` VERCEL_BRANCH_URL: ${process.env.VERCEL_BRANCH_URL ?? '(not set)'}`);
|
||||
console.log(` VERCEL_PROJECT_PRODUCTION_URL: ${process.env.VERCEL_PROJECT_PRODUCTION_URL ?? '(not set)'}`);
|
||||
console.log(
|
||||
` VERCEL_PROJECT_PRODUCTION_URL: ${process.env.VERCEL_PROJECT_PRODUCTION_URL ?? '(not set)'}`,
|
||||
);
|
||||
console.log(` AUTH_EMAIL_VERIFICATION: ${process.env.AUTH_EMAIL_VERIFICATION ?? '(not set)'}`);
|
||||
console.log(` AUTH_ENABLE_MAGIC_LINK: ${process.env.AUTH_ENABLE_MAGIC_LINK ?? '(not set)'}`);
|
||||
|
||||
@@ -96,14 +101,18 @@ const printEnvInfo = () => {
|
||||
console.log(` AUTH_SSO_PROVIDERS: ${ssoProviders ?? '(not set)'}`);
|
||||
|
||||
if (ssoProviders) {
|
||||
const getEnvPrefix = (provider: string) => `AUTH_${provider.toUpperCase().replaceAll('-', '_')}`;
|
||||
const getEnvPrefix = (provider: string) =>
|
||||
`AUTH_${provider.toUpperCase().replaceAll('-', '_')}`;
|
||||
|
||||
const providers = ssoProviders.split(/[,,]/).map(p => p.trim()).filter(Boolean);
|
||||
const providers = ssoProviders
|
||||
.split(/[,,]/)
|
||||
.map((p) => p.trim())
|
||||
.filter(Boolean);
|
||||
const missingProviders: string[] = [];
|
||||
|
||||
for (const provider of providers) {
|
||||
const envPrefix = getEnvPrefix(provider);
|
||||
const hasEnvVar = Object.keys(process.env).some(key => key.startsWith(envPrefix));
|
||||
const hasEnvVar = Object.keys(process.env).some((key) => key.startsWith(envPrefix));
|
||||
if (!hasEnvVar) {
|
||||
missingProviders.push(provider);
|
||||
}
|
||||
@@ -112,7 +121,9 @@ const printEnvInfo = () => {
|
||||
if (missingProviders.length > 0) {
|
||||
console.log('\n ⚠️ SSO Provider Configuration Warning:');
|
||||
for (const provider of missingProviders) {
|
||||
console.log(` - "${provider}" is configured but no ${getEnvPrefix(provider)}_* env vars found`);
|
||||
console.log(
|
||||
` - "${provider}" is configured but no ${getEnvPrefix(provider)}_* env vars found`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +132,7 @@ const printEnvInfo = () => {
|
||||
};
|
||||
|
||||
// 创建需要排除的特性映射
|
||||
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
||||
|
||||
const partialBuildPages = [
|
||||
// no need for bundle analyzer (frontend only)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DEFAULT_MODEL_PROVIDER_LIST } from 'model-bank/modelProviders';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { DEFAULT_MODEL_PROVIDER_LIST } from 'model-bank/modelProviders';
|
||||
|
||||
export const root = resolve(__dirname, '../..');
|
||||
|
||||
export interface DataItem {
|
||||
|
||||
@@ -2,7 +2,8 @@ import { consola } from 'consola';
|
||||
import { markdownTable } from 'markdown-table';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
import { AGENT_SPLIT, DataItem } from './const';
|
||||
import type { DataItem } from './const';
|
||||
import { AGENT_SPLIT } from './const';
|
||||
import {
|
||||
fetchAgentIndex,
|
||||
genLink,
|
||||
|
||||
@@ -2,7 +2,8 @@ import { consola } from 'consola';
|
||||
import { markdownTable } from 'markdown-table';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
import { DataItem, PLUGIN_SPLIT } from './const';
|
||||
import type { DataItem } from './const';
|
||||
import { PLUGIN_SPLIT } from './const';
|
||||
import {
|
||||
fetchPluginIndex,
|
||||
genLink,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { consola } from 'consola';
|
||||
import { readJSONSync } from 'fs-extra';
|
||||
import { resolve } from 'node:path';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
import { PROVIDER_LIST, PROVIDER_SPLIT, root } from './const';
|
||||
@@ -28,7 +29,7 @@ const runProviderTable = async (lang?: string) => {
|
||||
)
|
||||
.join('\n'),
|
||||
`<details><summary><kbd>See more providers (+${PROVIDER_LIST.length - 10})</kbd></summary>`,
|
||||
PROVIDER_LIST.slice(10, PROVIDER_LIST.length)
|
||||
PROVIDER_LIST.slice(10)
|
||||
.map((item) =>
|
||||
genProviderTable({
|
||||
...item,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { kebabCase } from 'es-toolkit/compat';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { kebabCase } from 'es-toolkit/compat';
|
||||
|
||||
import { AGENT_I18N_URL, AGENT_URL, PLUGIN_I18N_URL, PLUGIN_URL, root } from './const';
|
||||
|
||||
const fetchIndex = async (url: string) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
||||
import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
||||
import { join, relative } from 'node:path';
|
||||
|
||||
interface ReplaceConfig {
|
||||
@@ -230,7 +230,7 @@ function parseArgs(): ReplaceConfig | null {
|
||||
if (!componentsStr || !fromPackage || !toPackage) {
|
||||
console.error('❌ 错误: 必须指定 --components, --from 和 --to 参数');
|
||||
console.error('使用 --help 查看帮助信息');
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const PROXYCHAINS_CONF_PATH = '/etc/proxychains4.conf';
|
||||
const isValidIP = (ip, version = 4) => {
|
||||
const ipv4Regex = /^(25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3}$/;
|
||||
const ipv6Regex =
|
||||
/^(([\da-f]{1,4}:){7}[\da-f]{1,4}|([\da-f]{1,4}:){1,7}:|([\da-f]{1,4}:){1,6}:[\da-f]{1,4}|([\da-f]{1,4}:){1,5}(:[\da-f]{1,4}){1,2}|([\da-f]{1,4}:){1,4}(:[\da-f]{1,4}){1,3}|([\da-f]{1,4}:){1,3}(:[\da-f]{1,4}){1,4}|([\da-f]{1,4}:){1,2}(:[\da-f]{1,4}){1,5}|[\da-f]{1,4}:((:[\da-f]{1,4}){1,6})|:((:[\da-f]{1,4}){1,7}|:)|fe80:(:[\da-f]{0,4}){0,4}%[\da-z]+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)|([\da-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d))$/;
|
||||
/^(([\da-f]{1,4}:){7}[\da-f]{1,4}|([\da-f]{1,4}:){1,7}:|([\da-f]{1,4}:){1,6}:[\da-f]{1,4}|([\da-f]{1,4}:){1,5}(:[\da-f]{1,4}){1,2}|([\da-f]{1,4}:){1,4}(:[\da-f]{1,4}){1,3}|([\da-f]{1,4}:){1,3}(:[\da-f]{1,4}){1,4}|([\da-f]{1,4}:){1,2}(:[\da-f]{1,4}){1,5}|[\da-f]{1,4}:((:[\da-f]{1,4}){1,6})|:((:[\da-f]{1,4}){1,7}|:)|fe80:(:[\da-f]{0,4}){0,4}%[\da-z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d)|([\da-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))$/;
|
||||
|
||||
switch (version) {
|
||||
case 4: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 停止并删除已存在的容器
|
||||
docker stop postgres-paradedb 2>/dev/null && docker rm postgres-paradedb 2>/dev/null
|
||||
docker stop postgres-paradedb 2> /dev/null && docker rm postgres-paradedb 2> /dev/null
|
||||
|
||||
# 启动pgvector容器
|
||||
docker run --name postgres-paradedb \
|
||||
|
||||
@@ -32,10 +32,10 @@ const shouldBuild = shouldProceedBuild();
|
||||
console.log('shouldBuild:', shouldBuild);
|
||||
if (shouldBuild) {
|
||||
console.log('✅ - Build can proceed');
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('🛑 - Build cancelled');
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user