@lobehub/lobehub 2.0.0-next.145 → 2.0.0-next.147

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.
Files changed (29) hide show
  1. package/.github/workflows/test.yml +3 -0
  2. package/CHANGELOG.md +50 -0
  3. package/apps/desktop/package.json +2 -0
  4. package/apps/desktop/src/main/controllers/__tests__/UploadFileCtr.test.ts +8 -12
  5. package/apps/desktop/src/main/core/infrastructure/__tests__/ProtocolManager.test.ts +1 -0
  6. package/apps/desktop/src/main/core/ui/__tests__/Tray.test.ts +2 -2
  7. package/apps/desktop/src/main/utils/__tests__/file-system.test.ts +1 -1
  8. package/apps/desktop/src/main/utils/__tests__/logger.test.ts +7 -7
  9. package/apps/desktop/src/main/utils/next-electron-rsc.ts +3 -1
  10. package/apps/desktop/src/preload/invoke.test.ts +4 -2
  11. package/apps/desktop/src/preload/routeInterceptor.test.ts +54 -9
  12. package/apps/desktop/src/preload/streamer.test.ts +32 -31
  13. package/changelog/v1.json +18 -0
  14. package/docs/development/database-schema.dbml +2 -1
  15. package/package.json +3 -3
  16. package/packages/database/migrations/0056_update_agent_slug_index.sql +2 -0
  17. package/packages/database/migrations/meta/0056_snapshot.json +8411 -0
  18. package/packages/database/migrations/meta/_journal.json +7 -0
  19. package/packages/database/src/core/migrations.json +11 -2
  20. package/packages/database/src/models/session.ts +2 -1
  21. package/packages/database/src/schemas/agent.ts +2 -3
  22. package/packages/electron-client-ipc/src/events/system.ts +1 -3
  23. package/packages/electron-client-ipc/src/types/system.ts +1 -0
  24. package/src/auth.ts +11 -2
  25. package/src/envs/auth.ts +12 -0
  26. package/src/libs/better-auth/constants.ts +7 -1
  27. package/src/libs/better-auth/sso/index.ts +2 -0
  28. package/src/libs/better-auth/sso/providers/apple.ts +33 -0
  29. package/src/libs/mcp/__tests__/__snapshots__/index.test.ts.snap +9 -0
@@ -392,6 +392,13 @@
392
392
  "when": 1764583392443,
393
393
  "tag": "0055_rename_phone_number_to_phone",
394
394
  "breakpoints": true
395
+ },
396
+ {
397
+ "idx": 56,
398
+ "version": "7",
399
+ "when": 1764685643024,
400
+ "tag": "0056_update_agent_slug_index",
401
+ "breakpoints": true
395
402
  }
396
403
  ],
397
404
  "version": "6"
@@ -884,12 +884,12 @@
884
884
  "\nCREATE INDEX IF NOT EXISTS \"account_userId_idx\" ON \"accounts\" USING btree (\"user_id\");\n",
885
885
  "\nCREATE INDEX IF NOT EXISTS \"auth_session_userId_idx\" ON \"auth_sessions\" USING btree (\"user_id\");\n",
886
886
  "\nCREATE INDEX IF NOT EXISTS \"verification_identifier_idx\" ON \"verifications\" USING btree (\"identifier\");\n",
887
- "\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_email_unique') THEN\n UPDATE \"users\" SET \"email\" = NULL WHERE \"email\" = '';\n ALTER TABLE \"users\" ADD CONSTRAINT \"users_email_unique\" UNIQUE (\"email\");\n END IF;\nEND $$;\n",
887
+ "\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_email_unique') THEN\n -- Normalize empty emails so the unique constraint can be created safely\n UPDATE \"users\" SET \"email\" = NULL WHERE \"email\" = '';\n ALTER TABLE \"users\" ADD CONSTRAINT \"users_email_unique\" UNIQUE (\"email\");\n END IF;\nEND $$;\n",
888
888
  "\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_phone_number_unique') THEN\n ALTER TABLE \"users\" ADD CONSTRAINT \"users_phone_number_unique\" UNIQUE (\"phone_number\");\n END IF;\nEND $$;\n"
