xinyu-pro 0.22.6 → 0.23.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/app/api/chat/route.ts +2 -2
- package/app/api/generate-svg/route.ts +1 -1
- package/app/api/generate-theme/route.ts +112 -135
- package/app/api/plugins/bindings/route.ts +4 -4
- package/app/api/plugins/export/route.ts +9 -3
- package/app/api/plugins/export-xye/route.ts +12 -7
- package/app/api/plugins/files/route.ts +9 -9
- package/app/api/plugins/files-list/route.ts +7 -3
- package/app/api/plugins/files-upload/route.ts +3 -3
- package/app/api/plugins/files-write/all/route.ts +250 -0
- package/app/api/plugins/files-write/route.ts +13 -15
- package/app/api/plugins/import/route.ts +5 -5
- package/app/api/plugins/import-package/route.ts +9 -9
- package/app/api/plugins/resources/route.ts +6 -2
- package/app/api/plugins/route.ts +215 -119
- package/app/api/plugins/scan/route.ts +1 -1
- package/app/api/plugins/storage/route.ts +3 -3
- package/app/api/plugins/toggle/route.ts +21 -0
- package/app/api/sessions/route.ts +8 -3
- package/app/api/settings/route.ts +2 -2
- package/app/api/suggest-fields/route.ts +1 -1
- package/app/api/templates/route.ts +2 -2
- package/app/api/themes/route.ts +116 -0
- package/app/editor/page.tsx +21 -4
- package/app/extensions/edit/[id]/page.tsx +2148 -984
- package/app/extensions/page.tsx +477 -86
- package/app/extensions/tutorial/code-examples.ts +833 -0
- package/app/extensions/tutorial/nav-link.tsx +27 -0
- package/app/extensions/tutorial/page.tsx +47 -3616
- package/app/extensions/tutorial/sections/AiInterceptionSection.tsx +87 -0
- package/app/extensions/tutorial/sections/ArchitectureSection.tsx +39 -0
- package/app/extensions/tutorial/sections/BestPracticesSection.tsx +78 -0
- package/app/extensions/tutorial/sections/ChatApiSection.tsx +212 -0
- package/app/extensions/tutorial/sections/CrossPluginSection.tsx +90 -0
- package/app/extensions/tutorial/sections/CssVariablesSection.tsx +189 -0
- package/app/extensions/tutorial/sections/DebugSection.tsx +48 -0
- package/app/extensions/tutorial/sections/DependencySection.tsx +134 -0
- package/app/extensions/tutorial/sections/DomSandboxSection.tsx +229 -0
- package/app/extensions/tutorial/sections/ExamplesSection.tsx +29 -0
- package/app/extensions/tutorial/sections/FileApiSection.tsx +44 -0
- package/app/extensions/tutorial/sections/GlobalApiSection.tsx +50 -0
- package/app/extensions/tutorial/sections/InputApiSection.tsx +213 -0
- package/app/extensions/tutorial/sections/LifecycleSection.tsx +105 -0
- package/app/extensions/tutorial/sections/OverviewSection.tsx +54 -0
- package/app/extensions/tutorial/sections/PermissionsSection.tsx +239 -0
- package/app/extensions/tutorial/sections/PersistentStorageSection.tsx +49 -0
- package/app/extensions/tutorial/sections/PluginConfigSection.tsx +81 -0
- package/app/extensions/tutorial/sections/PluginImportExportSection.tsx +68 -0
- package/app/extensions/tutorial/sections/PluginStorageSection.tsx +94 -0
- package/app/extensions/tutorial/sections/ResourceApiSection.tsx +88 -0
- package/app/extensions/tutorial/sections/SecuritySection.tsx +106 -0
- package/app/extensions/tutorial/sections/SlotsSection.tsx +130 -0
- package/app/extensions/tutorial/sections/UiApiSection.tsx +147 -0
- package/app/extensions/tutorial/sections/UtilsApiSection.tsx +96 -0
- package/app/extensions/tutorial/sections-data.tsx +325 -0
- package/app/extensions/tutorial/styles.ts +59 -0
- package/app/extensions/tutorial/types.ts +14 -0
- package/app/game/[id]/page.tsx +336 -148
- package/app/globals.css +41 -0
- package/app/page.tsx +17 -10
- package/app/settings/page.tsx +218 -236
- package/bin/cli.js +3 -10
- package/components/ChatInput.tsx +20 -6
- package/components/ChatWindow.tsx +1 -1
- package/components/MessageBubble.tsx +5 -6
- package/components/ui/ConfirmDialog.tsx +28 -6
- package/components/ui/DeprecatedBadge.tsx +163 -0
- package/components/ui/PageHeader.tsx +1 -1
- package/components/ui/PermissionConflictDialog.tsx +1 -1
- package/components/ui/PluginConfigForm.tsx +2 -3
- package/components/ui/PluginFloatingLayer.tsx +2 -2
- package/components/ui/PluginModalRenderer.tsx +84 -38
- package/components/ui/PluginProvider.tsx +32 -13
- package/components/ui/PluginSlotRenderer.tsx +2 -2
- package/components/ui/ThemeCustomizer.tsx +4 -7
- package/components/ui/ThemeProvider.tsx +214 -125
- package/components/ui/ThemeSwitcher.tsx +119 -157
- package/components/ui/ToastProvider.tsx +47 -17
- package/lib/{parseWorldCard.ts → client/parseWorldCard.ts} +1 -1
- package/lib/{plugin-dom-sandbox.ts → client/plugin-dom-sandbox.ts} +2 -2
- package/lib/{plugin-runtime.ts → client/plugin-runtime.ts} +166 -67
- package/lib/client/plugin-utils.ts +105 -0
- package/lib/{router-history.ts → client/router-history.ts} +1 -1
- package/lib/{storage.ts → client/storage.ts} +66 -3
- package/lib/{themes.ts → client/themes.ts} +21 -1
- package/lib/{builtin-plugins.ts → server/builtin-plugins.ts} +1 -1
- package/lib/{db-init.ts → server/db-init.ts} +2 -2
- package/lib/{db.ts → server/db.ts} +48 -8
- package/lib/{get-ai-config.ts → server/get-ai-config.ts} +2 -2
- package/lib/{plugin-files.ts → server/plugin-files.ts} +7 -2
- package/lib/server/plugin-utils.ts +88 -0
- package/lib/{manifest-parser.ts → shared/manifest-parser.ts} +4 -4
- package/lib/{plugin-types.ts → shared/plugin-types.ts} +11 -6
- package/lib/{version.ts → shared/version.ts} +1 -1
- package/next.config.mjs +3 -2
- package/package.json +4 -3
- package/styles/themes.css +7 -2
- package/version.json +2 -2
- package/app/extensions/create/page.tsx +0 -1422
- /package/lib/{plugin-events.ts → client/plugin-events.ts} +0 -0
- /package/lib/{plugin-resource-tracker.ts → client/plugin-resource-tracker.ts} +0 -0
- /package/lib/{plugin-html-sanitizer.ts → shared/plugin-html-sanitizer.ts} +0 -0
- /package/lib/{plugin-security.ts → shared/plugin-security.ts} +0 -0
- /package/lib/{prompt-builder.ts → shared/prompt-builder.ts} +0 -0
- /package/lib/{types.ts → shared/types.ts} +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// app/api/themes/route.ts - 自定义主题 CRUD API
|
|
2
|
+
|
|
3
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
+
import { execute } from '@/lib/server/db';
|
|
5
|
+
import { ensureDb } from '@/lib/server/db-init';
|
|
6
|
+
|
|
7
|
+
export const dynamic = 'force-dynamic';
|
|
8
|
+
|
|
9
|
+
export async function GET(request: NextRequest) {
|
|
10
|
+
try {
|
|
11
|
+
await ensureDb();
|
|
12
|
+
const { searchParams } = new URL(request.url);
|
|
13
|
+
const id = searchParams.get('id');
|
|
14
|
+
|
|
15
|
+
if (id) {
|
|
16
|
+
const [rows] = await execute('SELECT * FROM themes WHERE id = ?', [id]);
|
|
17
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
18
|
+
const row = list[0] as Record<string, unknown> | undefined;
|
|
19
|
+
if (row) {
|
|
20
|
+
return NextResponse.json(formatThemeRow(row));
|
|
21
|
+
}
|
|
22
|
+
return NextResponse.json(null);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const [rows] = await execute('SELECT * FROM themes ORDER BY updated_at DESC');
|
|
26
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
27
|
+
return NextResponse.json(list.map(formatThemeRow));
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('Themes GET error:', error);
|
|
30
|
+
return NextResponse.json({ error: '读取主题失败' }, { status: 500 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function POST(request: NextRequest) {
|
|
35
|
+
try {
|
|
36
|
+
const body = await request.json();
|
|
37
|
+
await ensureDb();
|
|
38
|
+
|
|
39
|
+
const {
|
|
40
|
+
id = `theme-${Date.now()}`,
|
|
41
|
+
name,
|
|
42
|
+
description = '',
|
|
43
|
+
isDark = true,
|
|
44
|
+
variables = {},
|
|
45
|
+
previewType = '',
|
|
46
|
+
previewContent = '',
|
|
47
|
+
} = body;
|
|
48
|
+
|
|
49
|
+
if (!name) {
|
|
50
|
+
return NextResponse.json({ error: '主题名称不能为空' }, { status: 400 });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await execute(
|
|
54
|
+
`INSERT INTO themes (id, name, description, is_dark, variables, preview_type, preview_content)
|
|
55
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
56
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
57
|
+
name = excluded.name,
|
|
58
|
+
description = excluded.description,
|
|
59
|
+
is_dark = excluded.is_dark,
|
|
60
|
+
variables = excluded.variables,
|
|
61
|
+
preview_type = excluded.preview_type,
|
|
62
|
+
preview_content = excluded.preview_content,
|
|
63
|
+
updated_at = datetime('now')`,
|
|
64
|
+
[
|
|
65
|
+
id,
|
|
66
|
+
name,
|
|
67
|
+
description,
|
|
68
|
+
isDark ? 1 : 0,
|
|
69
|
+
JSON.stringify(variables),
|
|
70
|
+
previewType || '',
|
|
71
|
+
previewContent || '',
|
|
72
|
+
]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const [rows] = await execute('SELECT * FROM themes WHERE id = ?', [id]);
|
|
76
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
77
|
+
const row = list[0] as Record<string, unknown> | undefined;
|
|
78
|
+
|
|
79
|
+
return NextResponse.json(row ? formatThemeRow(row) : { id, name });
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('Themes POST error:', error);
|
|
82
|
+
return NextResponse.json({ error: '保存主题失败' }, { status: 500 });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function DELETE(request: NextRequest) {
|
|
87
|
+
try {
|
|
88
|
+
await ensureDb();
|
|
89
|
+
const { searchParams } = new URL(request.url);
|
|
90
|
+
const id = searchParams.get('id');
|
|
91
|
+
|
|
92
|
+
if (!id) {
|
|
93
|
+
return NextResponse.json({ error: '缺少主题 ID' }, { status: 400 });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await execute('DELETE FROM themes WHERE id = ?', [id]);
|
|
97
|
+
return NextResponse.json({ success: true });
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('Themes DELETE error:', error);
|
|
100
|
+
return NextResponse.json({ error: '删除主题失败' }, { status: 500 });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function formatThemeRow(row: Record<string, unknown>) {
|
|
105
|
+
return {
|
|
106
|
+
id: row.id,
|
|
107
|
+
name: row.name,
|
|
108
|
+
description: row.description,
|
|
109
|
+
isDark: row.is_dark === 1 || row.is_dark === true,
|
|
110
|
+
variables: typeof row.variables === 'string' ? JSON.parse(row.variables as string) : row.variables,
|
|
111
|
+
previewType: row.preview_type || '',
|
|
112
|
+
previewContent: row.preview_content || '',
|
|
113
|
+
createdAt: row.created_at,
|
|
114
|
+
updatedAt: row.updated_at,
|
|
115
|
+
};
|
|
116
|
+
}
|
package/app/editor/page.tsx
CHANGED
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
import React, { useState, useCallback, useEffect, useMemo, useRef, Suspense } from 'react';
|
|
5
5
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
6
|
-
import { useRouterHistory } from '@/lib/router-history';
|
|
7
|
-
import { WorldCardField, WorldCardTemplate, FieldType } from '@/lib/types';
|
|
8
|
-
import {
|
|
9
|
-
|
|
6
|
+
import { useRouterHistory } from '@/lib/client/router-history';
|
|
7
|
+
import { WorldCardField, WorldCardTemplate, FieldType } from '@/lib/shared/types';
|
|
8
|
+
import {
|
|
9
|
+
getAppSettings, saveWorldTemplate, getWorldTemplate, saveGameSession, StoredSession, getPlugins,
|
|
10
|
+
getPluginBindings, upsertPluginBinding
|
|
11
|
+
} from '@/lib/client/storage';
|
|
12
|
+
import { fieldsToWorldSetting, fieldsToWorldData, injectWorldData } from '@/lib/client/parseWorldCard';
|
|
10
13
|
import { useToast } from '@/components/ui/ToastProvider';
|
|
11
14
|
import ConfirmDialog from '@/components/ui/ConfirmDialog';
|
|
12
15
|
import PageHeader from '@/components/ui/PageHeader';
|
|
@@ -891,6 +894,20 @@ function EditorPageContent() {
|
|
|
891
894
|
createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
|
|
892
895
|
};
|
|
893
896
|
await saveGameSession(session);
|
|
897
|
+
|
|
898
|
+
// 为插件创建世界级绑定(使用全局绑定的配置作为默认值)
|
|
899
|
+
if (validPlugins.length > 0) {
|
|
900
|
+
const globalBindings = await getPluginBindings('global');
|
|
901
|
+
const globalBindingMap = new Map(globalBindings.map(b => [b.extensionId, b]));
|
|
902
|
+
for (const pid of validPlugins) {
|
|
903
|
+
const globalBinding = globalBindingMap.get(pid);
|
|
904
|
+
await upsertPluginBinding({
|
|
905
|
+
extensionId: pid, scope: 'world', worldId: gameId,
|
|
906
|
+
enabled: true, config: globalBinding?.config || {}, sortOrder: 0,
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
894
911
|
navigate(`/game/${gameId}`, {record: recordRouter});
|
|
895
912
|
} catch (err) {
|
|
896
913
|
toast(err instanceof Error ? err.message : '创建游戏失败', 'error');
|