From b1072a9c658f08a22ded2ac41d398887ae4a2024 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Sat, 3 Oct 2026 17:17:59 +0800 Subject: [PATCH 1/6] =?UTF-8?q?docs:=20=E5=BC=95=E7=94=A8=E8=B7=A8=20Peer?= =?UTF-8?q?=20=E5=8F=AF=E8=A7=82=E6=B5=8B=E6=80=A7=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/_shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_shared b/docs/_shared index d87049c..a603b03 160000 --- a/docs/_shared +++ b/docs/_shared @@ -1 +1 @@ -Subproject commit d87049c49ba10f0a710022dce23abcd316127b3c +Subproject commit a603b036fd41dae5a471dea24cd7609bb4927bd5 From b81554d94ffce93628a18c7c4b78b207e65828ae Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Sat, 3 Oct 2026 18:16:46 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=E6=8C=89=E9=9C=80=E5=90=AF?= =?UTF-8?q?=E7=94=A8=E6=B5=8F=E8=A7=88=E5=99=A8=20OTLP=20=E4=B8=8E?= =?UTF-8?q?=E8=B7=A8=20Peer=20Job=20=E8=BF=BD=E8=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client-web/src/core.ts | 16 +- apps/client-web/src/locales/messages/en.json | 9 +- .../src/locales/messages/zh-CN.json | 9 +- apps/client-web/src/views/jobs/job/job.vue | 10 +- .../src/views/settings/settings.vue | 17 +- .../client-runtime-and-delegation.md | 34 ++ docs/40-deployment/web-delivery.md | 33 ++ packages/core/package.json | 9 + packages/core/src/base/db-api.ts | 29 +- packages/core/src/config/schema.ts | 16 + .../core/src/database/database.generated.ts | 6 + packages/core/src/index.ts | 9 +- packages/core/src/job/job.ts | 2 + packages/core/src/job/manager.ts | 101 ++++-- packages/core/src/obsrv/index.ts | 1 + packages/core/src/obsrv/telemetry.ts | 305 ++++++++++++++++++ packages/core/src/peer/contracts.ts | 3 +- packages/core/src/peer/http.ts | 152 +++++---- packages/core/src/peer/manager.ts | 61 ++-- pnpm-lock.yaml | 239 ++++++++++++++ 20 files changed, 938 insertions(+), 123 deletions(-) create mode 100644 packages/core/src/obsrv/telemetry.ts diff --git a/apps/client-web/src/core.ts b/apps/client-web/src/core.ts index 5a1b70e..3e2f24c 100644 --- a/apps/client-web/src/core.ts +++ b/apps/client-web/src/core.ts @@ -7,6 +7,9 @@ import { configStore, + initializeTelemetry, + shutdownTelemetry, + flushTelemetry, ExtensionRegistryOriginResolver, DEFAULT_EXTENSION_REGISTRY_ORIGIN, localStorageAdapter, @@ -205,9 +208,10 @@ export function getExtensionSetupContribution(name: string): ExtensionSetupContr } /** Replace the browser-owned lease runtime after a validated Settings cutover. */ -export function adoptWebPeerRuntime(runtime: WebPeerRuntime): void { +export async function adoptWebPeerRuntime(runtime: WebPeerRuntime): Promise { webPeerRuntime?.stop() webPeerRuntime = runtime + await initializeTelemetry(configStore.metaConfig, WEB_PEER_IDENTITY.applicationVersion) JobManager.startWorker() } @@ -216,6 +220,7 @@ export async function stopWebPeerRuntime(): Promise { webPeerRuntime = null currentWebPeer.value = null await JobManager.stopWorker() + await shutdownTelemetry() } /** Start the lease after Settings has mounted and loaded recovery configuration. */ @@ -226,7 +231,7 @@ export async function startConfiguredWebPeerRuntime(): Promise { const peer = await candidate.register() await configStore.loadPeerConfig() await candidate.start() - adoptWebPeerRuntime(candidate) + await adoptWebPeerRuntime(candidate) currentWebPeer.value = { id: peer.id, name: peer.name } } catch (error) { candidate.stop() @@ -335,7 +340,7 @@ export async function initializeCore(options: { loadPeerConfig?: boolean } = {}) const peer = await candidate.register() await configStore.loadPeerConfig() await candidate.start() - adoptWebPeerRuntime(candidate) + await adoptWebPeerRuntime(candidate) currentWebPeer.value = { id: peer.id, name: peer.name } } catch (error) { candidate.stop() @@ -353,3 +358,8 @@ export async function initializeCore(options: { loadPeerConfig?: boolean } = {}) export async function shutdownCore(): Promise { await stopWebPeerRuntime() } + +// Page termination is best effort; normal connection shutdown awaits bounded SDK drain. +window.addEventListener('pagehide', () => { + void flushTelemetry() +}) diff --git a/apps/client-web/src/locales/messages/en.json b/apps/client-web/src/locales/messages/en.json index be3759e..3d5cfc7 100644 --- a/apps/client-web/src/locales/messages/en.json +++ b/apps/client-web/src/locales/messages/en.json @@ -69,7 +69,11 @@ "resetConfirmMessage": "Are you sure you want to reset all settings to default? This action cannot be undone.", "exportConfig": "Export", "importConfig": "Import", - "importError": "Unable to restore configuration. Check the file and deployment connection." + "importError": "Unable to restore configuration. Check the file and deployment connection.", + "telemetryEnabled": "Enable telemetry for this browser Peer", + "telemetryHelp": "Takes effect after saving the connection. Requires deployment observability endpoints; existing Job logs remain available.", + "telemetryRelay": "Peer telemetry relay URL (optional)", + "telemetryRelayHelp": "Use only a trusted deployment Peer relay. This connection’s short-lived Peer identity authenticates requests; leave empty to use deployment public observability endpoints." }, "source": { "deleteConfirmTitle": "Delete Source", @@ -198,7 +202,8 @@ "retry": "Retry", "notAvailable": "N/A", "notFound": "Job not found", - "sourceNotFound": "Source not found" + "sourceNotFound": "Source not found", + "openDiagnostics": "Open diagnostics (search by Job ID)" }, "logs": { "loading": "Loading logs…", diff --git a/apps/client-web/src/locales/messages/zh-CN.json b/apps/client-web/src/locales/messages/zh-CN.json index e2d1946..d945afb 100644 --- a/apps/client-web/src/locales/messages/zh-CN.json +++ b/apps/client-web/src/locales/messages/zh-CN.json @@ -69,7 +69,11 @@ "resetConfirmMessage": "确定要重置所有设置为默认值吗?此操作无法撤销。", "exportConfig": "导出", "importConfig": "导入", - "importError": "无法恢复配置,请检查文件及部署连接。" + "importError": "无法恢复配置,请检查文件及部署连接。", + "telemetryEnabled": "启用此浏览器 Peer 的遥测", + "telemetryHelp": "保存连接后生效。需要部署配置观测出口;原有 Job 日志继续保留。", + "telemetryRelay": "Peer 遥测中转地址(可选)", + "telemetryRelayHelp": "仅填写可信部署 Peer 的中转地址。此连接的短期 Peer 身份将用于认证;留空使用部署的公开观测出口。" }, "source": { "deleteConfirmTitle": "删除数据源", @@ -199,7 +203,8 @@ "retry": "重试", "notAvailable": "不可用", "notFound": "未找到任务", - "sourceNotFound": "未找到数据源" + "sourceNotFound": "未找到数据源", + "openDiagnostics": "打开诊断入口(使用 Job ID 查询)" }, "logs": { "loading": "正在读取日志…", diff --git a/apps/client-web/src/views/jobs/job/job.vue b/apps/client-web/src/views/jobs/job/job.vue index 20ca40e..4bed875 100644 --- a/apps/client-web/src/views/jobs/job/job.vue +++ b/apps/client-web/src/views/jobs/job/job.vue @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n' import { useAsyncState, useIntervalFn } from '@vueuse/core' import { InkLoading, InkButton, InkField, InkSkeleton } from '@inkcre/ui-web' import LogsViewer from '@/components/obsrv/LogsViewer/LogsViewer.vue' -import { APIError, Job, JobStatus, Source } from '@inkcre/core' +import { APIError, Job, JobStatus, Source, telemetryDiagnosticsUrl } from '@inkcre/core' import dayjs from 'dayjs' const route = useRoute() @@ -147,6 +147,14 @@ watch( + {{ t('job.openDiagnostics') }} +