889
889
  ],
890
890
  "bps": true,
891
891
  "folderMillis": 1764579351312,
892
- "hash": "22fb7a65764b1f3e3c1ae2ce95d448685e6a01d1fb2f8c3f925c655f0824c161"
892
+ "hash": "1d2536a9471bb87686b35053f98ba7762259a07c819dc4489bb4f3c7f27a4d8d"
893
893
  },
894
894
  {
895
895
  "sql": [
@@ -901,5 +901,14 @@
901
901
  "bps": true,
902
902
  "folderMillis": 1764583392443,
903
903
  "hash": "6a43d90ee1d2e1e008d1b8206f227aa05b9a2e2a8fc8c31ec608a3716c716a6c"
904
+ },
905
+ {
906
+ "sql": [
907
+ "ALTER TABLE \"agents\" DROP CONSTRAINT \"agents_slug_unique\";",
908
+ "\nCREATE UNIQUE INDEX IF NOT EXISTS \"agents_slug_user_id_unique\" ON \"agents\" USING btree (\"slug\",\"user_id\");\n"
909
+ ],
910
+ "bps": true,
911
+ "folderMillis": 1764685643024,
912
+ "hash": "6e7ac7f964eb03efa3cb0d2fd35ded23e25c3abf955c4c2a51418f8daef54af9"
904
913
  }
905
914
  ]
