ai_co_discuss 0.3.52 → 0.3.54
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/docs/THIRD_PARTY_NOTICES.md +5 -1
- package/package.json +2 -1
- package/web/app.js +23 -10
- package/web/modern.css +1 -1
- package/web/modern.js +24128 -13789
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
PDF 站内预览使用 [Mozilla PDF.js](https://github.com/mozilla/pdf.js) 的 `pdfjs-dist 6.4.299`,遵循 Apache-2.0;完整许可证随 [web/pdfjs/LICENSE](../web/pdfjs/LICENSE) 分发。CMap、标准字体、ICC 与 WASM 解码器的独立许可证保留在 `web/pdfjs/cmaps/`、`standard_fonts/`、`iccs/`、`wasm/` 中。构建只复制所需运行文件及这些许可证,不使用远程 CDN。
|
|
14
14
|
|
|
15
|
-
`package.json` 声明直接依赖,`package-lock.json` 记录实际版本、来源及包许可元数据。Vue、Nuxt UI、Markdown-it、KaTeX、Motion、Iconify / Lucide、fflate、uqr
|
|
15
|
+
`package.json` 声明直接依赖,`package-lock.json` 记录实际版本、来源及包许可元数据。Vue、Nuxt UI、Markdown-it、KaTeX、Motion、Iconify / Lucide、fflate、uqr、jsQR 等第三方代码用于前端渲染、本地备份、配对二维码的显示与扫描;Vite、Tailwind CSS 与 Wrangler 用于构建和部署。
|
|
16
16
|
|
|
17
17
|
发布带依赖的程序或重新打包前端时,应保留所使用包中的 LICENSE / NOTICE 文件和生成产物中的许可注释。KaTeX 的样式表与公式字体随前端复制到 `web/katex/`(附其 LICENSE),其包内许可同样适用;Lucide 图标遵循该图标集自身许可。依赖安装后的原始许可位于各 `node_modules/<package>/`,下方附录保存直接依赖及当前前端实际打包模块的许可文本,便于源码与静态产物一同分发。
|
|
18
18
|
|
|
@@ -1263,6 +1263,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
1263
1263
|
SOFTWARE.
|
|
1264
1264
|
```
|
|
1265
1265
|
|
|
1266
|
+
## jsQR 1.4.0
|
|
1267
|
+
|
|
1268
|
+
来源:[jsQR](https://github.com/cozmo/jsQR),用于在网页内扫描设备配对二维码。按 Apache License 2.0 授权,全文见 <https://www.apache.org/licenses/LICENSE-2.0>。
|
|
1269
|
+
|
|
1266
1270
|
## uqr 0.1.2
|
|
1267
1271
|
|
|
1268
1272
|
来源:[uqr](https://github.com/unjs/uqr),用于在网页上显示设备配对二维码。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai_co_discuss",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.54",
|
|
4
4
|
"bin": {
|
|
5
5
|
"codiscuss": "runner/codiscuss.mjs"
|
|
6
6
|
},
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"markdown-it-cjk-friendly": "3.0.0",
|
|
35
35
|
"motion-v": "2.7.0",
|
|
36
36
|
"pdfjs-dist": "6.4.299",
|
|
37
|
+
"jsqr": "1.4.0",
|
|
37
38
|
"uqr": "0.1.2",
|
|
38
39
|
"vite": "8.3.4",
|
|
39
40
|
"vue": "3.5.44",
|
package/web/app.js
CHANGED
|
@@ -53,7 +53,7 @@ const RELAY_PING_MS = 25000;
|
|
|
53
53
|
const ROOM_RELAY_PATH = /^\/api\/(rooms|folders|revisions)(\/|\?|$)/;
|
|
54
54
|
// One part of a file sent to the computer stays well inside the relay's 1 MiB frame once encoded and encrypted.
|
|
55
55
|
const RELAY_UPLOAD_PART_BYTES = 384 * 1024;
|
|
56
|
-
const COMPUTER_UNREACHABLE = "
|
|
56
|
+
const COMPUTER_UNREACHABLE = "电脑未连接:请先与电脑配对,并确认电脑开机且运行 codiscuss";
|
|
57
57
|
let local_connection = null;
|
|
58
58
|
let computer_connecting = false;
|
|
59
59
|
let relay_machine = null;
|
|
@@ -220,7 +220,7 @@ async function request_json(path, payload, access_token) {
|
|
|
220
220
|
const token = access_token || (target_room ? localStorage.getItem(`discuss-access:${target_room}`) : null);
|
|
221
221
|
options.headers = token ? { "X-Discussion-Token": token } : {};
|
|
222
222
|
// The online website has no accounts: a paired device signs its requests with its own non-exportable key.
|
|
223
|
-
if (state.admin.devices && /^\/api\/(machines|admin\/profile)/.test(path)) {
|
|
223
|
+
if ((state.admin.devices || paired_record()) && /^\/api\/(machines|admin\/profile|admin$)/.test(path)) {
|
|
224
224
|
const credential = await device_credential(payload === undefined ? "GET" : "POST", path.split("?")[0]);
|
|
225
225
|
if (credential) options.headers["X-CoDiscuss-Device"] = credential;
|
|
226
226
|
}
|
|
@@ -340,7 +340,7 @@ async function update_admin_profile(patch) {
|
|
|
340
340
|
patch = { ...patch, username: patch.username.trim() };
|
|
341
341
|
}
|
|
342
342
|
const result = await request_json("/api/admin/profile", patch);
|
|
343
|
-
apply_admin_state({ local: state.admin.local, registered: true, setup_available: false, logged_in: true, profile: result.profile });
|
|
343
|
+
apply_admin_state({ local: state.admin.local, devices: state.admin.devices, computer_rooms: state.admin.computer_rooms, registered: true, setup_available: false, logged_in: true, profile: result.profile });
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
/** Shrink the chosen image into a small square data URL that fits the server limit. */
|
|
@@ -1954,8 +1954,8 @@ function save_room_credentials(room, token, members = []) {
|
|
|
1954
1954
|
|
|
1955
1955
|
/** Public administrator state for the account UI; the session token never leaves the controller. */
|
|
1956
1956
|
function admin_snapshot() {
|
|
1957
|
-
const { loaded, local, registered, setup_available, logged_in, profile, identity_version } = state.admin;
|
|
1958
|
-
return { loaded, local, registered, setup_available, logged_in, identity_version, profile: profile && { ...profile } };
|
|
1957
|
+
const { loaded, local, devices, registered, setup_available, logged_in, profile, identity_version } = state.admin;
|
|
1958
|
+
return { loaded, local, devices, registered, setup_available, logged_in, identity_version, profile: profile && { ...profile } };
|
|
1959
1959
|
}
|
|
1960
1960
|
|
|
1961
1961
|
/** Build only non-secret status metadata for the currently selected room. */
|
|
@@ -2080,6 +2080,16 @@ function take_pairing_code() {
|
|
|
2080
2080
|
notify("info", "已读取配对码:打开 设置 → 账号,点“配对”");
|
|
2081
2081
|
}
|
|
2082
2082
|
|
|
2083
|
+
/** Take the code and computer fingerprint from a scanned pairing link; answers the code, or "" when it is not one. */
|
|
2084
|
+
function take_scanned_pairing(text) {
|
|
2085
|
+
const hash = String(text || "").split("#")[1] || "";
|
|
2086
|
+
const code = (hash.match(/(?:^|&)pair=([0-9A-Za-z-]{12,16})/) || [])[1];
|
|
2087
|
+
if (!code) return "";
|
|
2088
|
+
state.device.pairing_code = code.toUpperCase();
|
|
2089
|
+
state.device.pairing_fp = (hash.match(/(?:^|&)fp=([0-9a-f]{32})/) || [])[1] || "";
|
|
2090
|
+
return state.device.pairing_code;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2083
2093
|
/** Read a site-bound connection without exposing its credential to the shared view snapshot. */
|
|
2084
2094
|
function restore_local_connection() {
|
|
2085
2095
|
const fragment = new URLSearchParams(location.hash?.slice(1) || "");
|
|
@@ -2105,6 +2115,8 @@ function restore_local_connection() {
|
|
|
2105
2115
|
async function local_launch_request(action, payload) {
|
|
2106
2116
|
// A website without rooms of its own reaches the computer only through the relay; pairing itself still needs the local bridge.
|
|
2107
2117
|
if (relay_machine && (!local_connection || computer_rooms_only() && action !== "machine-link")) return relay_command(action, payload);
|
|
2118
|
+
// Only the computer's own page has a local service at this address; elsewhere the computer is reached through the relay alone.
|
|
2119
|
+
if (!local_connection && !["127.0.0.1", "localhost"].includes(location.hostname)) throw Object.assign(new Error(COMPUTER_UNREACHABLE), { preflight: true });
|
|
2108
2120
|
const headers = { "Content-Type": "application/json", "X-CoDiscuss-Local": "1" };
|
|
2109
2121
|
if (local_connection) headers["X-CoDiscuss-Connection"] = local_connection.token;
|
|
2110
2122
|
let response;
|
|
@@ -2276,7 +2288,8 @@ async function pair_this_device(code) {
|
|
|
2276
2288
|
state.admin.logged_in = true;
|
|
2277
2289
|
publish_view();
|
|
2278
2290
|
notify("info", "这台设备已与电脑配对");
|
|
2279
|
-
//
|
|
2291
|
+
// The owner's profile, settings and the computer's rooms load now that the computer accepts this device.
|
|
2292
|
+
await load_admin_state();
|
|
2280
2293
|
await load_launch_settings();
|
|
2281
2294
|
if (computer_rooms_only()) connect_computer_rooms();
|
|
2282
2295
|
} });
|
|
@@ -2770,7 +2783,6 @@ async function load_launch_settings() {
|
|
|
2770
2783
|
state.launch.connect_command = local ? "codiscuss local open" : `codiscuss local connect "${location.origin}"`;
|
|
2771
2784
|
try {
|
|
2772
2785
|
local_connection = null;
|
|
2773
|
-
relay_machine = null;
|
|
2774
2786
|
take_pairing_code();
|
|
2775
2787
|
local_connection = restore_local_connection();
|
|
2776
2788
|
state.launch.remote = Boolean(local_connection);
|
|
@@ -2779,8 +2791,9 @@ async function load_launch_settings() {
|
|
|
2779
2791
|
// Pair first, so the computer this page runs on can then be reached through the relay like any other device.
|
|
2780
2792
|
state.launch.relay = await load_relay_machine();
|
|
2781
2793
|
// An online computer that publishes a command key does everything the local service would; an older one only creates rooms.
|
|
2782
|
-
|
|
2783
|
-
relay_machine = state.launch.relay;
|
|
2794
|
+
// The previous one stays in use until this answer arrives, so requests made meanwhile still reach the computer.
|
|
2795
|
+
relay_machine = state.launch.relay?.online && state.launch.relay.public_key ? state.launch.relay : null;
|
|
2796
|
+
if (!relay_machine) return;
|
|
2784
2797
|
state.launch.remote = true;
|
|
2785
2798
|
}
|
|
2786
2799
|
const settings = await local_launch_request("settings");
|
|
@@ -4689,7 +4702,7 @@ window.discuss_view = { snapshot: view_snapshot, write_field: write_view_field,
|
|
|
4689
4702
|
admin: { register: register_admin, login: login_admin, logout: logout_admin,
|
|
4690
4703
|
update_profile: update_admin_profile, avatar_from_file: admin_avatar_from_file, validate: validate_admin_form,
|
|
4691
4704
|
sessions: admin_sessions, revoke: revoke_admin_sessions, change_password: change_admin_password },
|
|
4692
|
-
device: { request: device_request, pair: pair_this_device, invite: invite_device, renew: renew_this_device, confirm_write: confirm_write_grant, forget: forget_pairing,
|
|
4705
|
+
device: { request: device_request, pair: pair_this_device, take_scanned: take_scanned_pairing, invite: invite_device, renew: renew_this_device, confirm_write: confirm_write_grant, forget: forget_pairing,
|
|
4693
4706
|
label: device_label, prompt_confirm: () => state.device.prompt?.run(), prompt_cancel: () => state.device.prompt?.cancel() },
|
|
4694
4707
|
request: request_json, rewind_plan, identities: IDENTITIES, display_name, mention_handles, mentioned_members, render_room_markdown, sources: SOURCE_LABELS,
|
|
4695
4708
|
set_member_access, set_member_model, allow_denials, set_member_adapter, reload_room_models, read_room_files, limits_label, stop_reason_label, participant_model, participant_files, participant_session_hint, participant_access,
|