agentworkshop 0.7.9 → 0.7.11
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/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{BUPj10t4.js → 6vYobj4F.js} +1 -1
- package/.output/public/_nuxt/{BCJFMBQ6.js → B-xskWta.js} +1 -1
- package/.output/public/_nuxt/{BC8s1Guv.js → B3Psw_sL.js} +1 -1
- package/.output/public/_nuxt/B53Mp7lD.js +1 -0
- package/.output/public/_nuxt/B5CYgFAD.js +14 -0
- package/.output/public/_nuxt/{91DZTUMJ.js → B8WV7GzS.js} +1 -1
- package/.output/public/_nuxt/{BDASpD_i.js → BBwMH_hG.js} +1 -1
- package/.output/public/_nuxt/BLzCac9K2.js +1 -0
- package/.output/public/_nuxt/BNXfwXpE.js +1 -0
- package/.output/public/_nuxt/BbZAzXjZ2.js +1 -0
- package/.output/public/_nuxt/{CFn4vHwD.js → Bc3PiGGr.js} +1 -1
- package/.output/public/_nuxt/{B0HpdCKS.js → Bckshc9V.js} +1 -1
- package/.output/public/_nuxt/BcrN7QEl2.js +1 -0
- package/.output/public/_nuxt/BgOhoDTI.js +1 -0
- package/.output/public/_nuxt/Bmpvki7M.js +1 -0
- package/.output/public/_nuxt/BxPPAkGA.js +3 -0
- package/.output/public/_nuxt/{u7KWCGSb.js → BxtpDtzC.js} +1 -1
- package/.output/public/_nuxt/{DxrgFxIr2.js → C4OAdbVK2.js} +1 -1
- package/.output/public/_nuxt/C6m-kenn.js +1 -0
- package/.output/public/_nuxt/{DDdEnkdw.js → CGx-mtWf.js} +1 -1
- package/.output/public/_nuxt/Cj6139IM.js +1 -0
- package/.output/public/_nuxt/{6PZPfFcO.js → Cor9siSf.js} +1 -1
- package/.output/public/_nuxt/{wirVyscc.js → D7jiode2.js} +1 -1
- package/.output/public/_nuxt/{Ct68Z0232.js → DA4lxCWC2.js} +1 -1
- package/.output/public/_nuxt/DEaY_uvR.js +1 -0
- package/.output/public/_nuxt/{MyA0Oeqd.js → DNxVTfhe.js} +1 -1
- package/.output/public/_nuxt/DT-Wg8r1.js +1 -0
- package/.output/public/_nuxt/DTYBfjRY.js +1 -0
- package/.output/public/_nuxt/{DvgKXPgu2.js → DWcEk1ur2.js} +1 -1
- package/.output/public/_nuxt/Dhqra7NB.js +1 -0
- package/.output/public/_nuxt/DlRO_q5L.js +1 -0
- package/.output/public/_nuxt/{D8EfUxO2.js → Ds8JbqGB.js} +1 -1
- package/.output/public/_nuxt/{DN5RuZ8k.js → DyisHHzD.js} +1 -1
- package/.output/public/_nuxt/ORt9oDIy2.js +1 -0
- package/.output/public/_nuxt/{By8BpbKH.js → QoCzfpo2.js} +1 -1
- package/.output/public/_nuxt/RzXYI9FM.js +23 -0
- package/.output/public/_nuxt/{BuktKVqK2.js → arUY5dyq2.js} +2 -2
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/88479a5b-ce6a-400f-9737-1cc9f54b1fe5.json +1 -0
- package/.output/public/_nuxt/{pKv_VWR4.js → d_Sz9KGm.js} +1 -1
- package/.output/public/_nuxt/{default.BR3e5fPY.css → default.BbgdTDCk.css} +1 -1
- package/.output/public/_nuxt/{C9cU_Ujd.js → eHYnGew0.js} +1 -1
- package/.output/public/_nuxt/{DM4CNkXz.js → eUGyJdiT.js} +1 -1
- package/.output/public/_nuxt/{entry.5qf6EqfN.css → entry.B03HBJGC.css} +1 -1
- package/.output/public/_nuxt/{B1g8pJmr.js → kkEthL84.js} +1 -1
- package/.output/public/_nuxt/permissions.CwZo6t1V.css +1 -0
- package/.output/public/_nuxt/settings.BqMF2nfj.css +1 -0
- package/.output/public/_nuxt/{D0Szyn_D.js → tJuVvBSl.js} +1 -1
- package/.output/public/_nuxt/zVkqCZ78.js +1 -0
- package/.output/server/chunks/_/LeftOutlined.mjs +1 -1
- package/.output/server/chunks/_/SearchOutlined.mjs +1 -1
- package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
- package/.output/server/chunks/_/host-bindings.mjs +1 -1
- package/.output/server/chunks/_/nitro.mjs +1636 -1315
- package/.output/server/chunks/_/nitro.mjs.map +1 -1
- package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
- package/.output/server/chunks/build/Col-biaNnEPf.mjs +1 -1
- package/.output/server/chunks/build/{OmpTerminalPanel-COphA1br.mjs → OmpTerminalPanel-Ban3yJZ4.mjs} +4 -5
- package/.output/server/chunks/build/OmpTerminalPanel-Ban3yJZ4.mjs.map +1 -0
- package/.output/server/chunks/build/{TownView-D8DSdO3H.mjs → TownView-CunmEMzS.mjs} +8 -9
- package/.output/server/chunks/build/{TownView-D8DSdO3H.mjs.map → TownView-CunmEMzS.mjs.map} +1 -1
- package/.output/server/chunks/build/{_id_-BV4FfiYd.mjs → _id_-CVnMdSeG.mjs} +7 -7
- package/.output/server/chunks/build/{_id_-BV4FfiYd.mjs.map → _id_-CVnMdSeG.mjs.map} +1 -1
- package/.output/server/chunks/build/{_id_-TP9hvnBM.mjs → _id_-D265Wh_k.mjs} +7 -7
- package/.output/server/chunks/build/{_id_-TP9hvnBM.mjs.map → _id_-D265Wh_k.mjs.map} +1 -1
- package/.output/server/chunks/build/{_wsId_-Mm9sQSz2.mjs → _wsId_-eNJmBp05.mjs} +17 -17
- package/.output/server/chunks/build/{_wsId_-Mm9sQSz2.mjs.map → _wsId_-eNJmBp05.mjs.map} +1 -1
- package/.output/server/chunks/build/{agents-To3a5xcZ.mjs → agents-B10wmFri.mjs} +9 -9
- package/.output/server/chunks/build/{agents-To3a5xcZ.mjs.map → agents-B10wmFri.mjs.map} +1 -1
- package/.output/server/chunks/build/alert-qJnjyRcP.mjs +1 -1
- package/.output/server/chunks/build/api-error-dul30BYQ.mjs +1 -1
- package/.output/server/chunks/build/button-DEcZFcqN.mjs +2 -2
- package/.output/server/chunks/build/{card-Dipvaykh.mjs → card-CCPQoKlh.mjs} +4 -4
- package/.output/server/chunks/build/{card-Dipvaykh.mjs.map → card-CCPQoKlh.mjs.map} +1 -1
- package/.output/server/chunks/build/{channel-templates-DRsP-qxl.mjs → channel-templates-CpWxVk5A.mjs} +7 -7
- package/.output/server/chunks/build/{channel-templates-DRsP-qxl.mjs.map → channel-templates-CpWxVk5A.mjs.map} +1 -1
- package/.output/server/chunks/build/{checkbox-dzcpU_Cd.mjs → checkbox-Dv1kjaUZ.mjs} +3 -3
- package/.output/server/chunks/build/{checkbox-dzcpU_Cd.mjs.map → checkbox-Dv1kjaUZ.mjs.map} +1 -1
- package/.output/server/chunks/build/client-only-D5BzSQc6.mjs +1 -1
- package/.output/server/chunks/build/{daq-_hCEaYLd.mjs → daq-DxaXk_8N.mjs} +9 -10
- package/.output/server/chunks/build/daq-DxaXk_8N.mjs.map +1 -0
- package/.output/server/chunks/build/{dcw-C7pJ4Y0p.mjs → dcw-DqjHrl5Z.mjs} +5 -5
- package/.output/server/chunks/build/{dcw-C7pJ4Y0p.mjs.map → dcw-DqjHrl5Z.mjs.map} +1 -1
- package/.output/server/chunks/build/{default-Dnjs36e8.mjs → default-YcUHc1Ev.mjs} +19 -12
- package/.output/server/chunks/build/{default-Dnjs36e8.mjs.map → default-YcUHc1Ev.mjs.map} +1 -1
- package/.output/server/chunks/build/drawer-Cmh90erI.mjs +1 -1
- package/.output/server/chunks/build/dropdown-vhn1NPFs.mjs +2 -2
- package/.output/server/chunks/build/hasIn-vQ9LWt-J.mjs +554 -0
- package/.output/server/chunks/build/hasIn-vQ9LWt-J.mjs.map +1 -0
- package/.output/server/chunks/build/initDefaultProps-DIbWwP4R.mjs +1 -1
- package/.output/server/chunks/build/{input-sf_BT6o6.mjs → input-DxDqeyQW.mjs} +5 -553
- package/.output/server/chunks/build/input-DxDqeyQW.mjs.map +1 -0
- package/.output/server/chunks/build/{input-number-Bd55elNN.mjs → input-number-CZ3ZrCsy.mjs} +3 -3
- package/.output/server/chunks/build/{input-number-Bd55elNN.mjs.map → input-number-CZ3ZrCsy.mjs.map} +1 -1
- package/.output/server/chunks/build/{logs-C039TFW1.mjs → logs-Co854R4y.mjs} +6 -7
- package/.output/server/chunks/build/logs-Co854R4y.mjs.map +1 -0
- package/.output/server/chunks/build/menu-WCrlpYVh.mjs +2 -2
- package/.output/server/chunks/build/modal-yvUquPj5.mjs +2 -2
- package/.output/server/chunks/build/{monitor-MIOvsyLa.mjs → monitor-miqq9xHB.mjs} +11 -11
- package/.output/server/chunks/build/{monitor-MIOvsyLa.mjs.map → monitor-miqq9xHB.mjs.map} +1 -1
- package/.output/server/chunks/build/{pages-C_VSGSGo.mjs → pages-DPC1Vp6w.mjs} +5 -5
- package/.output/server/chunks/build/{pages-C_VSGSGo.mjs.map → pages-DPC1Vp6w.mjs.map} +1 -1
- package/.output/server/chunks/build/permissions-Eu9e6hfZ.mjs +534 -0
- package/.output/server/chunks/build/permissions-Eu9e6hfZ.mjs.map +1 -0
- package/.output/server/chunks/build/{plugins-4FMWkN8d.mjs → plugins-D84mvK9G.mjs} +3 -4
- package/.output/server/chunks/build/plugins-D84mvK9G.mjs.map +1 -0
- package/.output/server/chunks/build/popconfirm-CRaHcz5O.mjs +2 -2
- package/.output/server/chunks/build/responsiveObserve-CS0UB6wQ.mjs +1 -1
- package/.output/server/chunks/build/{segmented-DPe9ZzLO.mjs → segmented-ChmQZwz6.mjs} +5 -4
- package/.output/server/chunks/build/{segmented-DPe9ZzLO.mjs.map → segmented-ChmQZwz6.mjs.map} +1 -1
- package/.output/server/chunks/build/select-D-CeE5vY.mjs +1 -1
- package/.output/server/chunks/build/{settings-DA8IkGLo.mjs → settings-BPBll_7K.mjs} +28 -26
- package/.output/server/chunks/build/settings-BPBll_7K.mjs.map +1 -0
- package/.output/server/chunks/build/space-CCBYAkXt.mjs +2 -2
- package/.output/server/chunks/build/spin-HVY81X_L.mjs +1 -1
- package/.output/server/chunks/build/switch-CelRXpcy.mjs +2 -2
- package/.output/server/chunks/build/{table-Cswq-l2r.mjs → table-BtksyDlQ.mjs} +5 -5
- package/.output/server/chunks/build/{table-Cswq-l2r.mjs.map → table-BtksyDlQ.mjs.map} +1 -1
- package/.output/server/chunks/build/{tabs-BM3tAh_J.mjs → tabs-DQv-_-R6.mjs} +3 -3
- package/.output/server/chunks/build/{tabs-BM3tAh_J.mjs.map → tabs-DQv-_-R6.mjs.map} +1 -1
- package/.output/server/chunks/build/{tag-NO9jEqKy.mjs → tag-A0tZ2Ouq.mjs} +4 -4
- package/.output/server/chunks/build/{tag-NO9jEqKy.mjs.map → tag-A0tZ2Ouq.mjs.map} +1 -1
- package/.output/server/chunks/build/{teams-DA1lkf1n.mjs → teams-CNflUtPh.mjs} +7 -7
- package/.output/server/chunks/build/{teams-DA1lkf1n.mjs.map → teams-CNflUtPh.mjs.map} +1 -1
- package/.output/server/chunks/build/{tokens-DKMvvk3e.mjs → tokens-CZpnEDVf.mjs} +10 -10
- package/.output/server/chunks/build/{tokens-DKMvvk3e.mjs.map → tokens-CZpnEDVf.mjs.map} +1 -1
- package/.output/server/chunks/build/town-BUqRobze.mjs +1 -1
- package/.output/server/chunks/build/{town-D0thZ7PK.mjs → town-BbaR-8io.mjs} +9 -10
- package/.output/server/chunks/build/town-BbaR-8io.mjs.map +1 -0
- package/.output/server/chunks/build/{useDaqStream-BVTRw8_H.mjs → useDaqStream-BkmyQT06.mjs} +34 -23
- package/.output/server/chunks/build/useDaqStream-BkmyQT06.mjs.map +1 -0
- package/.output/server/chunks/build/{useDcwStream-DNsivqI_.mjs → useDcwStream-DWVoU96J.mjs} +60 -46
- package/.output/server/chunks/build/useDcwStream-DWVoU96J.mjs.map +1 -0
- package/.output/server/chunks/build/{useDeviceTwins-WeIom7A6.mjs → useDeviceTwins-34WGk9aN.mjs} +2 -2
- package/.output/server/chunks/build/{useDeviceTwins-WeIom7A6.mjs.map → useDeviceTwins-34WGk9aN.mjs.map} +1 -1
- package/.output/server/chunks/build/useLocalTime-9a4B-aHv.mjs +1 -1
- package/.output/server/chunks/build/{useOpsLog-DcKnPO43.mjs → useOpsLog-C9zTzYof.mjs} +27 -15
- package/.output/server/chunks/build/useOpsLog-C9zTzYof.mjs.map +1 -0
- package/.output/server/chunks/build/useSiteConfig-DJe_KMVr.mjs +1 -1
- package/.output/server/chunks/build/useWorkshopApi-D2gq06N2.mjs +1 -1
- package/.output/server/chunks/build/{useWorkshopWs-B3j5wIAK.mjs → useWorkshopWs-CprkZEdq.mjs} +2 -3
- package/.output/server/chunks/build/useWorkshopWs-CprkZEdq.mjs.map +1 -0
- package/.output/server/chunks/build/{users-CmVvb1oq.mjs → users-D6RNylrW.mjs} +10 -10
- package/.output/server/chunks/build/{users-CmVvb1oq.mjs.map → users-D6RNylrW.mjs.map} +1 -1
- package/.output/server/chunks/build/{workshop-BhWnJMWs.mjs → workshop-Crsai2Y9.mjs} +9 -9
- package/.output/server/chunks/build/{workshop-BhWnJMWs.mjs.map → workshop-Crsai2Y9.mjs.map} +1 -1
- package/.output/server/chunks/build/{workspaces-IfORCDJE.mjs → workspaces-BuydxM-3.mjs} +2 -3
- package/.output/server/chunks/build/workspaces-BuydxM-3.mjs.map +1 -0
- package/.output/server/chunks/routes/api/health.get.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/mcp/workshop.mjs +1 -1
- package/.output/server/chunks/routes/api/metrics.mjs +1 -1
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -1
- package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/config.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/index.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +1 -1
- package/.output/server/chunks/routes/api/system/monitor.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/settings/events.get.mjs +1 -1
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/_id_.put.mjs +1 -1
- package/.output/server/chunks/routes/api/users/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/login.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/logout.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/me.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/register.post.mjs +1 -1
- package/.output/server/chunks/routes/api/users/setup-status.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/_...path_.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +19 -8
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/audit.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/caller.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +3 -3
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs +3 -3
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +7 -6
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +5 -2
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +7 -6
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +4 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +8 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +4 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +4 -4
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +7 -3
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +3 -2
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +5 -3
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index.put.mjs +41 -0
- package/.output/server/chunks/routes/api/workshop/index.put.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs +4 -3
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index11.get.mjs +27 -0
- package/.output/server/chunks/routes/api/workshop/index11.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs +4 -4
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.get.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs +18 -11
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs +24 -12
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs +12 -7
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +2 -2
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +3 -3
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +1 -1
- package/.output/server/chunks/routes/renderer.mjs +3 -3
- package/.output/server/chunks/virtual/entry.mjs +271 -31
- package/.output/server/chunks/virtual/entry.mjs.map +1 -1
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +1 -1
- package/.output/server/package.json +1 -1
- package/README-zh.md +15 -0
- package/README.md +20 -0
- package/app/components/AppSidebar.vue +7 -1
- package/app/composables/workshop/apiClient.ts +103 -95
- package/app/composables/workshop/useDaqStream.ts +35 -21
- package/app/composables/workshop/useDcwStream.ts +22 -5
- package/app/composables/workshop/useOpsLog.ts +26 -13
- package/app/composables/workshop/useWorkshopWs.ts +11 -2
- package/app/pages/permissions/index.vue +327 -0
- package/app/pages/settings.vue +4 -2
- package/app/plugins/http.ts +18 -2
- package/app/plugins/session-restore.client.ts +7 -2
- package/app/stores/workshop/user.ts +14 -1
- package/i18n/locales/en.ts +37 -0
- package/i18n/locales/zh-CN.ts +37 -0
- package/package.json +1 -1
- package/scripts/_dbg-acc-1-setup.mjs +57 -0
- package/scripts/_dbg-acc-2-diag.mjs +14 -0
- package/scripts/_dbg-acc-2-intervals.mjs +81 -0
- package/scripts/_dbg-acc-3-daq.mjs +48 -0
- package/scripts/_dbg-acc-4-team.mjs +92 -0
- package/scripts/_dbg-acc-5-visual.mjs +63 -0
- package/scripts/_dbg-acc-5b-ws-town.mjs +18 -0
- package/scripts/_dbg-acc-5c-town.mjs +12 -0
- package/scripts/_dbg-acc-6-i18n.mjs +19 -0
- package/scripts/_dbg-audit-neg-e2e.mjs +64 -0
- package/scripts/_dbg-final-features.mjs +155 -0
- package/scripts/_dbg-final-fixups.mjs +62 -0
- package/scripts/_dbg-final-visual.mjs +29 -0
- package/scripts/_dbg-perms-e2e.mjs +102 -0
- package/scripts/_dbg-perms-visual.mjs +36 -0
- package/scripts/_dbg-protocol-matrix.mjs +16 -0
- package/sdk/api.mjs +117 -101
- package/sdk/context.mjs +240 -219
- package/sdk/hooks.mjs +105 -103
- package/sdk/index.d.mts +142 -135
- package/sdk/lifecycle.mjs +26 -25
- package/server/api/workshop/agent-tools/bindings/index.post.ts +40 -20
- package/server/api/workshop/daq/[id]/bind.post.ts +5 -2
- package/server/api/workshop/daq/[id]/frames/content.get.ts +4 -1
- package/server/api/workshop/daq/[id]/frames.get.ts +4 -1
- package/server/api/workshop/daq/[id]/samples.get.ts +4 -1
- package/server/api/workshop/daq/[id].patch.ts +3 -0
- package/server/api/workshop/daq/alarms/[id]/ack.post.ts +20 -15
- package/server/api/workshop/daq/controller.post.ts +2 -0
- package/server/api/workshop/daq/index.get.ts +5 -3
- package/server/api/workshop/daq/index.post.ts +2 -2
- package/server/api/workshop/dcw/[id]/bind.post.ts +20 -17
- package/server/api/workshop/dcw/[id]/test.post.ts +18 -15
- package/server/api/workshop/dcw/[id]/write.post.ts +3 -0
- package/server/api/workshop/dcw/index.get.ts +22 -9
- package/server/api/workshop/dcw/line/query.get.ts +38 -31
- package/server/api/workshop/dcw/lines/[id]/start.post.ts +3 -0
- package/server/api/workshop/dcw/lines/[id]/stop.post.ts +3 -0
- package/server/api/workshop/dcw/lines/index.get.ts +8 -2
- package/server/api/workshop/dcw/lines/index.post.ts +2 -2
- package/server/api/workshop/dcw/products/index.post.ts +16 -16
- package/server/api/workshop/dcw/runs/[id]/data.get.ts +20 -15
- package/server/api/workshop/dcw/runs/index.get.ts +13 -11
- package/server/api/workshop/permissions/index.get.ts +30 -0
- package/server/api/workshop/permissions/index.put.ts +29 -0
- package/server/api/workshop/ws.ts +18 -6
- package/server/data/daqs.json +48 -48
- package/server/data/dcw-products.json +21 -0
- package/server/data/dcw-recipes.json +84 -0
- package/server/data/dcw-rollback.json +94 -6
- package/server/data/dcw-runs.json +81 -75
- package/server/data/dcw-writes.json +108 -0
- package/server/data/dcws.json +645 -382
- package/server/data/line-runs.json +8 -8
- package/server/plugins/backup.ts +119 -116
- package/server/repositories/user.repository.ts +86 -6
- package/server/services/user.service.ts +5 -3
- package/server/services/workshop/daq/bus/index.ts +5 -3
- package/server/services/workshop/daq/bus/inproc.adapter.ts +12 -3
- package/server/services/workshop/daq/bus/mqtt.adapter.ts +13 -0
- package/server/services/workshop/daq/bus/queue-port.ts +2 -0
- package/server/services/workshop/daq/daq-controller.ts +18 -1
- package/server/services/workshop/db/ops.repo.ts +6 -0
- package/server/services/workshop/dcw/dcw-controller.ts +10 -2
- package/server/services/workshop/permissions.ts +79 -0
- package/server/services/workshop/plugins/host.mjs +38 -1
- package/server/services/workshop/scene-events.ts +25 -1
- package/shared/config/single-instance.mjs +24 -0
- package/shared/daq-protocol.ts +2 -0
- package/.output/public/_nuxt/B1kA8LhC.js +0 -14
- package/.output/public/_nuxt/B9MUiDFl.js +0 -1
- package/.output/public/_nuxt/B9dLFSYI.js +0 -1
- package/.output/public/_nuxt/BaMkWl5i2.js +0 -1
- package/.output/public/_nuxt/BmHvC_OU.js +0 -1
- package/.output/public/_nuxt/CBciOiTQ.js +0 -1
- package/.output/public/_nuxt/CUMdhxg9.js +0 -1
- package/.output/public/_nuxt/CgvGu2IO.js +0 -1
- package/.output/public/_nuxt/CjDQPXfv.js +0 -1
- package/.output/public/_nuxt/CmHzfVc5.js +0 -3
- package/.output/public/_nuxt/Cn3J3NXR.js +0 -23
- package/.output/public/_nuxt/Cst47G4-.js +0 -1
- package/.output/public/_nuxt/D3VJ3lex.js +0 -1
- package/.output/public/_nuxt/D8wyHvcz2.js +0 -1
- package/.output/public/_nuxt/Dqj2h40U.js +0 -1
- package/.output/public/_nuxt/OV6PBW2z.js +0 -1
- package/.output/public/_nuxt/builds/meta/92d6bd39-dbc5-46d5-90d8-8387f36715fa.json +0 -1
- package/.output/public/_nuxt/settings.DeRNNUcP.css +0 -1
- package/.output/server/chunks/build/OmpTerminalPanel-COphA1br.mjs.map +0 -1
- package/.output/server/chunks/build/daq-_hCEaYLd.mjs.map +0 -1
- package/.output/server/chunks/build/input-sf_BT6o6.mjs.map +0 -1
- package/.output/server/chunks/build/logs-C039TFW1.mjs.map +0 -1
- package/.output/server/chunks/build/plugins-4FMWkN8d.mjs.map +0 -1
- package/.output/server/chunks/build/settings-DA8IkGLo.mjs.map +0 -1
- package/.output/server/chunks/build/town-D0thZ7PK.mjs.map +0 -1
- package/.output/server/chunks/build/useDaqStream-BVTRw8_H.mjs.map +0 -1
- package/.output/server/chunks/build/useDcwStream-DNsivqI_.mjs.map +0 -1
- package/.output/server/chunks/build/useOpsLog-DcKnPO43.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkshopWs-B3j5wIAK.mjs.map +0 -1
- package/.output/server/chunks/build/user-Dk-ytEUV.mjs +0 -140
- package/.output/server/chunks/build/user-Dk-ytEUV.mjs.map +0 -1
- package/.output/server/chunks/build/workspaces-IfORCDJE.mjs.map +0 -1
- /package/.output/public/_nuxt/{CNs_Ozdc2.js → CNs_Ozdc.js} +0 -0
- /package/.output/public/_nuxt/{Cno6kYiO2.js → Cno6kYiO.js} +0 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"productId": "pd-6348a595",
|
|
8
8
|
"productName": "0.8mm 光学膜",
|
|
9
9
|
"startedAt": "2026-09-03T11:18:01.213Z",
|
|
10
|
-
"taggedSamples":
|
|
10
|
+
"taggedSamples": 49286
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"lineId": "ln-9a60a0cd",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"productId": "pd-db432902",
|
|
58
58
|
"productName": "探针产品",
|
|
59
59
|
"startedAt": "2026-09-04T05:08:10.103Z",
|
|
60
|
-
"taggedSamples":
|
|
60
|
+
"taggedSamples": 17196
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
"lineId": "ln-6a34fbc7",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"productId": "pd-10cfc2b3",
|
|
68
68
|
"productName": "全协议产品-mtnynfph",
|
|
69
69
|
"startedAt": "2026-09-05T05:47:26.453Z",
|
|
70
|
-
"taggedSamples":
|
|
70
|
+
"taggedSamples": 48679
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"lineId": "ln-419463e0",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"productId": "pd-b9b15b64",
|
|
78
78
|
"productName": "全协议产品-mtnzg090",
|
|
79
79
|
"startedAt": "2026-09-05T06:09:36.931Z",
|
|
80
|
-
"taggedSamples":
|
|
80
|
+
"taggedSamples": 48652
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"lineId": "ln-3548f325",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"productId": "pd-fd822802",
|
|
88
88
|
"productName": "runp3-prod",
|
|
89
89
|
"startedAt": "2026-09-05T07:23:51.972Z",
|
|
90
|
-
"taggedSamples":
|
|
90
|
+
"taggedSamples": 3925
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"lineId": "ln-c3a7ba01",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"productId": "pd-d547a376",
|
|
108
108
|
"productName": "pp-prod",
|
|
109
109
|
"startedAt": "2026-09-05T09:47:55.526Z",
|
|
110
|
-
"taggedSamples":
|
|
110
|
+
"taggedSamples": 6231
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"lineId": "ln-1acc1a0c",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"productId": "pd-3adf854f",
|
|
118
118
|
"productName": "lx8-prod",
|
|
119
119
|
"startedAt": "2026-09-06T02:22:23.209+08:00",
|
|
120
|
-
"taggedSamples":
|
|
120
|
+
"taggedSamples": 4136
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"lineId": "ln-917490c1",
|
|
@@ -127,6 +127,6 @@
|
|
|
127
127
|
"productId": "pd-75752beb",
|
|
128
128
|
"productName": "lx8-prod",
|
|
129
129
|
"startedAt": "2026-09-06T02:24:50.582+08:00",
|
|
130
|
-
"taggedSamples":
|
|
130
|
+
"taggedSamples": 3995
|
|
131
131
|
}
|
|
132
132
|
]
|
package/server/plugins/backup.ts
CHANGED
|
@@ -1,116 +1,119 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 备份定时插件(S6,production-readiness-plan)。
|
|
3
|
-
*
|
|
4
|
-
* 对 data/ 下三库(workshop/users/daq-timeseries)每日 serialize 镜像快照到
|
|
5
|
-
* data/backups/,按 BACKUP_KEEP(默认 7)轮转;调度模式复用 ws.ts 保留期清理的
|
|
6
|
-
* setInterval + globalThis key 防 HMR 重复 + unref()。dev 与生产均生效
|
|
7
|
-
* (备份无副作用,始终开启;BACKUP_DISABLED=1 可关)。
|
|
8
|
-
*/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
copyFileSync
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 备份定时插件(S6,production-readiness-plan)。
|
|
3
|
+
*
|
|
4
|
+
* 对 data/ 下三库(workshop/users/daq-timeseries)每日 serialize 镜像快照到
|
|
5
|
+
* data/backups/,按 BACKUP_KEEP(默认 7)轮转;调度模式复用 ws.ts 保留期清理的
|
|
6
|
+
* setInterval + globalThis key 防 HMR 重复 + unref()。dev 与生产均生效
|
|
7
|
+
* (备份无副作用,始终开启;BACKUP_DISABLED=1 可关)。
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs'
|
|
10
|
+
import { copyFile as copyFileAsync } from 'node:fs/promises'
|
|
11
|
+
import { resolve } from 'node:path'
|
|
12
|
+
import { ensureDataDir } from '@/shared/config/home.mjs'
|
|
13
|
+
import { backupSettings } from '../services/workshop/settings'
|
|
14
|
+
import { backupRegistry } from '../services/workshop/db/backup-registry'
|
|
15
|
+
|
|
16
|
+
const g = globalThis as typeof globalThis & { __awBackupTimer?: NodeJS.Timeout, __awBackupLastAt?: string }
|
|
17
|
+
|
|
18
|
+
const DB_FILES = ['workshop.sqlite', 'users.sqlite', 'daq-timeseries.sqlite'] as const
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 单库在线快照(hardening ST-2 终版:零侵入文件拷贝)。
|
|
22
|
+
*
|
|
23
|
+
* 真实事故两连(Windows + node:sqlite):
|
|
24
|
+
* 1) 对活库开第二连接 serialize/close → 主连接 prepared statements 全部失效;
|
|
25
|
+
* 2) 对主连接 serialize() → 该连接上全部语句被 finalize(20 分钟后 Mailbox 一用即炸)。
|
|
26
|
+
* 结论:node:sqlite 上 serialize 路线对常驻服务不可行。终版:PASSIVE checkpoint
|
|
27
|
+
* (尽力把 WAL 并回主文件,失败不影响服务)→ 拷贝主文件。得到的是「最后一次
|
|
28
|
+
* checkpoint 时刻」的有效 SQLite 镜像;备份语义为日级韧性的兜底,允许略旧。
|
|
29
|
+
*/
|
|
30
|
+
async function backupOne(src: string, target: string): Promise<void> {
|
|
31
|
+
const db = backupRegistry.get(src)
|
|
32
|
+
if (db) {
|
|
33
|
+
try {
|
|
34
|
+
db.exec('PRAGMA wal_checkpoint(PASSIVE)')
|
|
35
|
+
}
|
|
36
|
+
catch { /* 忙时跳过 checkpoint,拷出的镜像退回上次 checkpoint 点,仍有效 */ }
|
|
37
|
+
}
|
|
38
|
+
// 原子落盘:快照写一半被杀会留下截断 .bak(轮转后还被当作有效备份)
|
|
39
|
+
// 异步拷贝:daq-timeseries 可达数百 MB,copyFileSync 会同步冻结事件循环数秒
|
|
40
|
+
// (期间 WS 扇出/采样 sweep/API 全部停摆)
|
|
41
|
+
const tmp = `${target}.tmp`
|
|
42
|
+
await copyFileAsync(src, tmp)
|
|
43
|
+
try {
|
|
44
|
+
renameSync(tmp, target)
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// rename 失败(目标被占用等):退回直写,可用性优先
|
|
48
|
+
await copyFileAsync(src, target)
|
|
49
|
+
try {
|
|
50
|
+
rmSync(tmp)
|
|
51
|
+
}
|
|
52
|
+
catch { /* ignore */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function backupOnce(dataDir: string): Promise<void> {
|
|
57
|
+
const backupDir = resolve(dataDir, 'backups')
|
|
58
|
+
mkdirSync(backupDir, { recursive: true })
|
|
59
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)
|
|
60
|
+
for (const file of DB_FILES) {
|
|
61
|
+
const src = resolve(dataDir, file)
|
|
62
|
+
if (!existsSync(src) || !backupRegistry.has(src)) continue
|
|
63
|
+
const target = resolve(backupDir, `${file}.${stamp}.bak`)
|
|
64
|
+
try {
|
|
65
|
+
await backupOne(src, target)
|
|
66
|
+
console.log('[backup]', file, '快照完成(serialize)')
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.error(`[backup] ${file} 快照失败:`, err instanceof Error ? err.message : err)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// 轮转:每库仅保留最近 backup.keep 份(按文件名内时间戳倒序;env BACKUP_KEEP 兼容)
|
|
73
|
+
const keep = Math.max(1, backupSettings().keep)
|
|
74
|
+
for (const file of DB_FILES) {
|
|
75
|
+
const own = readdirSync(backupDir)
|
|
76
|
+
.filter(f => f.startsWith(`${file}.`) && f.endsWith('.bak'))
|
|
77
|
+
.sort()
|
|
78
|
+
.reverse()
|
|
79
|
+
for (const stale of own.slice(keep)) {
|
|
80
|
+
try {
|
|
81
|
+
rmSync(resolve(backupDir, stale))
|
|
82
|
+
}
|
|
83
|
+
catch { /* 轮转失败不致命 */ }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
console.log('[backup] 快照完成 →', backupDir)
|
|
87
|
+
// R4:记录最近一次成功备份时间,供 /api/metrics 观测
|
|
88
|
+
g.__awBackupLastAt = new Date().toISOString()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default function backupPlugin() {
|
|
92
|
+
const backupCfg = backupSettings()
|
|
93
|
+
if (backupCfg.disabled) return
|
|
94
|
+
if (g.__awBackupTimer) return
|
|
95
|
+
const dataDir = ensureDataDir()
|
|
96
|
+
|
|
97
|
+
// 启动 30s 后首备(避开启动风暴),此后每 backup.interval_hours(默认 24h)
|
|
98
|
+
const first = setTimeout(() => {
|
|
99
|
+
try {
|
|
100
|
+
// backupOnce 是 async:同步 try/catch 接不住内部 rejection(会变成 unhandled
|
|
101
|
+
// rejection 触发 dev-stability-guard 退进程),必须显式 .catch
|
|
102
|
+
backupOnce(dataDir).catch((err: unknown) => {
|
|
103
|
+
console.error('[backup] 首备失败:', err instanceof Error ? err.message : err)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.error('[backup] 首备失败:', err instanceof Error ? err.message : err)
|
|
108
|
+
}
|
|
109
|
+
}, 30_000)
|
|
110
|
+
first.unref?.()
|
|
111
|
+
const hours = Math.max(1, backupCfg.interval_hours)
|
|
112
|
+
const timer = setInterval(() => {
|
|
113
|
+
backupOnce(dataDir).catch((err: unknown) => {
|
|
114
|
+
console.error('[backup] 定时备份失败:', err instanceof Error ? err.message : err)
|
|
115
|
+
})
|
|
116
|
+
}, hours * 3_600_000)
|
|
117
|
+
timer.unref?.()
|
|
118
|
+
g.__awBackupTimer = timer
|
|
119
|
+
}
|
|
@@ -40,6 +40,14 @@ CREATE TABLE IF NOT EXISTS user_tokens (
|
|
|
40
40
|
last_used_at TEXT
|
|
41
41
|
);
|
|
42
42
|
CREATE INDEX IF NOT EXISTS idx_user_tokens_user ON user_tokens(user_id);
|
|
43
|
+
CREATE TABLE IF NOT EXISTS user_line_grants (
|
|
44
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
45
|
+
line_id TEXT NOT NULL,
|
|
46
|
+
mode TEXT NOT NULL,
|
|
47
|
+
granted_by TEXT,
|
|
48
|
+
granted_at TEXT NOT NULL,
|
|
49
|
+
PRIMARY KEY (user_id, line_id)
|
|
50
|
+
);
|
|
43
51
|
`
|
|
44
52
|
|
|
45
53
|
let db: DatabaseSync | null = null
|
|
@@ -50,6 +58,9 @@ function getDb(): DatabaseSync {
|
|
|
50
58
|
db = new DatabaseSync(DB_PATH)
|
|
51
59
|
// 主连接登记(备份 serialize 用;见 backup-registry 说明)
|
|
52
60
|
backupRegistry.register(DB_PATH, db)
|
|
61
|
+
// WAL:认证读路径不再与写互斥(rollback 模式每请求写锁+fsync 串行化全部 API)
|
|
62
|
+
db.exec('PRAGMA journal_mode = WAL')
|
|
63
|
+
db.exec('PRAGMA synchronous = NORMAL')
|
|
53
64
|
db.exec('PRAGMA busy_timeout = 5000')
|
|
54
65
|
db.exec(SCHEMA_SQL)
|
|
55
66
|
migrateSchema(db)
|
|
@@ -69,6 +80,8 @@ function migrateSchema(d: DatabaseSync): void {
|
|
|
69
80
|
if (!cols.some(c => c.name === 'expires_at')) {
|
|
70
81
|
d.exec('ALTER TABLE user_tokens ADD COLUMN expires_at TEXT')
|
|
71
82
|
}
|
|
83
|
+
// 安全迁移:清空存量明文 token——库中只保留哈希,备份/文件拷贝不再等于凭据泄漏
|
|
84
|
+
d.exec('UPDATE user_tokens SET token_plain = NULL WHERE token_plain IS NOT NULL')
|
|
72
85
|
// 存量 token 宽限 30 天(从部署时刻起算,避免升级即全员掉线)
|
|
73
86
|
d.prepare('UPDATE user_tokens SET expires_at = ? WHERE expires_at IS NULL').run(isoInDays(TOKEN_TTL_DAYS))
|
|
74
87
|
}
|
|
@@ -168,7 +181,7 @@ function hashToken(token: string): string {
|
|
|
168
181
|
return createHash('sha256').update(token).digest('hex')
|
|
169
182
|
}
|
|
170
183
|
|
|
171
|
-
/** 签发新 token
|
|
184
|
+
/** 签发新 token:明文仅此一次返回,库中只存 SHA-256 哈希(0.7.10 起不再存档明文) */
|
|
172
185
|
function issueToken(userId: string, label: string): { raw: string, row: UserToken } {
|
|
173
186
|
const raw = `ut-${randomUUID().replace(/-/g, '')}`
|
|
174
187
|
const hash = hashToken(raw)
|
|
@@ -179,14 +192,18 @@ function issueToken(userId: string, label: string): { raw: string, row: UserToke
|
|
|
179
192
|
createdAt: now(),
|
|
180
193
|
lastUsedAt: null,
|
|
181
194
|
preview: maskPreview(raw),
|
|
182
|
-
hasPlain:
|
|
195
|
+
hasPlain: false,
|
|
183
196
|
}
|
|
184
197
|
const d = getDb()
|
|
185
|
-
d.prepare('INSERT INTO user_tokens (id, user_id, label, token_hash, token_plain, created_at, expires_at) VALUES (?, ?, ?, ?,
|
|
186
|
-
.run(row.id, userId, label, hash,
|
|
198
|
+
d.prepare('INSERT INTO user_tokens (id, user_id, label, token_hash, token_plain, created_at, expires_at) VALUES (?, ?, ?, ?, NULL, ?, ?)')
|
|
199
|
+
.run(row.id, userId, label, hash, row.createdAt, isoInDays(TOKEN_TTL_DAYS))
|
|
187
200
|
return { raw, row }
|
|
188
201
|
}
|
|
189
202
|
|
|
203
|
+
/** last_used_at 写节流:每 tokenId 60s 最多落库一次(高频认证路径不再逐请求写锁) */
|
|
204
|
+
const lastUsedSeen = new Map<string, number>()
|
|
205
|
+
const LAST_USED_THROTTLE_MS = 60_000
|
|
206
|
+
|
|
190
207
|
/** 按 token 明文查用户(命中且未过期则刷新 last_used_at);无效/已过期返回 null。tokenId 供前端识别当前会话 token。 */
|
|
191
208
|
export function findByToken(token: string): (User & { tokenId: string }) | null {
|
|
192
209
|
const d = getDb()
|
|
@@ -201,7 +218,11 @@ WHERE t.token_hash = ?`,
|
|
|
201
218
|
if (row.expiresAt && Date.parse(row.expiresAt) < Date.now()) return null
|
|
202
219
|
// 禁用账号即时失效(此前存量 token 在禁用后最长 30 天仍可用)
|
|
203
220
|
if (row.status && row.status !== 'active') return null
|
|
204
|
-
|
|
221
|
+
const seenAt = lastUsedSeen.get(row.tokenId) ?? 0
|
|
222
|
+
if (Date.now() - seenAt >= LAST_USED_THROTTLE_MS) {
|
|
223
|
+
lastUsedSeen.set(row.tokenId, Date.now())
|
|
224
|
+
d.prepare('UPDATE user_tokens SET last_used_at = ? WHERE token_hash = ?').run(now(), hash)
|
|
225
|
+
}
|
|
205
226
|
return row
|
|
206
227
|
}
|
|
207
228
|
|
|
@@ -233,6 +254,19 @@ export const userRepository = {
|
|
|
233
254
|
return { items: rows.map(toUser), total, page, pageSize }
|
|
234
255
|
},
|
|
235
256
|
|
|
257
|
+
/** 全量用户(不分页;管理面授权矩阵用,避免分页截断) */
|
|
258
|
+
listAll(): User[] {
|
|
259
|
+
const d = getDb()
|
|
260
|
+
const rows = d.prepare('SELECT id, name, email, role, status, created_at AS createdAt FROM users ORDER BY created_at DESC').all() as Array<Record<string, unknown>>
|
|
261
|
+
return rows.map(toUser)
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
/** 全部产线授权(单查询;管理面按 userId 分组,替代逐用户 N+1) */
|
|
265
|
+
allGrants(): Array<{ userId: string, lineId: string, mode: string, grantedBy: string | null, grantedAt: string }> {
|
|
266
|
+
const d = getDb()
|
|
267
|
+
return d.prepare('SELECT user_id AS userId, line_id AS lineId, mode, granted_by AS grantedBy, granted_at AS grantedAt FROM user_line_grants').all() as Array<{ userId: string, lineId: string, mode: string, grantedBy: string | null, grantedAt: string }>
|
|
268
|
+
},
|
|
269
|
+
|
|
236
270
|
findById(id: string): User | undefined {
|
|
237
271
|
const d = getDb()
|
|
238
272
|
const row = d.prepare('SELECT id, name, email, role, status, created_at AS createdAt FROM users WHERE id = ?').get(id) as Record<string, unknown> | undefined
|
|
@@ -254,10 +288,37 @@ export const userRepository = {
|
|
|
254
288
|
/** 是否存在活跃管理员(初始化判定:false → 系统处于首启注册模式,首个注册账号将成为管理员) */
|
|
255
289
|
hasActiveAdmin(): boolean {
|
|
256
290
|
const d = getDb()
|
|
257
|
-
const { n } = d.prepare(
|
|
291
|
+
const { n } = d.prepare('SELECT COUNT(*) AS n FROM users WHERE role = \'admin\' AND status = \'active\'').get() as { n: number }
|
|
258
292
|
return n > 0
|
|
259
293
|
},
|
|
260
294
|
|
|
295
|
+
// ===== 产线授权(user_line_grants;admin/editor 不查此表,全量全权)=====
|
|
296
|
+
|
|
297
|
+
/** 某用户全部产线授权 */
|
|
298
|
+
listGrants(userId: string): Array<{ lineId: string, mode: string, grantedBy: string | null, grantedAt: string }> {
|
|
299
|
+
const d = getDb()
|
|
300
|
+
return d.prepare('SELECT line_id AS lineId, mode, granted_by AS grantedBy, granted_at AS grantedAt FROM user_line_grants WHERE user_id = ?').all(userId) as Array<{ lineId: string, mode: string, grantedBy: string | null, grantedAt: string }>
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
/** 单条授权(mode 非 readonly/operate → 撤销);返回是否发生变化 */
|
|
304
|
+
setGrant(userId: string, lineId: string, mode: string | null, grantedBy: string | null): boolean {
|
|
305
|
+
const d = getDb()
|
|
306
|
+
if (mode !== 'readonly' && mode !== 'operate') {
|
|
307
|
+
return d.prepare('DELETE FROM user_line_grants WHERE user_id = ? AND line_id = ?').run(userId, lineId).changes > 0
|
|
308
|
+
}
|
|
309
|
+
d.prepare(`INSERT INTO user_line_grants (user_id, line_id, mode, granted_by, granted_at) VALUES (?, ?, ?, ?, ?)
|
|
310
|
+
ON CONFLICT(user_id, line_id) DO UPDATE SET mode = excluded.mode, granted_by = excluded.granted_by, granted_at = excluded.granted_at`)
|
|
311
|
+
.run(userId, lineId, mode, grantedBy, now())
|
|
312
|
+
return true
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
/** 用户 → 产线访问映射(lineId → 'readonly'|'operate');无记录 = 无权 */
|
|
316
|
+
lineAccessMap(userId: string): Map<string, string> {
|
|
317
|
+
const d = getDb()
|
|
318
|
+
const rows = d.prepare('SELECT line_id AS lineId, mode FROM user_line_grants WHERE user_id = ?').all(userId) as Array<{ lineId: string, mode: string }>
|
|
319
|
+
return new Map(rows.map(r => [r.lineId, r.mode]))
|
|
320
|
+
},
|
|
321
|
+
|
|
261
322
|
/** 内部:取密码哈希(仅认证路径使用,不参与领域对象外泄) */
|
|
262
323
|
getPasswordHash(email: string): { id: string, hash: string } | null {
|
|
263
324
|
const d = getDb()
|
|
@@ -280,6 +341,25 @@ export const userRepository = {
|
|
|
280
341
|
return user
|
|
281
342
|
},
|
|
282
343
|
|
|
344
|
+
/** 原子注册(IMMEDIATE 事务内判定管理员空缺):并发注册不会产生第二个 bootstrap admin */
|
|
345
|
+
createWithRoleBootstrap(input: UserCreate & { password: string }): { user: User, bootstrap: boolean } {
|
|
346
|
+
const d = getDb()
|
|
347
|
+
d.exec('BEGIN IMMEDIATE')
|
|
348
|
+
try {
|
|
349
|
+
const bootstrap = !this.hasActiveAdmin()
|
|
350
|
+
const user = this.create({ ...input, role: bootstrap ? 'admin' : input.role })
|
|
351
|
+
d.exec('COMMIT')
|
|
352
|
+
return { user, bootstrap }
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
try {
|
|
356
|
+
d.exec('ROLLBACK')
|
|
357
|
+
}
|
|
358
|
+
catch { /* 事务已自滚 */ }
|
|
359
|
+
throw err
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
|
|
283
363
|
update(id: string, input: UserUpdate): User | undefined {
|
|
284
364
|
const d = getDb()
|
|
285
365
|
const current = this.findById(id)
|
|
@@ -84,7 +84,8 @@ export const userService = {
|
|
|
84
84
|
// ===== 认证(公开端点)=====
|
|
85
85
|
|
|
86
86
|
/** 注册:创建账号 + 签发首个 token(邮箱/用户名占用 → 409)。
|
|
87
|
-
*
|
|
87
|
+
* 首启初始化:原子事务内判定「尚无活跃管理员」→ 首个注册账号授予 admin
|
|
88
|
+
* (并发注册不会产生第二个 bootstrap admin) */
|
|
88
89
|
register(input: UserRegister): AuthResult {
|
|
89
90
|
if (userRepository.findByEmail(input.email)) {
|
|
90
91
|
throw new AppError(409, ErrorCodes.CONFLICT, '邮箱已被注册')
|
|
@@ -92,11 +93,12 @@ export const userService = {
|
|
|
92
93
|
if (userRepository.findByName(input.name)) {
|
|
93
94
|
throw new AppError(409, 'USER_EXISTS', `用户名已存在: ${input.name}`)
|
|
94
95
|
}
|
|
95
|
-
const needsBootstrap =
|
|
96
|
+
const { user, bootstrap: needsBootstrap } = userRepository.createWithRoleBootstrap({
|
|
97
|
+
...input, role: 'user', status: 'active',
|
|
98
|
+
})
|
|
96
99
|
if (needsBootstrap) {
|
|
97
100
|
console.log(`[users] 初始化:尚无管理员账号,首个注册账号授予管理员角色(${input.email})`)
|
|
98
101
|
}
|
|
99
|
-
const user = userRepository.create({ ...input, role: needsBootstrap ? 'admin' : 'user', status: 'active' })
|
|
100
102
|
const { raw } = userRepository.createToken(user.id, needsBootstrap ? 'bootstrap-admin' : 'default')
|
|
101
103
|
return { user: this.publicProfile(user), token: raw }
|
|
102
104
|
},
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* DaqQueuePort 工厂 —— 配置驱动(DAQ_MQTT_URL 由 infra 提供),缺省进程内 mock 队列。
|
|
3
3
|
* 单例 globalThis;rebuildDaqQueue() 支持重连时切回真实 MQTT。
|
|
4
4
|
*/
|
|
5
|
-
import { createLogger } from '../../logger'
|
|
5
|
+
import { createLogger } from '../../logger'
|
|
6
6
|
import { InProcQueueAdapter } from './inproc.adapter'
|
|
7
7
|
import { MqttQueueAdapter } from './mqtt.adapter'
|
|
8
8
|
import type { DaqQueuePort } from './queue-port'
|
|
9
9
|
|
|
10
|
-
const log = createLogger('daq.queue')
|
|
11
|
-
|
|
10
|
+
const log = createLogger('daq.queue')
|
|
11
|
+
|
|
12
12
|
const g = globalThis as typeof globalThis & { __daqQueue?: DaqQueuePort }
|
|
13
13
|
|
|
14
14
|
export async function getDaqQueue(): Promise<DaqQueuePort> {
|
|
@@ -22,6 +22,8 @@ export async function getDaqQueue(): Promise<DaqQueuePort> {
|
|
|
22
22
|
|
|
23
23
|
/** 重连/初始装配:按 infra 判定结果(重新)构建 MQTT 或进程内队列 */
|
|
24
24
|
export async function rebuildDaqQueue(online: boolean, url?: string | null): Promise<DaqQueuePort> {
|
|
25
|
+
// 换装前释放旧 adapter(mqtt 连接 / inproc 泵),防重建泄漏
|
|
26
|
+
await g.__daqQueue?.close?.()
|
|
25
27
|
if (!online || !url) {
|
|
26
28
|
if (g.__daqQueue?.backend !== 'inproc') {
|
|
27
29
|
g.__daqQueue = new InProcQueueAdapter()
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* 与 MQTT 版同契约:生产端 publish 即刻入队不阻塞采集;消费泵按序拉取,
|
|
4
4
|
* 拥塞时丢最旧并计数(暴露给 meta,诚实可见)。
|
|
5
5
|
*/
|
|
6
|
-
import { createLogger } from '../../logger'
|
|
6
|
+
import { createLogger } from '../../logger'
|
|
7
7
|
import type { DaqConsumer, DaqQueuePort, DaqSampleEnvelope } from './queue-port'
|
|
8
8
|
|
|
9
|
-
const log = createLogger('daq.queue')
|
|
10
|
-
|
|
9
|
+
const log = createLogger('daq.queue')
|
|
10
|
+
|
|
11
11
|
const QUEUE_CAP = 10_000
|
|
12
12
|
/** 消费泵节拍(ms):攒批交给下游(TSDB 批量写) */
|
|
13
13
|
const PUMP_INTERVAL = 250
|
|
@@ -45,6 +45,15 @@ export class InProcQueueAdapter implements DaqQueuePort {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/** 释放消费泵(rebuild 换装前调用,防定时器泄漏) */
|
|
49
|
+
close(): void {
|
|
50
|
+
if (this.pump) {
|
|
51
|
+
clearInterval(this.pump)
|
|
52
|
+
this.pump = null
|
|
53
|
+
}
|
|
54
|
+
this.consumers.clear()
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
private drain(): void {
|
|
49
58
|
if (this.queue.length === 0 || this.consumers.size === 0) return
|
|
50
59
|
const batch = this.queue.splice(0, this.queue.length)
|
|
@@ -107,5 +107,18 @@ export class MqttQueueAdapter implements DaqQueuePort {
|
|
|
107
107
|
return () => {
|
|
108
108
|
this.consumers.delete(fn)
|
|
109
109
|
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** 断开 MQTT 连接并清理订阅(rebuild 换装前调用,防 socket/keepalive 泄漏) */
|
|
113
|
+
async close(): Promise<void> {
|
|
114
|
+
this.consumers.clear()
|
|
115
|
+
const c = this.client
|
|
116
|
+
this.client = null
|
|
117
|
+
if (c) {
|
|
118
|
+
try {
|
|
119
|
+
await new Promise<void>(r => c.end(false, () => r()))
|
|
120
|
+
}
|
|
121
|
+
catch { /* 已断连等场景:尽力而为 */ }
|
|
122
|
+
}
|
|
110
123
|
}
|
|
111
124
|
}
|
|
@@ -289,6 +289,7 @@ class DaqController {
|
|
|
289
289
|
value: node.value ?? env.value,
|
|
290
290
|
state: node.state,
|
|
291
291
|
at: env.at,
|
|
292
|
+
lineId: node.lineId ?? null,
|
|
292
293
|
} satisfies AepDaqReading
|
|
293
294
|
this.broadcast?.('daq.reading', reading)
|
|
294
295
|
// 插件钩子:下发级采样观察(与 WS daq.reading 同点同节拍;宿主未装载时零开销 no-op)
|
|
@@ -373,6 +374,7 @@ class DaqController {
|
|
|
373
374
|
templateRef: node.templateRef,
|
|
374
375
|
kind: f.kind,
|
|
375
376
|
at: env.at,
|
|
377
|
+
lineId: node.lineId ?? null,
|
|
376
378
|
preview: f.kind === 'vector' ? DaqController.previewOf(f.points ?? [], FRAME_PREVIEW_POINTS) : undefined,
|
|
377
379
|
metrics,
|
|
378
380
|
thumbUrl: f.kind === 'image' && f.objectKey
|
|
@@ -619,6 +621,9 @@ class DaqController {
|
|
|
619
621
|
}
|
|
620
622
|
finally {
|
|
621
623
|
this.tsdbWriting = false
|
|
624
|
+
// 尾批自愈:flush 期间新样本/帧到达时 schedule 被跳过(tsdbWriting 守卫),
|
|
625
|
+
// 若此处不留 timer,停线后的残余批次将无定时器可触发,驻留内存直至进程重启
|
|
626
|
+
if (this.tsdbBuffer.length > 0 || this.frameBuffer.length > 0) this.scheduleTsdbFlush()
|
|
622
627
|
}
|
|
623
628
|
}
|
|
624
629
|
|
|
@@ -626,13 +631,25 @@ class DaqController {
|
|
|
626
631
|
* 状态随行:节点 alarm 派生自用户设置的量程/预警带(数据驱动),透传给孪生而非让孪生按硬编码阈值猜 */
|
|
627
632
|
private pendingBackfill = new Map<string, Record<string, number | string | boolean>>()
|
|
628
633
|
|
|
634
|
+
/** 同绑定 siblings 缓存(1s TTL):回写热路径不再逐样本全量 scan,O(N²)→O(N)/周期 */
|
|
635
|
+
private siblingsCache = new Map<string, { at: number, list: DaqNode[] }>()
|
|
636
|
+
|
|
637
|
+
private siblingsOf(bindingId: string): DaqNode[] {
|
|
638
|
+
const hit = this.siblingsCache.get(bindingId)
|
|
639
|
+
if (hit && Date.now() - hit.at < 1000) return hit.list
|
|
640
|
+
const list = this.repo.all().filter(n => n.deviceBindingId === bindingId)
|
|
641
|
+
if (this.siblingsCache.size > 500) this.siblingsCache.clear()
|
|
642
|
+
this.siblingsCache.set(bindingId, { at: Date.now(), list })
|
|
643
|
+
return list
|
|
644
|
+
}
|
|
645
|
+
|
|
629
646
|
private writeBackTelemetry(node: DaqNode): void {
|
|
630
647
|
if (!node.deviceBindingId || node.value == null) return
|
|
631
648
|
const host = getDaqHostPorts()
|
|
632
649
|
if (!host) return // 端口未装配(边缘独立/装配前):不攒积压,直接跳过回写
|
|
633
650
|
const key = findDaqTemplate(node.templateKey)?.telemetryKey ?? node.templateKey
|
|
634
651
|
// 同设备多节点绑定:取最严重节点态(alarm > warn > ok/offline),避免"最近写者定态"抖动
|
|
635
|
-
const siblings = this.
|
|
652
|
+
const siblings = this.siblingsOf(node.deviceBindingId)
|
|
636
653
|
const worst = siblings.some(n => n.state === 'alarm')
|
|
637
654
|
? 'alarm'
|
|
638
655
|
: siblings.some(n => n.state === 'warn') ? 'warn' : 'ok'
|
|
@@ -103,6 +103,12 @@ export function createAlarmEventRepo(db: DatabaseSync) {
|
|
|
103
103
|
)
|
|
104
104
|
|
|
105
105
|
return {
|
|
106
|
+
/** 按 id 取报警关联节点(产线权限判定用);不存在返回 undefined */
|
|
107
|
+
nodeIdById(id) {
|
|
108
|
+
const r = db.prepare('SELECT node_id FROM alarm_events WHERE id = ?').get(id)
|
|
109
|
+
return r?.node_id
|
|
110
|
+
},
|
|
111
|
+
|
|
106
112
|
/** 报警产生(同 node+metric 未确认报警幂等去重,防止高频越限刷表) */
|
|
107
113
|
raise(a: {
|
|
108
114
|
id: string
|