@@ -656,7 +656,8 @@ export class SessionModel {
656
656
  const results = await this.db.query.agents.findMany({
657
657
  limit: pageSize,
658
658
  offset,
659
- orderBy: [desc(agents.updatedAt)],
659
+ // Keep deterministic ordering for keyword search results
660
+ orderBy: [asc(agents.id)],
660
661
  where: and(
661
662
  eq(agents.userId, this.userId),
662
663
  or(
@@ -28,9 +28,7 @@ export const agents = pgTable(
28
28
  .primaryKey()
29
29
  .$defaultFn(() => idGenerator('agents'))
30
30
  .notNull(),
31
- slug: varchar('slug', { length: 100 })
32
- .$defaultFn(() => randomSlug(4))
33
- .unique(),
31
+ slug: varchar('slug', { length: 100 }).$defaultFn(() => randomSlug(3)),
34
32
  title: varchar('title', { length: 255 }),
35
33
  description: varchar('description', { length: 1000 }),
36
34
  tags: jsonb('tags').$type<string[]>().default([]),
@@ -65,6 +63,7 @@ export const agents = pgTable(
65
63
  },
66
64
  (t) => [
67
65
  uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId),
66
+ uniqueIndex('agents_slug_user_id_unique').on(t.slug, t.userId),
68
67
  index('agents_title_idx').on(t.title),
69
68
  index('agents_description_idx').on(t.description),
70
69
  ],
@@ -1,6 +1,4 @@
1
- import { ThemeAppearance } from 'antd-style';
2
-
3
- import { ElectronAppState, ThemeMode } from '../types';
1
+ import { ElectronAppState, ThemeAppearance, ThemeMode } from '../types';
4
2
 
5
3
  export interface SystemDispatchEvents {
6
4
  checkSystemAccessibility: () => boolean | undefined;
@@ -25,3 +25,4 @@ export interface UserPathData {
25
25
  }
26
26
 
27
27
  export type ThemeMode = 'auto' | 'dark' | 'light';
28
+ export type ThemeAppearance = 'dark' | 'light' | string;
package/src/auth.ts CHANGED
@@ -19,6 +19,8 @@ import { EmailService } from '@/server/services/email';
19
19
  const VERIFICATION_LINK_EXPIRES_IN = 3600;
20
20
  const MAGIC_LINK_EXPIRES_IN = 900;
21
21
  const enableMagicLink = authEnv.NEXT_PUBLIC_ENABLE_MAGIC_LINK;
22
+ const APPLE_TRUSTED_ORIGIN = 'https://appleid.apple.com';
23
+ const enabledSSOProviders = parseSSOProviders(authEnv.AUTH_SSO_PROVIDERS);
22
24
 
23
25
  const { socialProviders, genericOAuthProviders } = initBetterAuthSSOProviders();
24
26
 
@@ -56,7 +58,14 @@ const getTrustedOrigins = () => {
56
58
  normalizeOrigin(process.env.VERCEL_URL),
57
59
  ].filter(Boolean) as string[];
58
60
 
59
- return defaults.length > 0 ? Array.from(new Set(defaults)) : undefined;
61
+ const baseTrustedOrigins = defaults.length > 0 ? Array.from(new Set(defaults)) : undefined;
62
+
63
+ if (!enabledSSOProviders.includes('apple')) return baseTrustedOrigins;
64
+
65
+ const mergedOrigins = new Set(baseTrustedOrigins || []);
66
+ mergedOrigins.add(APPLE_TRUSTED_ORIGIN);
67
+
68
+ return Array.from(mergedOrigins);
60
69
  };
61
70
 
62
71
  export const auth = betterAuth({
@@ -64,7 +73,7 @@ export const auth = betterAuth({
64
73
  accountLinking: {
65
74
  allowDifferentEmails: true,
66
75
  enabled: true,
67
- trustedProviders: parseSSOProviders(authEnv.AUTH_SSO_PROVIDERS),
76
+ trustedProviders: enabledSSOProviders,
68
77
  },
69
78
  },
70
79
 
package/src/envs/auth.ts CHANGED
@@ -69,6 +69,10 @@ declare global {
69
69
  AUTH_GOOGLE_ID?: string;
70
70
  AUTH_GOOGLE_SECRET?: string;
71
71
 
72
+ AUTH_APPLE_CLIENT_ID?: string;
73
+ AUTH_APPLE_CLIENT_SECRET?: string;
74
+ AUTH_APPLE_APP_BUNDLE_IDENTIFIER?: string;
75
+
72
76
  AUTH_GITHUB_ID?: string;
73
77
  AUTH_GITHUB_SECRET?: string;
74
78
 
@@ -184,6 +188,10 @@ export const getAuthConfig = () => {
184
188
  AUTH_GOOGLE_ID: z.string().optional(),
185
189
  AUTH_GOOGLE_SECRET: z.string().optional(),
186
190
 
191
+ AUTH_APPLE_CLIENT_ID: z.string().optional(),
192
+ AUTH_APPLE_CLIENT_SECRET: z.string().optional(),
193
+ AUTH_APPLE_APP_BUNDLE_IDENTIFIER: z.string().optional(),
194
+
187
195
  AUTH_GITHUB_ID: z.string().optional(),
188
196
  AUTH_GITHUB_SECRET: z.string().optional(),
189
197
 
@@ -301,6 +309,10 @@ export const getAuthConfig = () => {
301
309
  AUTH_GOOGLE_ID: process.env.AUTH_GOOGLE_ID,
302
310
  AUTH_GOOGLE_SECRET: process.env.AUTH_GOOGLE_SECRET,
303
311
 
312
+ AUTH_APPLE_CLIENT_ID: process.env.AUTH_APPLE_CLIENT_ID,
313
+ AUTH_APPLE_CLIENT_SECRET: process.env.AUTH_APPLE_CLIENT_SECRET,
314
+ AUTH_APPLE_APP_BUNDLE_IDENTIFIER: process.env.AUTH_APPLE_APP_BUNDLE_IDENTIFIER,
315
+
304
316
  AUTH_GITHUB_ID: process.env.AUTH_GITHUB_ID,
305
317
  AUTH_GITHUB_SECRET: process.env.AUTH_GITHUB_SECRET,
306
318
 
@@ -2,7 +2,13 @@
2
2
  * Canonical IDs of Better-Auth built-in social providers.
3
3
  * Keep this list in sync with provider definitions in `src/libs/better-auth/sso/providers`.
4
4
  */
5
- export const BUILTIN_BETTER_AUTH_PROVIDERS = ['google', 'github', 'cognito', 'microsoft'] as const;
5
+ export const BUILTIN_BETTER_AUTH_PROVIDERS = [
6
+ 'apple',
7
+ 'google',
8
+ 'github',
9
+ 'cognito',
10
+ 'microsoft',
11
+ ] as const;
6
12
 
7
13
  /**
8
14
  * Provider alias → canonical ID mapping.
@@ -5,6 +5,7 @@ import { authEnv } from '@/envs/auth';
5
5
  import { BUILTIN_BETTER_AUTH_PROVIDERS } from '@/libs/better-auth/constants';
6
6
  import { parseSSOProviders } from '@/libs/better-auth/utils/server';
7
7
 
8
+ import Apple from './providers/apple';
8
9
  import Auth0 from './providers/auth0';
9
10
  import Authelia from './providers/authelia';
10
11
  import Authentik from './providers/authentik';
@@ -23,6 +24,7 @@ import Wechat from './providers/wechat';
23
24
  import Zitadel from './providers/zitadel';
24
25
 
25
26
  const providerDefinitions = [
27
+ Apple,
26
28
  Google,
27
29
  Github,
28
30
  Cognito,
@@ -0,0 +1,33 @@
1
+ import { authEnv } from '@/envs/auth';
2
+
3
+ import type { BuiltinProviderDefinition } from '../types';
4
+
5
+ const provider: BuiltinProviderDefinition<
6
+ {
7
+ AUTH_APPLE_APP_BUNDLE_IDENTIFIER?: string;
8
+ AUTH_APPLE_CLIENT_ID: string;
9
+ AUTH_APPLE_CLIENT_SECRET: string;
10
+ },
11
+ 'apple'
12
+ > = {
13
+ build: (env) => {
14
+ return {
15
+ appBundleIdentifier: env.AUTH_APPLE_APP_BUNDLE_IDENTIFIER,
16
+ clientId: env.AUTH_APPLE_CLIENT_ID,
17
+ clientSecret: env.AUTH_APPLE_CLIENT_SECRET,
18
+ };
19
+ },
20
+ checkEnvs: () => {
21
+ return !!(authEnv.AUTH_APPLE_CLIENT_ID && authEnv.AUTH_APPLE_CLIENT_SECRET)
22
+ ? {
23
+ AUTH_APPLE_APP_BUNDLE_IDENTIFIER: authEnv.AUTH_APPLE_APP_BUNDLE_IDENTIFIER,
24
+ AUTH_APPLE_CLIENT_ID: authEnv.AUTH_APPLE_CLIENT_ID,
25
+ AUTH_APPLE_CLIENT_SECRET: authEnv.AUTH_APPLE_CLIENT_SECRET,
26
+ }
27
+ : false;
28
+ },
29
+ id: 'apple',
30
+ type: 'builtin',
31
+ };
32
+
33
+ export default provider;
@@ -4,6 +4,9 @@ exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
4
4
  [
5
5
  {
6
6
  "description": "Echoes back a message with 'Hello' prefix",
7
+ "execution": {
8
+ "taskSupport": "forbidden",
9
+ },
7
10
  "inputSchema": {
8
11
  "$schema": "http://json-schema.org/draft-07/schema#",
9
12
  "additionalProperties": false,
@@ -22,6 +25,9 @@ exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
22
25
  },
23
26
  {
24
27
  "description": "Lists all available tools and methods",
28
+ "execution": {
29
+ "taskSupport": "forbidden",
30
+ },
25
31
  "inputSchema": {
26
32
  "$schema": "http://json-schema.org/draft-07/schema#",
27
33
  "properties": {},
@@ -31,6 +37,9 @@ exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
31
37
  },
32
38
  {
33
39
  "description": "Adds two numbers",
40
+ "execution": {
41
+ "taskSupport": "forbidden",
42
+ },
34
43
  "inputSchema": {
35
44
  "$schema": "http://json-schema.org/draft-07/schema#",
36
45
  "additionalProperties": false,