@sleep2agi/agent-network-dashboard 0.6.3-preview.56 → 0.6.3-preview.57
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/.next/BUILD_COMMIT +1 -1
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +9 -0
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +145 -95
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +75 -19
- package/.next/required-server-files.js +4 -4
- package/.next/required-server-files.json +4 -4
- package/.next/routes-manifest.json +63 -0
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +14 -14
- package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/admin/page.js.nft.json +1 -1
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +16 -16
- package/.next/server/app/admin.segments/_full.segment.rsc +16 -16
- package/.next/server/app/admin.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/api/anet/host-supervisors/route.js.nft.json +1 -1
- package/.next/server/app/api/anet/node-config/route.js +1 -1
- package/.next/server/app/api/anet/node-config/route.js.nft.json +1 -1
- package/.next/server/app/api/hub/people/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/people/route/build-manifest.json +12 -0
- package/.next/server/app/api/hub/people/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/people/route.js +7 -0
- package/.next/server/app/api/hub/people/route.js.map +5 -0
- package/.next/server/app/api/hub/people/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/people/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route/build-manifest.json +12 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route.js +7 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route.js.map +5 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/requirements/[id]/checklist/[itemId]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route/build-manifest.json +12 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route.js +7 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route.js.map +5 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/requirements/[id]/comments/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/requirements/[id]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/requirements/[id]/route/build-manifest.json +12 -0
- package/.next/server/app/api/hub/requirements/[id]/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/requirements/[id]/route.js +7 -0
- package/.next/server/app/api/hub/requirements/[id]/route.js.map +5 -0
- package/.next/server/app/api/hub/requirements/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/requirements/[id]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/requirements/events/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/requirements/events/route/build-manifest.json +12 -0
- package/.next/server/app/api/hub/requirements/events/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/requirements/events/route.js +7 -0
- package/.next/server/app/api/hub/requirements/events/route.js.map +5 -0
- package/.next/server/app/api/hub/requirements/events/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/requirements/events/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/hub/requirements/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/requirements/route/build-manifest.json +12 -0
- package/.next/server/app/api/hub/requirements/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/requirements/route.js +7 -0
- package/.next/server/app/api/hub/requirements/route.js.map +5 -0
- package/.next/server/app/api/hub/requirements/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/requirements/route_client-reference-manifest.js +3 -0
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +16 -16
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/index.segments/_full.segment.rsc +16 -16
- package/.next/server/app/index.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +16 -16
- package/.next/server/app/login.segments/_full.segment.rsc +16 -16
- package/.next/server/app/login.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/logs/page.js.nft.json +1 -1
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +16 -16
- package/.next/server/app/logs.segments/_full.segment.rsc +16 -16
- package/.next/server/app/logs.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/messages/page.js.nft.json +1 -1
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +16 -16
- package/.next/server/app/messages.segments/_full.segment.rsc +16 -16
- package/.next/server/app/messages.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/node/page.js.nft.json +1 -1
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +16 -16
- package/.next/server/app/node.segments/_full.segment.rsc +16 -16
- package/.next/server/app/node.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/nodes/[alias]/page.js.nft.json +1 -1
- package/.next/server/app/nodes/[alias]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes/page.js.nft.json +1 -1
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +16 -16
- package/.next/server/app/nodes.segments/_full.segment.rsc +16 -16
- package/.next/server/app/nodes.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/org/page/app-paths-manifest.json +3 -0
- package/.next/server/app/org/page/build-manifest.json +20 -0
- package/.next/server/app/org/page/next-font-manifest.json +11 -0
- package/.next/server/app/org/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/org/page/server-reference-manifest.json +4 -0
- package/.next/server/app/org/page.js +13 -0
- package/.next/server/app/org/page.js.map +5 -0
- package/.next/server/app/org/page.js.nft.json +1 -0
- package/.next/server/app/org/page_client-reference-manifest.js +3 -0
- package/.next/server/app/org.html +12 -0
- package/.next/server/app/org.meta +26 -0
- package/.next/server/app/org.rsc +27 -0
- package/.next/server/app/org.segments/_full.segment.rsc +27 -0
- package/.next/server/app/org.segments/_tree.segment.rsc +5 -0
- package/.next/server/app/org.segments/org/__PAGE__.segment.rsc +32 -0
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/providers/page.js.nft.json +1 -1
- package/.next/server/app/providers/page_client-reference-manifest.js +1 -1
- package/.next/server/app/providers.html +2 -2
- package/.next/server/app/providers.rsc +16 -16
- package/.next/server/app/providers.segments/_full.segment.rsc +16 -16
- package/.next/server/app/providers.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/providers.segments/providers/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/requirements/[id]/page/app-paths-manifest.json +3 -0
- package/.next/server/app/requirements/[id]/page/build-manifest.json +20 -0
- package/.next/server/app/requirements/[id]/page/next-font-manifest.json +11 -0
- package/.next/server/app/requirements/[id]/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/requirements/[id]/page/server-reference-manifest.json +4 -0
- package/.next/server/app/requirements/[id]/page.js +13 -0
- package/.next/server/app/requirements/[id]/page.js.map +5 -0
- package/.next/server/app/requirements/[id]/page.js.nft.json +1 -0
- package/.next/server/app/requirements/[id]/page_client-reference-manifest.js +3 -0
- package/.next/server/app/requirements/page/app-paths-manifest.json +3 -0
- package/.next/server/app/requirements/page/build-manifest.json +20 -0
- package/.next/server/app/requirements/page/next-font-manifest.json +11 -0
- package/.next/server/app/requirements/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/requirements/page/server-reference-manifest.json +4 -0
- package/.next/server/app/requirements/page.js +13 -0
- package/.next/server/app/requirements/page.js.map +5 -0
- package/.next/server/app/requirements/page.js.nft.json +1 -0
- package/.next/server/app/requirements/page_client-reference-manifest.js +3 -0
- package/.next/server/app/requirements.html +12 -0
- package/.next/server/app/requirements.meta +26 -0
- package/.next/server/app/requirements.rsc +27 -0
- package/.next/server/app/requirements.segments/_full.segment.rsc +27 -0
- package/.next/server/app/requirements.segments/_tree.segment.rsc +5 -0
- package/.next/server/app/requirements.segments/requirements/__PAGE__.segment.rsc +32 -0
- package/.next/server/app/scheduled-tasks/page.js.nft.json +1 -1
- package/.next/server/app/scheduled-tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/scheduled-tasks.html +2 -2
- package/.next/server/app/scheduled-tasks.rsc +16 -16
- package/.next/server/app/scheduled-tasks.segments/_full.segment.rsc +16 -16
- package/.next/server/app/scheduled-tasks.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/scheduled-tasks.segments/scheduled-tasks/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/server-logs/page.js.nft.json +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +16 -16
- package/.next/server/app/server-logs.segments/_full.segment.rsc +16 -16
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/servers/page.js.nft.json +1 -1
- package/.next/server/app/servers/page_client-reference-manifest.js +1 -1
- package/.next/server/app/servers.html +2 -2
- package/.next/server/app/servers.rsc +16 -16
- package/.next/server/app/servers.segments/_full.segment.rsc +16 -16
- package/.next/server/app/servers.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/servers.segments/servers/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/settings/networks/page.js.nft.json +1 -1
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +16 -16
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +16 -16
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +16 -16
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +16 -16
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +16 -16
- package/.next/server/app/settings.segments/_full.segment.rsc +16 -16
- package/.next/server/app/settings.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/skillhub/page.js.nft.json +1 -1
- package/.next/server/app/skillhub/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skillhub.html +2 -2
- package/.next/server/app/skillhub.rsc +16 -16
- package/.next/server/app/skillhub.segments/_full.segment.rsc +16 -16
- package/.next/server/app/skillhub.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/skillhub.segments/skillhub/__PAGE__.segment.rsc +15 -15
- package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page.js.nft.json +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +16 -16
- package/.next/server/app/tasks.segments/_full.segment.rsc +16 -16
- package/.next/server/app/tasks.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +15 -15
- package/.next/server/app-paths-manifest.json +9 -0
- package/.next/server/chunks/1oeh_server_app_api_hub_requirements_[id]_checklist_[itemId]_route_actions_05mpe5a.js +3 -0
- package/.next/server/chunks/1oeh_server_app_api_hub_requirements_[id]_checklist_[itemId]_route_actions_05mpe5a.js.map +1 -0
- package/.next/server/chunks/1oeh_server_app_api_hub_requirements_[id]_comments_route_actions_1lv4qr1.js +3 -0
- package/.next/server/chunks/1oeh_server_app_api_hub_requirements_[id]_comments_route_actions_1lv4qr1.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0-wvy_a._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0-wvy_a._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__053z4wp._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__053z4wp._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0if0bw1._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0if0bw1._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0liwkmx._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0liwkmx._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__0q9xwca._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0q9xwca._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1941b2h._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1941b2h._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1_rzyvn._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1_rzyvn._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1vua9gf._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1vua9gf._.js.map +1 -0
- package/.next/server/chunks/_05lpz54._.js +1 -1
- package/.next/server/chunks/_05lpz54._.js.map +1 -1
- package/.next/server/chunks/_next-internal_server_app_api_hub_people_route_actions_01pw78e.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_people_route_actions_01pw78e.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_requirements_[id]_route_actions_1jkq5c6.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_requirements_[id]_route_actions_1jkq5c6.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_requirements_events_route_actions_1ypnpu5.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_requirements_events_route_actions_1ypnpu5.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_requirements_route_actions_1lyeno6.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_hub_requirements_route_actions_1lyeno6.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0-94ipy._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0-94ipy._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09n7eih._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09n7eih._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ol09h3._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0ol09h3._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__14k36ti._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__14k36ti._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1bn1jjm._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1bn1jjm._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1ovdbox._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1ovdbox._.js.map +1 -1
- package/.next/server/chunks/ssr/_0q4m25o._.js +0 -0
- package/.next/server/chunks/ssr/_0q4m25o._.js.map +1 -1
- package/.next/server/chunks/ssr/_1z1o6o3._.js +0 -0
- package/.next/server/chunks/ssr/_1z1o6o3._.js.map +1 -1
- package/.next/server/chunks/ssr/_next-internal_server_app_org_page_actions_0hbcef1.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_org_page_actions_0hbcef1.js.map +1 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_requirements_[id]_page_actions_1wjoy4l.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_requirements_[id]_page_actions_1wjoy4l.js.map +1 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_requirements_page_actions_0x9m0gy.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_requirements_page_actions_0x9m0gy.js.map +1 -0
- package/.next/server/chunks/ssr/app_05mfyco._.js +3 -0
- package/.next/server/chunks/ssr/app_05mfyco._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_0_s8u96._.js → app_07bzc6w._.js} +1 -1
- package/.next/server/chunks/ssr/app_099f0wg._.js +3 -0
- package/.next/server/chunks/ssr/app_099f0wg._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_1oxcq68._.js → app_0g7oz9w._.js} +1 -1
- package/.next/server/chunks/ssr/app_0iz553k._.js +1 -1
- package/.next/server/chunks/ssr/app_0iz553k._.js.map +1 -1
- package/.next/server/chunks/ssr/app_0los-eu._.js +1 -1
- package/.next/server/chunks/ssr/app_0los-eu._.js.map +1 -1
- package/.next/server/chunks/ssr/{app_0x7s72b._.js → app_0tt2ueo._.js} +1 -1
- package/.next/server/chunks/ssr/{app_081zy6c._.js → app_0ugqkd7._.js} +1 -1
- package/.next/server/chunks/ssr/app_1auk3il._.js +11 -0
- package/.next/server/chunks/ssr/app_1auk3il._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_0o4bxq0._.js → app_1e91uc-._.js} +1 -1
- package/.next/server/chunks/ssr/{app_1psh956._.js → app_1f96aq_._.js} +1 -1
- package/.next/server/chunks/ssr/app_1rma_8a._.js +11 -0
- package/.next/server/chunks/ssr/app_1rma_8a._.js.map +1 -0
- package/.next/server/chunks/ssr/{app_0_dhiwi._.js → app_1ua57bx._.js} +1 -1
- package/.next/server/chunks/ssr/app_components_04a31va._.js +1 -1
- package/.next/server/chunks/ssr/app_components_04a31va._.js.map +1 -1
- package/.next/server/chunks/ssr/{app_lib_10o69j_._.js → app_lib_20-pe_0._.js} +2 -2
- package/.next/server/chunks/ssr/{app_lib_10o69j_._.js.map → app_lib_20-pe_0._.js.map} +1 -1
- package/.next/server/chunks/ssr/app_nodes_NodesView_tsx_1w6_d8p._.js +2 -2
- package/.next/server/chunks/ssr/app_nodes_NodesView_tsx_1w6_d8p._.js.map +1 -1
- package/.next/server/chunks/ssr/app_page_tsx_0pxmutw._.js +1 -1
- package/.next/server/chunks/ssr/app_page_tsx_0pxmutw._.js.map +1 -1
- package/.next/server/chunks/ssr/app_scheduled-tasks_page_tsx_0xs70_6._.js +1 -1
- package/.next/server/chunks/ssr/app_scheduled-tasks_page_tsx_0xs70_6._.js.map +1 -1
- package/.next/server/chunks/ssr/app_tasks_TasksView_tsx_068vqml._.js +1 -1
- package/.next/server/chunks/ssr/app_tasks_TasksView_tsx_068vqml._.js.map +1 -1
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/middleware.js.nft.json +1 -1
- package/.next/server/next-font-manifest.js +1 -1
- package/.next/server/next-font-manifest.json +12 -0
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/prefetch-hints.json +28 -0
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/{trj9RsCWuEDMfq9BuoKfl → _HZB6K84VKNaxf1K7dqqj}/_clientMiddlewareManifest.js +4 -0
- package/.next/static/chunks/{27b9kqyo7bmdr.js → 08-obrj2goweb.js} +2 -2
- package/.next/static/chunks/{0agh8mvmpke4j.js → 0cuzbmf4k1kgl.js} +1 -1
- package/.next/static/chunks/0fih4pzed1syn.js +9 -0
- package/.next/static/chunks/0iiu4-g5k8jcq.js +1 -0
- package/.next/static/chunks/{37booeyruo9_l.js → 0iz44n632kw4w.js} +1 -1
- package/.next/static/chunks/0jt-1caejz1jv.js +1 -0
- package/.next/static/chunks/0k-4980o5t7_r.css +1 -0
- package/.next/static/chunks/114pblaedlrqs.js +1 -0
- package/.next/static/chunks/1tcaw8g6u6o-4.js +1 -0
- package/.next/static/chunks/1v5-qgib9884o.js +0 -0
- package/.next/static/chunks/{02303d1rbqx74.js → 2-x9r-1t3c1mn.js} +1 -1
- package/.next/static/chunks/{28o3ssg0_q2n-.js → 21djd6ixldlx0.js} +1 -1
- package/.next/static/chunks/2anlzel60my8y.js +2 -0
- package/.next/static/chunks/{3jxk7q1jxyvol.js → 2juzvtg9ne4yt.js} +1 -1
- package/.next/static/chunks/3cb3_kcec7bms.js +1 -0
- package/.next/static/chunks/{233p45nuh4m5b.css → 3d-1vk5hzu5rq.css} +2 -2
- package/.next/static/chunks/3shtxab8cmux9.js +1 -0
- package/.next/static/chunks/3u059pjgl4gcw.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +11 -2
- package/.next/types/validator.ts +81 -0
- package/.vercel/.env.development.local +2 -0
- package/.vercel/.env.production.local +25 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/output/builds.json +23 -0
- package/.vercel/output/config.json +489 -0
- package/.vercel/output/diagnostics/build-diagnostics.json +6 -0
- package/.vercel/output/diagnostics/cli_traces.json +1 -0
- package/.vercel/output/diagnostics/framework.json +1 -0
- package/.vercel/output/diagnostics/route-bundle-stats.json +245 -0
- package/.vercel/output/diagnostics/trace +2 -0
- package/.vercel/output/diagnostics/trace-build +1 -0
- package/.vercel/output/diagnostics/turbopack +0 -0
- package/.vercel/output/functions/_global-error.prerender-config.json +38 -0
- package/.vercel/output/functions/_global-error.prerender-fallback.html +1 -0
- package/.vercel/output/functions/_global-error.rsc.func/.next/routes-manifest.json +1 -0
- package/.vercel/output/functions/_global-error.rsc.func/.next/server/app-paths-manifest.json +1 -0
- package/.vercel/output/functions/_global-error.rsc.func/.next/server/pages-manifest.json +1 -0
- package/.vercel/output/functions/_global-error.rsc.func/.vc-config.json +807 -0
- package/.vercel/output/functions/_global-error.rsc.func/___next_launcher.cjs +68 -0
- package/.vercel/output/functions/_global-error.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/_global-error.rsc.prerender-fallback.rsc +15 -0
- package/.vercel/output/functions/_global-error.segments/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_global-error.segments/__PAGE__.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/_global-error.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_global-error.segments/_full.segment.rsc.prerender-fallback.rsc +15 -0
- package/.vercel/output/functions/_global-error.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_global-error.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/_global-error.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_global-error.segments/_index.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/_global-error.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_global-error.segments/_tree.segment.rsc.prerender-fallback.rsc +1 -0
- package/.vercel/output/functions/_middleware.func/.vc-config.json +107 -0
- package/.vercel/output/functions/_middleware.func/___next_launcher.cjs +135 -0
- package/.vercel/output/functions/_not-found.prerender-config.json +38 -0
- package/.vercel/output/functions/_not-found.prerender-fallback.html +12 -0
- package/.vercel/output/functions/_not-found.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/_not-found.rsc.prerender-fallback.rsc +21 -0
- package/.vercel/output/functions/_not-found.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_not-found.segments/_full.segment.rsc.prerender-fallback.rsc +21 -0
- package/.vercel/output/functions/_not-found.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_not-found.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/_not-found.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_not-found.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/_not-found.segments/_not-found/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_not-found.segments/_not-found/__PAGE__.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/_not-found.segments/_not-found.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_not-found.segments/_not-found.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/_not-found.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/_not-found.segments/_tree.segment.rsc.prerender-fallback.rsc +3 -0
- package/.vercel/output/functions/admin.prerender-config.json +37 -0
- package/.vercel/output/functions/admin.prerender-fallback.html +12 -0
- package/.vercel/output/functions/admin.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/admin.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/admin.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/admin.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/admin.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/admin.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/admin.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/admin.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/admin.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/admin.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/admin.segments/admin/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/admin.segments/admin/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/admin.segments/admin.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/admin.segments/admin.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/api/anet/config.func/.next/routes-manifest.json +1 -0
- package/.vercel/output/functions/api/anet/config.func/.next/server/app-paths-manifest.json +1 -0
- package/.vercel/output/functions/api/anet/config.func/.next/server/pages-manifest.json +1 -0
- package/.vercel/output/functions/api/anet/config.func/.vc-config.json +818 -0
- package/.vercel/output/functions/api/anet/config.func/___next_launcher.cjs +68 -0
- package/.vercel/output/functions/index.prerender-config.json +38 -0
- package/.vercel/output/functions/index.prerender-fallback.html +12 -0
- package/.vercel/output/functions/index.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/index.rsc.prerender-fallback.rsc +25 -0
- package/.vercel/output/functions/index.segments/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/index.segments/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/index.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/index.segments/_full.segment.rsc.prerender-fallback.rsc +25 -0
- package/.vercel/output/functions/index.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/index.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/index.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/index.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/index.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/index.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/login.prerender-config.json +37 -0
- package/.vercel/output/functions/login.prerender-fallback.html +6 -0
- package/.vercel/output/functions/login.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/login.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/login.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/login.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/login.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/login.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/login.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/login.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/login.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/login.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/login.segments/login/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/login.segments/login/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/login.segments/login.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/login.segments/login.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/logs.prerender-config.json +37 -0
- package/.vercel/output/functions/logs.prerender-fallback.html +12 -0
- package/.vercel/output/functions/logs.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/logs.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/logs.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/logs.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/logs.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/logs.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/logs.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/logs.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/logs.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/logs.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/logs.segments/logs/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/logs.segments/logs/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/logs.segments/logs.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/logs.segments/logs.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/manifest.webmanifest.func/.next/routes-manifest.json +1 -0
- package/.vercel/output/functions/manifest.webmanifest.func/.next/server/app-paths-manifest.json +1 -0
- package/.vercel/output/functions/manifest.webmanifest.func/.next/server/pages-manifest.json +1 -0
- package/.vercel/output/functions/manifest.webmanifest.func/.vc-config.json +715 -0
- package/.vercel/output/functions/manifest.webmanifest.func/___next_launcher.cjs +68 -0
- package/.vercel/output/functions/manifest.webmanifest.prerender-config.json +38 -0
- package/.vercel/output/functions/manifest.webmanifest.prerender-fallback.body +1 -0
- package/.vercel/output/functions/messages.prerender-config.json +37 -0
- package/.vercel/output/functions/messages.prerender-fallback.html +12 -0
- package/.vercel/output/functions/messages.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/messages.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/messages.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/messages.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/messages.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/messages.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/messages.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/messages.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/messages.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/messages.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/messages.segments/messages/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/messages.segments/messages/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/messages.segments/messages.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/messages.segments/messages.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/node.prerender-config.json +37 -0
- package/.vercel/output/functions/node.prerender-fallback.html +12 -0
- package/.vercel/output/functions/node.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/node.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/node.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/node.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/node.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/node.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/node.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/node.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/node.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/node.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/node.segments/node/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/node.segments/node/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/node.segments/node.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/node.segments/node.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/nodes.prerender-config.json +37 -0
- package/.vercel/output/functions/nodes.prerender-fallback.html +12 -0
- package/.vercel/output/functions/nodes.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/nodes.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/nodes.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/nodes.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/nodes.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/nodes.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/nodes.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/nodes.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/nodes.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/nodes.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/nodes.segments/nodes/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/nodes.segments/nodes/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/nodes.segments/nodes.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/nodes.segments/nodes.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/server-logs.prerender-config.json +37 -0
- package/.vercel/output/functions/server-logs.prerender-fallback.html +12 -0
- package/.vercel/output/functions/server-logs.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/server-logs.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/server-logs.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/server-logs.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/server-logs.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/server-logs.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/server-logs.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/server-logs.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/server-logs.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/server-logs.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/server-logs.segments/server-logs/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/server-logs.segments/server-logs/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/server-logs.segments/server-logs.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/server-logs.segments/server-logs.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/servers.prerender-config.json +37 -0
- package/.vercel/output/functions/servers.prerender-fallback.html +12 -0
- package/.vercel/output/functions/servers.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/servers.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/servers.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/servers.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/servers.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/servers.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/servers.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/servers.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/servers.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/servers.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/servers.segments/servers/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/servers.segments/servers/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/servers.segments/servers.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/servers.segments/servers.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings/networks.prerender-config.json +37 -0
- package/.vercel/output/functions/settings/networks.prerender-fallback.html +12 -0
- package/.vercel/output/functions/settings/networks.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/settings/networks.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/settings/networks.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/settings/networks.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/settings/networks.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/settings/networks.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings/networks.segments/settings/networks/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/settings/networks/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/settings/networks.segments/settings/networks.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/settings/networks.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings/networks.segments/settings.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/networks.segments/settings.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings/tokens.prerender-config.json +37 -0
- package/.vercel/output/functions/settings/tokens.prerender-fallback.html +12 -0
- package/.vercel/output/functions/settings/tokens.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/settings/tokens.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/settings/tokens.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/settings/tokens.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/settings/tokens.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/settings/tokens.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/settings/tokens.segments/settings/tokens.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/settings/tokens.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings/tokens.segments/settings.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings/tokens.segments/settings.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings.prerender-config.json +37 -0
- package/.vercel/output/functions/settings.prerender-fallback.html +12 -0
- package/.vercel/output/functions/settings.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/settings.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/settings.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/settings.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/settings.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/settings.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/settings.segments/settings/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings.segments/settings/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/settings.segments/settings.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/settings.segments/settings.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/tasks/[id].func/.next/routes-manifest.json +1 -0
- package/.vercel/output/functions/tasks/[id].func/.next/server/app-paths-manifest.json +1 -0
- package/.vercel/output/functions/tasks/[id].func/.next/server/pages-manifest.json +1 -0
- package/.vercel/output/functions/tasks/[id].func/.vc-config.json +713 -0
- package/.vercel/output/functions/tasks/[id].func/___next_launcher.cjs +68 -0
- package/.vercel/output/functions/tasks.prerender-config.json +37 -0
- package/.vercel/output/functions/tasks.prerender-fallback.html +12 -0
- package/.vercel/output/functions/tasks.rsc.prerender-config.json +38 -0
- package/.vercel/output/functions/tasks.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/tasks.segments/_full.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/tasks.segments/_full.segment.rsc.prerender-fallback.rsc +27 -0
- package/.vercel/output/functions/tasks.segments/_head.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/tasks.segments/_head.segment.rsc.prerender-fallback.rsc +6 -0
- package/.vercel/output/functions/tasks.segments/_index.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/tasks.segments/_index.segment.rsc.prerender-fallback.rsc +10 -0
- package/.vercel/output/functions/tasks.segments/_tree.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/tasks.segments/_tree.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/functions/tasks.segments/tasks/__PAGE__.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/tasks.segments/tasks/__PAGE__.segment.rsc.prerender-fallback.rsc +9 -0
- package/.vercel/output/functions/tasks.segments/tasks.segment.rsc.prerender-config.json +28 -0
- package/.vercel/output/functions/tasks.segments/tasks.segment.rsc.prerender-fallback.rsc +5 -0
- package/.vercel/output/static/404.html +12 -0
- package/.vercel/output/static/404.rsc.json +1 -0
- package/.vercel/output/static/404.segments/_tree.segment.rsc.json +1 -0
- package/.vercel/output/static/500.html +1 -0
- package/.vercel/output/static/500.rsc.json +1 -0
- package/.vercel/output/static/500.segments/_tree.segment.rsc.json +1 -0
- package/.vercel/output/static/_next/__private/trace +2 -0
- package/.vercel/output/static/_next/static/TakLsJFW-DjjhsqoZu3Ok/_buildManifest.js +11 -0
- package/.vercel/output/static/_next/static/TakLsJFW-DjjhsqoZu3Ok/_clientMiddlewareManifest.js +42 -0
- package/.vercel/output/static/_next/static/TakLsJFW-DjjhsqoZu3Ok/_ssgManifest.js +1 -0
- package/.vercel/output/static/_next/static/chunks/00~h525bo.q7f.js +1 -0
- package/.vercel/output/static/_next/static/chunks/01xlw8hd842-c.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0257pdz1-imal.js +2 -0
- package/.vercel/output/static/_next/static/chunks/03~yq9q893hmn.js +1 -0
- package/.vercel/output/static/_next/static/chunks/04uju~n5s9g7..css +1 -0
- package/.vercel/output/static/_next/static/chunks/066jf0nk75nic.css +2 -0
- package/.vercel/output/static/_next/static/chunks/085gdrlppedvd.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0a5rikwbpt8_7.js +4 -0
- package/.vercel/output/static/_next/static/chunks/0b9r.-87w.lvh.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0ced2tacwy8v7.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0e-.zgw81gela.js +31 -0
- package/.vercel/output/static/_next/static/chunks/0gu130fpple04.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0jmypv56.iwft.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0krr-nvdwqdj1.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0mqs00d_9jvzx.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0ore4vqiwv2nx.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0pqt~8bl3ukh4.js +4 -0
- package/.vercel/output/static/_next/static/chunks/0q.t7da_-e4yl.js +4 -0
- package/.vercel/output/static/_next/static/chunks/0q3rj30g1oodv.js +7 -0
- package/.vercel/output/static/_next/static/chunks/0qp3_l.t4nzzq.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0qy1ci2dqfaqg.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0u359llqm1_01.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0u7ftv8celiqa.js +1 -0
- package/.vercel/output/static/_next/static/chunks/0~ijg-d65glam.js +1 -0
- package/.vercel/output/static/_next/static/chunks/14bsg3_-taiw4.js +1 -0
- package/.vercel/output/static/_next/static/chunks/168q2d2bi7swr.js +7 -0
- package/.vercel/output/static/_next/static/chunks/16aqsgrwba4zk.js +1 -0
- package/.vercel/output/static/_next/static/chunks/16tw8s4cce9_x.js +1 -0
- package/.vercel/output/static/_next/static/chunks/turbopack-01f1xs~cq_~si.js +1 -0
- package/.vercel/output/static/_next/static/media/4fa387ec64143e14-s.0wkzw~je483f-.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/53b9e256198e5412-s.0-wfv7uh4i7h9.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/5ce348bf30bf5439-s.0zgw-jeven.3w.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/6306c77e7c8268e4-s.0rhz0arwfsn~5.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/7178b3e590c64307-s.0nx0ww8fni_q3.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/797e433ab948586e-s.p.08e28id.o-okb.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/7d817b4c03b0c5f1-s.0l76wvqk9d84w.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/8a480f0b521d4e75-s.0jzbimsg8vl84.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/bbc41e54d2fcbd21-s.0k4k9394f2q-k.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/caa3a2e1cccd8315-s.p.09~u27dqhyhd6.woff2 +0 -0
- package/.vercel/output/static/_next/static/media/favicon.0x3dzn~oxb6tn.ico +0 -0
- package/.vercel/output/static/_next/static/media/fef07dbb0973bf53-s.12tyk43_3sh9u.woff2 +0 -0
- package/.vercel/output/static/_next/static/not-found.txt +1 -0
- package/.vercel/project.json +16 -0
- package/AGENTS.md +9 -0
- package/CLAUDE.md +1 -0
- package/README.md +1 -0
- package/app/api/anet/host-supervisors/route.ts +63 -2
- package/app/api/anet/node-config/route.ts +145 -168
- package/app/api/hub/people/route.ts +48 -0
- package/app/api/hub/requirements/[id]/checklist/[itemId]/route.ts +54 -0
- package/app/api/hub/requirements/[id]/comments/route.ts +51 -0
- package/app/api/hub/requirements/[id]/route.ts +89 -0
- package/app/api/hub/requirements/events/route.ts +45 -0
- package/app/api/hub/requirements/route.ts +53 -0
- package/app/components/CreateNodeWizard.tsx +7 -2
- package/app/components/HostSupervisorPicker.tsx +76 -29
- package/app/components/NodeSettingsPanel.tsx +28 -25
- package/app/components/Sidebar.tsx +4 -0
- package/app/components/TaskChatPanel.tsx +6 -6
- package/app/components/TaskDetail.tsx +8 -7
- package/app/components/TaskList.tsx +6 -7
- package/app/components/TopoGraph.tsx +3 -2
- package/app/lib/time.ts +23 -0
- package/app/org/page.tsx +222 -0
- package/app/requirements/[id]/page.tsx +361 -0
- package/app/requirements/page.tsx +279 -0
- package/app/scheduled-tasks/page.tsx +98 -13
- package/apps/desktop/icon.png +0 -0
- package/bun.lock +1688 -0
- package/electron-builder.json +5 -1
- package/package.json +4 -2
- package/proxy.ts +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0dwa10z._.js +0 -11
- package/.next/server/chunks/ssr/[root-of-the-server]__0dwa10z._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__202xetf._.js +0 -11
- package/.next/server/chunks/ssr/[root-of-the-server]__202xetf._.js.map +0 -1
- package/.next/static/chunks/0pton-t_-fqyu.css +0 -1
- package/.next/static/chunks/0z8vfpga444t1.js +0 -1
- package/.next/static/chunks/14c8u_tcund0g.js +0 -0
- package/.next/static/chunks/2kp8-5cyc-jbg.js +0 -1
- package/.next/static/chunks/3a53_ky07bdhz.js +0 -9
- package/.next/static/chunks/3im40-b21df3u.js +0 -2
- package/.next/static/chunks/3tnbxlq42_jjv.js +0 -1
- /package/.next/server/chunks/ssr/{app_0_s8u96._.js.map → app_07bzc6w._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{app_0o4bxq0._.js.map → app_0g7oz9w._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{app_0x7s72b._.js.map → app_0tt2ueo._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{app_081zy6c._.js.map → app_0ugqkd7._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{app_1oxcq68._.js.map → app_1e91uc-._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{app_1psh956._.js.map → app_1f96aq_._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{app_0_dhiwi._.js.map → app_1ua57bx._.js.map} +0 -0
- /package/.next/static/{trj9RsCWuEDMfq9BuoKfl → _HZB6K84VKNaxf1K7dqqj}/_buildManifest.js +0 -0
- /package/.next/static/{trj9RsCWuEDMfq9BuoKfl → _HZB6K84VKNaxf1K7dqqj}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[34507,a=>{"use strict";var b=a.i(72131);let c="anet-avatars-updated",d={},e=new Set,f="",g=[];function h(a){if(!g.length)return"";let b=5381;for(let c=0;c<a.length;c++)b=(b<<5)+b+a.charCodeAt(c)>>>0;return g[b%g.length]}function i(a){return a?e.has(a)?d[a]||h(a)||"":({})[a]||h(a)||"":""}let j=0;function k(a){let b=()=>{j++,a()};return window.addEventListener(c,b),window.addEventListener("storage",b),()=>{window.removeEventListener(c,b),window.removeEventListener("storage",b)}}a.s(["getAvatarUrl",0,i,"hydrateHubAvatars",0,function(a){if(!a)return;let b={},c=new Set;for(let d of a)d.alias&&(c.add(d.alias),"string"==typeof d.avatar_url&&d.avatar_url&&(b[d.alias]=d.avatar_url));let g=JSON.stringify(b)+"|"+[...c].sort().join(",");g!==f&&(f=g,d=b,e=c)},"setAvatarUrl",0,function(a,b){},"useAvatarUrl",0,function(a){return(0,b.useSyncExternalStore)(k,()=>i(a),()=>"")},"useAvatarsVersion",0,function(){return(0,b.useSyncExternalStore)(k,()=>j,()=>0)}])},5537,a=>{"use strict";let b="anet_chat_outbox_v2:",c="anet_chat_draft_v2:",d=["anet_chat_outbox_v1","anet_chat_draft_v1:"];function e(a,b){if(!b)return null;try{let c=JSON.parse(b.getItem("anet_v3_auth")||"null"),d=c?.user?.user_id||c?.user?.username,e=a||b.getItem("anet_network_id")||c?.currentNetwork;if("string"!=typeof d||!d||"string"!=typeof e||!e)return null;return`${encodeURIComponent(d)}:${encodeURIComponent(e)}`}catch{return null}}function f(a){return!!a&&"object"==typeof a&&"string"==typeof a.requestId&&/^dreq_[A-Za-z0-9_-]{16,96}$/.test(a.requestId)&&"string"==typeof a.localTaskId&&"string"==typeof a.panelAlias&&"string"==typeof a.targetAlias&&"string"==typeof a.content&&new TextEncoder().encode(a.content).byteLength<=32768&&"string"==typeof a.priority&&"string"==typeof a.networkId&&"string"==typeof a.createdAt}function g(a=e(),c,d=Date.now()){if(!c||!a)return[];try{let e=JSON.parse(c.getItem(b+a)||"[]");if(!Array.isArray(e))return[];let g=e.filter(f).filter(a=>{let b=Date.parse(a.createdAt);return Number.isFinite(b)&&b<=d&&d-b<=864e5}).slice(-100);return g.length!==e.length&&h(c,a,g),g}catch{return[]}}function h(a,c,d){try{return a.setItem(b+c,JSON.stringify(d.slice(-100))),!0}catch{return!1}}a.s(["CHAT_DRAFT_PREFIX",0,c,"chatOutboxForAlias",0,function(a,b=e(),c){return g(b,c).filter(b=>b.panelAlias===a)},"chatPrivateScope",0,e,"clearPrivateChatStorage",0,function(a){if(!a)return 0;let e=0;try{let f=[];for(let e=0;e<a.length;e+=1){let g=a.key(e);g&&(g.startsWith(b)||g.startsWith(c)||d.some(a=>g.startsWith(a)))&&f.push(g)}for(let b of f)a.removeItem(b),e+=1}catch{}return e},"putChatOutbox",0,function(a,b=e(a.networkId),c){if(!c||!b||!f(a))return!1;let d=g(b,c).filter(b=>b.requestId!==a.requestId);return d.push(a),h(c,b,d)},"removeChatOutbox",0,function(a,b=e(),c){return!!c&&!!b&&h(c,b,g(b,c).filter(b=>b.requestId!==a))}])},6439,86512,a=>{"use strict";var b=a.i(72131),c=a.i(72596),d=a.i(22397);let e="anet-chat-mute-updated";function f(a){return!!a&&new Set().has(a)}let g=0;function h(a){let b=()=>{g++,a()};return window.addEventListener(e,b),window.addEventListener("storage",b),()=>{window.removeEventListener(e,b),window.removeEventListener("storage",b)}}function i(){return(0,b.useSyncExternalStore)(h,()=>g,()=>0)}a.s(["isMuted",0,f,"toggleMute",0,function(a){},"useMuteVersion",0,i,"useMuted",0,function(a){return(0,b.useSyncExternalStore)(h,()=>!!a&&f(a),()=>!1)}],86512);let j="anet-chat-read-updated",k=new Set(["","dashboard","admin","api","hub"]),l=a=>k.has((a||"").trim().toLowerCase());function m(a){if(!a)return 0;let b=a.includes("T")?a:a.replace(" ","T"),c=Date.parse(/Z$|[+-]\d{2}:\d{2}$/.test(b)?b:`${b}Z`);return Number.isFinite(c)?c:0}let n="__baseline",o=async a=>{let b=await fetch(a);if(401===b.status)throw window.location.assign("/login"),Error("unauthorized");return b.json()};function p(a,b){a&&new Date().toISOString()}a.s(["badgeLabel",0,function(a){return a<=0?"":a>99?"99+":String(a)},"markChatRead",0,p,"useChatUnread",0,function(){let{networkId:a}=(0,d.useNetworkId)(),{data:e}=(0,c.default)(function(a,b){if(!b)return a;let c=a.includes("?")?"&":"?";return`${a}${c}network_id=${encodeURIComponent(b)}`}("/api/hub/messages?limit=200",a),o,{refreshInterval:5e3,dedupingInterval:3e3}),[g,h]=(0,b.useState)(0);(0,b.useEffect)(()=>{let b=b=>{b.key&&b.key!==`anet_chat_read_v1:${a||"global"}`||h(a=>"number"==typeof a?a+1:1)},c=b=>{let c=b.detail;(c?.networkId===void 0||c.networkId===a)&&h(a=>"number"==typeof a?a+1:1)};return window.addEventListener("storage",b),window.addEventListener(j,c),()=>{window.removeEventListener("storage",b),window.removeEventListener(j,c)}},[a,h]);let k=(0,b.useMemo)(()=>({}),[a,g]),q=(0,b.useMemo)(()=>{let a=new Map,b=new Map,c=new Set(Object.keys(k).filter(a=>a!==n)),d=m(k[n]),f=(e,f)=>{c.has(e)&&f>(b.get(e)||0)&&b.set(e,f),f>Math.max(m(k[e]),d)&&a.set(e,(a.get(e)||0)+1)};for(let a of e?.messages||[]){let b=a.from_alias?.trim();if(!b||l(b)||!l(a.to_alias))continue;let c=m(a.created_at);c&&f(b,c)}return{counts:a,lastActivity:b}},[e,k]),r=(0,b.useCallback)(a=>!!a&&(q.counts.get(a)||0)>0,[q]),s=(0,b.useCallback)(a=>a&&q.counts.get(a)||0,[q]),t=(0,b.useCallback)(a=>a&&q.lastActivity.get(a)||0,[q]),u=i(),{totalUnread:v,hasMutedUnread:w}=(0,b.useMemo)(()=>{let a=0,b=!1;for(let[c,d]of q.counts){if(f(c)){d>0&&(b=!0);continue}a+=d}return{totalUnread:a,hasMutedUnread:b}},[q,u]);return{unreadMap:q,hasUnread:r,unreadCount:s,lastActivityAt:t,totalUnread:v,hasMutedUnread:w,clearUnread:(0,b.useCallback)(b=>{p(b,a)},[a])}}],6439)},44332,a=>{"use strict";var b=a.i(72131),c=a.i(34507),d=a.i(72596),e=a.i(22397);let f=async a=>{let b=await fetch(a);if(401===b.status)throw window.location.assign("/login"),Error("unauthorized");return b.json()},g={refreshInterval:5e3,dedupingInterval:3e3};function h(a,b){if(!b)return a;let c=a.includes("?")?"&":"?";return`${a}${c}network_id=${encodeURIComponent(b)}`}a.s(["useAnetConfig",0,function(){let{data:a}=(0,d.default)("/api/anet/config",f,{refreshInterval:3e4});return{config:a||null}},"useHealth",0,function(){let{data:a,error:b}=(0,d.default)("/api/hub/health",f,g);return{health:a||null,error:b}},"useMessages",0,function(a=100){let{networkId:b}=(0,e.useNetworkId)(),{data:c,error:i,isLoading:j}=(0,d.default)(h(`/api/hub/messages?limit=${a}`,b),f,{...g,keepPreviousData:!0});return{messages:c?.messages||[],error:i,isLoading:j}},"useNodeLifecycle",0,function(){let{networkId:a}=(0,e.useNetworkId)(),{data:i,error:j,mutate:k}=(0,d.default)(h("/api/hub/nodes",a),f,g);(0,b.useEffect)(()=>{(0,c.hydrateHubAvatars)(i?.nodes)},[i]);let l={},m={},n={};for(let a of i?.nodes??[])a.alias&&"string"==typeof a.lifecycle_state&&(l[a.alias]=a.lifecycle_state),a.alias&&"string"==typeof a.node_id&&(m[a.alias]=a.node_id),a.alias&&(n[a.alias]={display_name:"string"==typeof a.display_name?a.display_name:null,team:"string"==typeof a.team?a.team:null,tags:Array.isArray(a.tags)?a.tags:[],attrs_revision:"number"==typeof a.attrs_revision?a.attrs_revision:0});return{lifecycleByAlias:l,nodeIdByAlias:m,attrsByAlias:n,error:j,refreshNodes:k}},"useSessions",0,function(){let{networkId:a}=(0,e.useNetworkId)(),{data:b,error:c,isLoading:i}=(0,d.default)(h("/api/hub/status",a),f,g);return{sessions:b?.sessions||[],hint:b?._hint,error:c,isLoading:i}},"useStats",0,function(){let{networkId:a}=(0,e.useNetworkId)(),{data:b,error:c}=(0,d.default)(h("/api/hub/stats",a),f,g);return{stats:b?.ok?b:null,error:c}},"useTasks",0,function(a){let{networkId:b}=(0,e.useNetworkId)(),c=new URLSearchParams({limit:"100",...a}).toString(),{data:i,error:j,isLoading:k}=(0,d.default)(h(`/api/hub/tasks?${c}`,b),f,g);return{tasks:i?.tasks||[],count:i?.count??0,source:i?.source,error:j,isLoading:k}}])},22397,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=(0,c.createContext)({networkId:"",setNetworkId:()=>{}});a.s(["NetworkProvider",0,function({children:a}){let[e,f]=(0,c.useState)("");return(0,c.useEffect)(()=>{let a=sessionStorage.getItem("anet_network_id");if(a)return void f(a);let b=!1;return fetch("/api/hub/networks",{cache:"no-store"}).then(a=>a.ok?a.json():{networks:[]}).then(a=>{if(b)return;let c=Array.isArray(a.networks)?a.networks:[],d=c.find(a=>"default"===a.network_name)||c[0],e=d?.network_id;if(e){f(e);try{sessionStorage.setItem("anet_network_id",e)}catch{}}}).catch(()=>{}),()=>{b=!0}},[]),(0,b.jsx)(d.Provider,{value:{networkId:e,setNetworkId:a=>{f(a),sessionStorage.setItem("anet_network_id",a)}},children:a})},"useNetworkId",0,function(){return(0,c.useContext)(d)}])},69237,a=>{"use strict";function b(a,b){if(!b)return;let c=(a.network_id?b[`${a.network_id}:${a.alias}`]:void 0)??b[a.alias];return"number"==typeof c?c:void 0}a.s(["isOnline",0,function(a,c){let d=b(a,c);return"number"==typeof d&&d>0},"presenceStatus",0,function(a,b){return void 0!==a?"ready":(b&&"number"==typeof b.sse_connections?b.sse_connections:0)>0?"blind":"loading"},"sseCountFor",0,b])},89706,a=>{"use strict";function b(a){if(!a)return null;let b=Date.parse(a.includes("T")?a:a.replace(" ","T")+"Z");return Number.isFinite(b)?b:null}a.s(["formatWeChatTime",0,function(a){let c=b(a);if(null===c)return"";let d=new Date(c),e=new Date,f="u">typeof navigator&&(navigator.language||"").toLowerCase().startsWith("zh"),g=`${String(d.getHours()).padStart(2,"0")}:${String(d.getMinutes()).padStart(2,"0")}`,h=a=>new Date(a.getFullYear(),a.getMonth(),a.getDate()).getTime(),i=Math.round((h(e)-h(d))/864e5);if(0===i)return g;if(1===i)return f?`昨天 ${g}`:`Yesterday ${g}`;if(i>1&&i<7){let a=new Intl.DateTimeFormat(f?"zh-CN":void 0,{weekday:f?"long":"short"}).format(d);return`${a} ${g}`}let j=new Intl.DateTimeFormat(f?"zh-CN":void 0,{month:f?"long":"short",day:"numeric",...d.getFullYear()!==e.getFullYear()?{year:"numeric"}:{}}).format(d);return`${j} ${g}`},"parseHubTime",0,b,"relativeAgo",0,function(a){let c=b(a);if(null===c)return null;let d=Math.floor((Date.now()-c)/1e3);return d<0?"just now":d<60?`${d}s ago`:d<3600?`${Math.floor(d/60)}m ago`:d<86400?`${Math.floor(d/3600)}h ago`:`${Math.floor(d/86400)}d ago`}])}];
|
|
1
|
+
module.exports=[34507,a=>{"use strict";var b=a.i(72131);let c="anet-avatars-updated",d={},e=new Set,f="",g=[];function h(a){if(!g.length)return"";let b=5381;for(let c=0;c<a.length;c++)b=(b<<5)+b+a.charCodeAt(c)>>>0;return g[b%g.length]}function i(a){return a?e.has(a)?d[a]||h(a)||"":({})[a]||h(a)||"":""}let j=0;function k(a){let b=()=>{j++,a()};return window.addEventListener(c,b),window.addEventListener("storage",b),()=>{window.removeEventListener(c,b),window.removeEventListener("storage",b)}}a.s(["getAvatarUrl",0,i,"hydrateHubAvatars",0,function(a){if(!a)return;let b={},c=new Set;for(let d of a)d.alias&&(c.add(d.alias),"string"==typeof d.avatar_url&&d.avatar_url&&(b[d.alias]=d.avatar_url));let g=JSON.stringify(b)+"|"+[...c].sort().join(",");g!==f&&(f=g,d=b,e=c)},"setAvatarUrl",0,function(a,b){},"useAvatarUrl",0,function(a){return(0,b.useSyncExternalStore)(k,()=>i(a),()=>"")},"useAvatarsVersion",0,function(){return(0,b.useSyncExternalStore)(k,()=>j,()=>0)}])},5537,a=>{"use strict";let b="anet_chat_outbox_v2:",c="anet_chat_draft_v2:",d=["anet_chat_outbox_v1","anet_chat_draft_v1:"];function e(a,b){if(!b)return null;try{let c=JSON.parse(b.getItem("anet_v3_auth")||"null"),d=c?.user?.user_id||c?.user?.username,e=a||b.getItem("anet_network_id")||c?.currentNetwork;if("string"!=typeof d||!d||"string"!=typeof e||!e)return null;return`${encodeURIComponent(d)}:${encodeURIComponent(e)}`}catch{return null}}function f(a){return!!a&&"object"==typeof a&&"string"==typeof a.requestId&&/^dreq_[A-Za-z0-9_-]{16,96}$/.test(a.requestId)&&"string"==typeof a.localTaskId&&"string"==typeof a.panelAlias&&"string"==typeof a.targetAlias&&"string"==typeof a.content&&new TextEncoder().encode(a.content).byteLength<=32768&&"string"==typeof a.priority&&"string"==typeof a.networkId&&"string"==typeof a.createdAt}function g(a=e(),c,d=Date.now()){if(!c||!a)return[];try{let e=JSON.parse(c.getItem(b+a)||"[]");if(!Array.isArray(e))return[];let g=e.filter(f).filter(a=>{let b=Date.parse(a.createdAt);return Number.isFinite(b)&&b<=d&&d-b<=864e5}).slice(-100);return g.length!==e.length&&h(c,a,g),g}catch{return[]}}function h(a,c,d){try{return a.setItem(b+c,JSON.stringify(d.slice(-100))),!0}catch{return!1}}a.s(["CHAT_DRAFT_PREFIX",0,c,"chatOutboxForAlias",0,function(a,b=e(),c){return g(b,c).filter(b=>b.panelAlias===a)},"chatPrivateScope",0,e,"clearPrivateChatStorage",0,function(a){if(!a)return 0;let e=0;try{let f=[];for(let e=0;e<a.length;e+=1){let g=a.key(e);g&&(g.startsWith(b)||g.startsWith(c)||d.some(a=>g.startsWith(a)))&&f.push(g)}for(let b of f)a.removeItem(b),e+=1}catch{}return e},"putChatOutbox",0,function(a,b=e(a.networkId),c){if(!c||!b||!f(a))return!1;let d=g(b,c).filter(b=>b.requestId!==a.requestId);return d.push(a),h(c,b,d)},"removeChatOutbox",0,function(a,b=e(),c){return!!c&&!!b&&h(c,b,g(b,c).filter(b=>b.requestId!==a))}])},6439,86512,a=>{"use strict";var b=a.i(72131),c=a.i(72596),d=a.i(22397);let e="anet-chat-mute-updated";function f(a){return!!a&&new Set().has(a)}let g=0;function h(a){let b=()=>{g++,a()};return window.addEventListener(e,b),window.addEventListener("storage",b),()=>{window.removeEventListener(e,b),window.removeEventListener("storage",b)}}function i(){return(0,b.useSyncExternalStore)(h,()=>g,()=>0)}a.s(["isMuted",0,f,"toggleMute",0,function(a){},"useMuteVersion",0,i,"useMuted",0,function(a){return(0,b.useSyncExternalStore)(h,()=>!!a&&f(a),()=>!1)}],86512);let j="anet-chat-read-updated",k=new Set(["","dashboard","admin","api","hub"]),l=a=>k.has((a||"").trim().toLowerCase());function m(a){if(!a)return 0;let b=a.includes("T")?a:a.replace(" ","T"),c=Date.parse(/Z$|[+-]\d{2}:\d{2}$/.test(b)?b:`${b}Z`);return Number.isFinite(c)?c:0}let n="__baseline",o=async a=>{let b=await fetch(a);if(401===b.status)throw window.location.assign("/login"),Error("unauthorized");return b.json()};function p(a,b){a&&new Date().toISOString()}a.s(["badgeLabel",0,function(a){return a<=0?"":a>99?"99+":String(a)},"markChatRead",0,p,"useChatUnread",0,function(){let{networkId:a}=(0,d.useNetworkId)(),{data:e}=(0,c.default)(function(a,b){if(!b)return a;let c=a.includes("?")?"&":"?";return`${a}${c}network_id=${encodeURIComponent(b)}`}("/api/hub/messages?limit=200",a),o,{refreshInterval:5e3,dedupingInterval:3e3}),[g,h]=(0,b.useState)(0);(0,b.useEffect)(()=>{let b=b=>{b.key&&b.key!==`anet_chat_read_v1:${a||"global"}`||h(a=>"number"==typeof a?a+1:1)},c=b=>{let c=b.detail;(c?.networkId===void 0||c.networkId===a)&&h(a=>"number"==typeof a?a+1:1)};return window.addEventListener("storage",b),window.addEventListener(j,c),()=>{window.removeEventListener("storage",b),window.removeEventListener(j,c)}},[a,h]);let k=(0,b.useMemo)(()=>({}),[a,g]),q=(0,b.useMemo)(()=>{let a=new Map,b=new Map,c=new Set(Object.keys(k).filter(a=>a!==n)),d=m(k[n]),f=(e,f)=>{c.has(e)&&f>(b.get(e)||0)&&b.set(e,f),f>Math.max(m(k[e]),d)&&a.set(e,(a.get(e)||0)+1)};for(let a of e?.messages||[]){let b=a.from_alias?.trim();if(!b||l(b)||!l(a.to_alias))continue;let c=m(a.created_at);c&&f(b,c)}return{counts:a,lastActivity:b}},[e,k]),r=(0,b.useCallback)(a=>!!a&&(q.counts.get(a)||0)>0,[q]),s=(0,b.useCallback)(a=>a&&q.counts.get(a)||0,[q]),t=(0,b.useCallback)(a=>a&&q.lastActivity.get(a)||0,[q]),u=i(),{totalUnread:v,hasMutedUnread:w}=(0,b.useMemo)(()=>{let a=0,b=!1;for(let[c,d]of q.counts){if(f(c)){d>0&&(b=!0);continue}a+=d}return{totalUnread:a,hasMutedUnread:b}},[q,u]);return{unreadMap:q,hasUnread:r,unreadCount:s,lastActivityAt:t,totalUnread:v,hasMutedUnread:w,clearUnread:(0,b.useCallback)(b=>{p(b,a)},[a])}}],6439)},44332,a=>{"use strict";var b=a.i(72131),c=a.i(34507),d=a.i(72596),e=a.i(22397);let f=async a=>{let b=await fetch(a);if(401===b.status)throw window.location.assign("/login"),Error("unauthorized");return b.json()},g={refreshInterval:5e3,dedupingInterval:3e3};function h(a,b){if(!b)return a;let c=a.includes("?")?"&":"?";return`${a}${c}network_id=${encodeURIComponent(b)}`}a.s(["useAnetConfig",0,function(){let{data:a}=(0,d.default)("/api/anet/config",f,{refreshInterval:3e4});return{config:a||null}},"useHealth",0,function(){let{data:a,error:b}=(0,d.default)("/api/hub/health",f,g);return{health:a||null,error:b}},"useMessages",0,function(a=100){let{networkId:b}=(0,e.useNetworkId)(),{data:c,error:i,isLoading:j}=(0,d.default)(h(`/api/hub/messages?limit=${a}`,b),f,{...g,keepPreviousData:!0});return{messages:c?.messages||[],error:i,isLoading:j}},"useNodeLifecycle",0,function(){let{networkId:a}=(0,e.useNetworkId)(),{data:i,error:j,mutate:k}=(0,d.default)(h("/api/hub/nodes",a),f,g);(0,b.useEffect)(()=>{(0,c.hydrateHubAvatars)(i?.nodes)},[i]);let l={},m={},n={};for(let a of i?.nodes??[])a.alias&&"string"==typeof a.lifecycle_state&&(l[a.alias]=a.lifecycle_state),a.alias&&"string"==typeof a.node_id&&(m[a.alias]=a.node_id),a.alias&&(n[a.alias]={display_name:"string"==typeof a.display_name?a.display_name:null,team:"string"==typeof a.team?a.team:null,tags:Array.isArray(a.tags)?a.tags:[],attrs_revision:"number"==typeof a.attrs_revision?a.attrs_revision:0});return{lifecycleByAlias:l,nodeIdByAlias:m,attrsByAlias:n,error:j,refreshNodes:k}},"useSessions",0,function(){let{networkId:a}=(0,e.useNetworkId)(),{data:b,error:c,isLoading:i}=(0,d.default)(h("/api/hub/status",a),f,g);return{sessions:b?.sessions||[],hint:b?._hint,error:c,isLoading:i}},"useStats",0,function(){let{networkId:a}=(0,e.useNetworkId)(),{data:b,error:c}=(0,d.default)(h("/api/hub/stats",a),f,g);return{stats:b?.ok?b:null,error:c}},"useTasks",0,function(a){let{networkId:b}=(0,e.useNetworkId)(),c=new URLSearchParams({limit:"100",...a}).toString(),{data:i,error:j,isLoading:k}=(0,d.default)(h(`/api/hub/tasks?${c}`,b),f,g);return{tasks:i?.tasks||[],count:i?.count??0,source:i?.source,error:j,isLoading:k}}])},22397,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=(0,c.createContext)({networkId:"",setNetworkId:()=>{}});a.s(["NetworkProvider",0,function({children:a}){let[e,f]=(0,c.useState)("");return(0,c.useEffect)(()=>{let a=sessionStorage.getItem("anet_network_id");if(a)return void f(a);let b=!1;return fetch("/api/hub/networks",{cache:"no-store"}).then(a=>a.ok?a.json():{networks:[]}).then(a=>{if(b)return;let c=Array.isArray(a.networks)?a.networks:[],d=c.find(a=>"default"===a.network_name)||c[0],e=d?.network_id;if(e){f(e);try{sessionStorage.setItem("anet_network_id",e)}catch{}}}).catch(()=>{}),()=>{b=!0}},[]),(0,b.jsx)(d.Provider,{value:{networkId:e,setNetworkId:a=>{f(a),sessionStorage.setItem("anet_network_id",a)}},children:a})},"useNetworkId",0,function(){return(0,c.useContext)(d)}])},69237,a=>{"use strict";function b(a,b){if(!b)return;let c=(a.network_id?b[`${a.network_id}:${a.alias}`]:void 0)??b[a.alias];return"number"==typeof c?c:void 0}a.s(["isOnline",0,function(a,c){let d=b(a,c);return"number"==typeof d&&d>0},"presenceStatus",0,function(a,b){return void 0!==a?"ready":(b&&"number"==typeof b.sse_connections?b.sse_connections:0)>0?"blind":"loading"},"sseCountFor",0,b])},89706,a=>{"use strict";function b(a){if(!a)return null;let b=Date.parse(a.includes("T")?a:a.replace(" ","T")+"Z");return Number.isFinite(b)?b:null}a.s(["NODE_STALE_MS",0,36e5,"formatWeChatTime",0,function(a){let c=b(a);if(null===c)return"";let d=new Date(c),e=new Date,f="u">typeof navigator&&(navigator.language||"").toLowerCase().startsWith("zh"),g=`${String(d.getHours()).padStart(2,"0")}:${String(d.getMinutes()).padStart(2,"0")}`,h=a=>new Date(a.getFullYear(),a.getMonth(),a.getDate()).getTime(),i=Math.round((h(e)-h(d))/864e5);if(0===i)return g;if(1===i)return f?`昨天 ${g}`:`Yesterday ${g}`;if(i>1&&i<7){let a=new Intl.DateTimeFormat(f?"zh-CN":void 0,{weekday:f?"long":"short"}).format(d);return`${a} ${g}`}let j=new Intl.DateTimeFormat(f?"zh-CN":void 0,{month:f?"long":"short",day:"numeric",...d.getFullYear()!==e.getFullYear()?{year:"numeric"}:{}}).format(d);return`${j} ${g}`},"isHubTimeStale",0,function(a){let c=b(a);return null!==c&&Date.now()-c>36e5},"parseHubTime",0,b,"relativeAgo",0,function(a){let c=b(a);if(null===c)return null;let d=Math.floor((Date.now()-c)/1e3);return d<0?"just now":d<60?`${d}s ago`:d<3600?`${Math.floor(d/60)}m ago`:d<86400?`${Math.floor(d/3600)}h ago`:`${Math.floor(d/86400)}d ago`}])}];
|
|
2
2
|
|
|
3
|
-
//# sourceMappingURL=
|
|
3
|
+
//# sourceMappingURL=app_lib_20-pe_0._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../app/lib/avatars.ts","../../../../app/lib/chat-outbox.ts","../../../../app/lib/chat-unread.ts","../../../../app/lib/chat-mute.ts","../../../../app/lib/hooks.ts","../../../../app/lib/network-context.tsx","../../../../app/lib/presence.ts","../../../../app/lib/time.ts"],"sourcesContent":["'use client';\n\nimport { useSyncExternalStore } from 'react';\n\n/* Loop R24 (Vincent 亲点: 头像换血) — custom avatar infrastructure.\n *\n * Resolution order, per alias (通信龙 裁定, avatar 接线单 07-31):\n * 1. hub avatar_url — nodes.avatar_url via GET /api/hub/nodes, hydrated\n * by useNodeLifecycle → hydrateHubAvatars(). The hub is the\n * CROSS-DEVICE truth, so it sits ABOVE localStorage (which is only a\n * per-browser cache); the pre-wiring order caused the \"改了头像别人\n * 看不到\" stuck-avatar report.\n * Evidence the hub side exists (this comment previously claimed it\n * didn't — that stale claim is WHY nobody wired this for weeks):\n * hub #462 shipped PUT /api/nodes/:ref/avatar (server.ts:2477,\n * validated by avatar-validate.ts) + nodes.avatar_url column\n * (db.ts:346) + the GET projection (server.ts:2784).\n * 2. user override — localStorage map, set in the node settings UI\n * (which now ALSO PUTs to the hub; localStorage is the echo)\n * 3. designed default — /avatars/manifest.json (static, alias → URL)\n * 4. shared pool — manifest \"_pool\"; stable djb2 pick per alias\n * 5. '' → caller falls back to the hue-hashed initial pill\n */\n\nconst STORE_KEY = 'anet_avatars_v1';\nconst AVATAR_EVENT = 'anet-avatars-updated';\n\nlet hubMap: Record<string, string> = {};\n/** Aliases that HAVE a nodes row — for them the hub is the whole truth,\n * INCLUDING \"cleared\" (avatar_url null): a stale localStorage override on\n * another device must not resurrect the old picture (clear-consistency\n * gap, #72 review follow-up / 通信龙 批准). Session-only aliases keep\n * localStorage as their only personalization. */\nlet hubNodeAliases: Set<string> = new Set();\nlet hubMapKey = ''; // change detector — avoid event storms on every poll\n\n/** Feed nodes from GET /api/hub/nodes into the resolution chain (layer 1).\n * Cheap to call on every SWR poll: only dispatches when content changed. */\nexport function hydrateHubAvatars(nodes: Array<{ alias?: string; avatar_url?: string | null }> | undefined) {\n if (!nodes) return;\n const next: Record<string, string> = {};\n const nextAliases = new Set<string>();\n for (const n of nodes) {\n if (!n.alias) continue;\n nextAliases.add(n.alias);\n if (typeof n.avatar_url === 'string' && n.avatar_url) next[n.alias] = n.avatar_url;\n }\n const key = JSON.stringify(next) + '|' + [...nextAliases].sort().join(',');\n if (key === hubMapKey) return;\n hubMapKey = key;\n hubMap = next;\n hubNodeAliases = nextAliases;\n if (typeof window !== 'undefined') window.dispatchEvent(new Event(AVATAR_EVENT));\n}\n\nlet manifest: Record<string, string> | null = null;\nlet pool: string[] = [];\nlet manifestRequested = false;\n\n/* Stable per-alias index so a given agent keeps the same pool avatar across\n * sessions/devices (djb2 over code units — no Math.random, no ordering). */\nfunction poolPick(alias: string): string {\n if (!pool.length) return '';\n let h = 5381;\n for (let i = 0; i < alias.length; i++) h = ((h << 5) + h + alias.charCodeAt(i)) >>> 0;\n return pool[h % pool.length];\n}\n\nfunction fetchManifestOnce() {\n if (manifestRequested || typeof window === 'undefined') return;\n manifestRequested = true;\n fetch('/avatars/manifest.json', { cache: 'no-cache' })\n .then((r) => (r.ok ? r.json() : null))\n .then((j) => {\n if (j && typeof j === 'object' && !Array.isArray(j)) {\n const clean: Record<string, string> = {};\n for (const [k, v] of Object.entries(j as Record<string, unknown>)) {\n if (k.startsWith('_')) continue; // meta keys (\"_pool\", …)\n if (typeof v === 'string' && v.startsWith('/')) clean[k] = v;\n }\n const rawPool = (j as Record<string, unknown>)._pool;\n pool = Array.isArray(rawPool)\n ? rawPool.filter((p): p is string => typeof p === 'string' && p.startsWith('/'))\n : [];\n manifest = clean;\n window.dispatchEvent(new Event(AVATAR_EVENT));\n }\n })\n .catch(() => {});\n}\n\nfunction readMap(): Record<string, string> {\n if (typeof window === 'undefined') return {};\n try {\n const parsed = JSON.parse(window.localStorage.getItem(STORE_KEY) || '{}');\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n}\n\nexport function getAvatarUrl(alias?: string | null): string {\n if (!alias) return '';\n // Node-backed: hub authority — its value, or (when cleared/none) the\n // designed default chain, SKIPPING localStorage entirely.\n if (hubNodeAliases.has(alias)) {\n return hubMap[alias] || manifest?.[alias] || poolPick(alias) || '';\n }\n // Session-only: localStorage is the only personalization layer.\n return readMap()[alias] || manifest?.[alias] || poolPick(alias) || '';\n}\n\n/** Empty/whitespace url removes the override (falls back to manifest/pill). */\nexport function setAvatarUrl(alias: string, url: string) {\n if (typeof window === 'undefined' || !alias) return;\n try {\n const m = readMap();\n if (url.trim()) m[alias] = url.trim();\n else delete m[alias];\n window.localStorage.setItem(STORE_KEY, JSON.stringify(m));\n window.dispatchEvent(new Event(AVATAR_EVENT));\n } catch {}\n}\n\nlet version = 0;\nfunction subscribe(callback: () => void) {\n fetchManifestOnce();\n const bump = () => { version++; callback(); };\n window.addEventListener(AVATAR_EVENT, bump);\n window.addEventListener('storage', bump);\n return () => {\n window.removeEventListener(AVATAR_EVENT, bump);\n window.removeEventListener('storage', bump);\n };\n}\n\n/** Monotonic version for callers that resolve many aliases via plain\n * getAvatarUrl() inside render loops (map callbacks can't call hooks —\n * same idiom as chat-mute's useMuteVersion). Subscribing also kicks off\n * the lazy manifest fetch and re-renders the caller when it lands. */\nexport function useAvatarsVersion(): number {\n return useSyncExternalStore(subscribe, () => version, () => 0);\n}\n\nexport function useAvatarUrl(alias?: string | null): string {\n return useSyncExternalStore(subscribe, () => getAvatarUrl(alias), () => '');\n}\n","'use client';\n\nexport const CHAT_OUTBOX_PREFIX = 'anet_chat_outbox_v2:';\nexport const CHAT_DRAFT_PREFIX = 'anet_chat_draft_v2:';\nconst LEGACY_PRIVATE_PREFIXES = ['anet_chat_outbox_v1', 'anet_chat_draft_v1:'];\nconst AUTH_KEY = 'anet_v3_auth';\nconst MAX_ENTRIES = 100;\nconst MAX_CONTENT_BYTES = 32 * 1024;\nconst OUTBOX_TTL_MS = 24 * 60 * 60 * 1000;\n\n/** Scope plaintext chat recovery data to the authenticated user and network.\n * If the client has no trustworthy identity snapshot, persistence is disabled. */\nexport function chatPrivateScope(\n networkId?: string | null,\n session: Storage | undefined = typeof window === 'undefined' ? undefined : window.sessionStorage,\n): string | null {\n if (!session) return null;\n try {\n const auth = JSON.parse(session.getItem(AUTH_KEY) || 'null');\n const identity = auth?.user?.user_id || auth?.user?.username;\n const network = networkId || session.getItem('anet_network_id') || auth?.currentNetwork;\n if (typeof identity !== 'string' || !identity || typeof network !== 'string' || !network) return null;\n return `${encodeURIComponent(identity)}:${encodeURIComponent(network)}`;\n } catch {\n return null;\n }\n}\n\n/** Explicit logout removes every account/network shard and legacy plaintext. */\nexport function clearPrivateChatStorage(\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n): number {\n if (!storage) return 0;\n let removed = 0;\n try {\n const keys: string[] = [];\n for (let index = 0; index < storage.length; index += 1) {\n const key = storage.key(index);\n if (key && (\n key.startsWith(CHAT_OUTBOX_PREFIX)\n || key.startsWith(CHAT_DRAFT_PREFIX)\n || LEGACY_PRIVATE_PREFIXES.some(prefix => key.startsWith(prefix))\n )) keys.push(key);\n }\n for (const key of keys) {\n storage.removeItem(key);\n removed += 1;\n }\n } catch {\n // Storage errors must not block logout.\n }\n return removed;\n}\n\nexport interface ChatOutboxEntry {\n requestId: string;\n localTaskId: string;\n panelAlias: string;\n targetAlias: string;\n content: string;\n priority: string;\n networkId: string;\n createdAt: string;\n}\n\nfunction valid(entry: unknown): entry is ChatOutboxEntry {\n if (!entry || typeof entry !== 'object') return false;\n const e = entry as Partial<ChatOutboxEntry>;\n return typeof e.requestId === 'string' && /^dreq_[A-Za-z0-9_-]{16,96}$/.test(e.requestId)\n && typeof e.localTaskId === 'string'\n && typeof e.panelAlias === 'string'\n && typeof e.targetAlias === 'string'\n && typeof e.content === 'string' && new TextEncoder().encode(e.content).byteLength <= MAX_CONTENT_BYTES\n && typeof e.priority === 'string'\n && typeof e.networkId === 'string'\n && typeof e.createdAt === 'string';\n}\n\nfunction storageKey(scope: string) { return CHAT_OUTBOX_PREFIX + scope; }\n\nexport function readChatOutbox(\n scope: string | null = chatPrivateScope(),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n now = Date.now(),\n): ChatOutboxEntry[] {\n if (!storage || !scope) return [];\n try {\n const parsed = JSON.parse(storage.getItem(storageKey(scope)) || '[]');\n if (!Array.isArray(parsed)) return [];\n const live = parsed.filter(valid).filter(entry => {\n const created = Date.parse(entry.createdAt);\n return Number.isFinite(created) && created <= now && now - created <= OUTBOX_TTL_MS;\n }).slice(-MAX_ENTRIES);\n // TTL is a storage lifecycle, not merely a display filter: erase expired,\n // malformed, and oversized plaintext opportunistically on every read.\n if (live.length !== parsed.length) write(storage, scope, live);\n return live;\n } catch {\n return [];\n }\n}\n\nfunction write(storage: Storage, scope: string, entries: ChatOutboxEntry[]): boolean {\n try {\n storage.setItem(storageKey(scope), JSON.stringify(entries.slice(-MAX_ENTRIES)));\n return true;\n } catch {\n // Storage can be disabled, full, or unavailable in a privacy-restricted\n // webview. The outbox is a recovery enhancement and must never prevent\n // the actual network send.\n return false;\n }\n}\n\nexport function putChatOutbox(\n entry: ChatOutboxEntry,\n scope: string | null = chatPrivateScope(entry.networkId),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n) {\n if (!storage || !scope || !valid(entry)) return false;\n const next = readChatOutbox(scope, storage).filter(item => item.requestId !== entry.requestId);\n next.push(entry);\n return write(storage, scope, next);\n}\n\nexport function removeChatOutbox(\n requestId: string,\n scope: string | null = chatPrivateScope(),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n) {\n if (!storage || !scope) return false;\n return write(storage, scope, readChatOutbox(scope, storage).filter(item => item.requestId !== requestId));\n}\n\nexport function chatOutboxForAlias(\n alias: string,\n scope: string | null = chatPrivateScope(),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n) {\n return readChatOutbox(scope, storage).filter(item => item.panelAlias === alias);\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport useSWR from 'swr';\nimport { useNetworkId } from './network-context';\nimport { isMuted, useMuteVersion } from './chat-mute';\n\nconst STORAGE_PREFIX = 'anet_chat_read_v1:';\nconst UNREAD_EVENT = 'anet-chat-read-updated';\n\ninterface ChatMessage {\n from_alias?: string | null;\n to_alias?: string | null;\n created_at?: string | null;\n}\n\n/** Senders/recipients that mean \"the dashboard user\" in hub data. The chat\n * panel uses the same set to decide which bubbles are \"You\". */\nconst USERISH = new Set(['', 'dashboard', 'admin', 'api', 'hub']);\nconst isUserish = (v?: string | null) => USERISH.has((v || '').trim().toLowerCase());\n\ninterface ReadMap {\n [alias: string]: string;\n}\n\nfunction storageKey(networkId: string) {\n return `${STORAGE_PREFIX}${networkId || 'global'}`;\n}\n\nfunction parseHubTime(value?: string | null): number {\n if (!value) return 0;\n const normalized = value.includes('T') ? value : value.replace(' ', 'T');\n const withZone = /Z$|[+-]\\d{2}:\\d{2}$/.test(normalized) ? normalized : `${normalized}Z`;\n const ts = Date.parse(withZone);\n return Number.isFinite(ts) ? ts : 0;\n}\n\n// Loop R8 (Vincent: 未读数字角标): last-read moved sessionStorage →\n// localStorage so read state survives refresh/new tabs/restart (微信预期).\n// One-time migration pulls any old session value forward.\nconst BASELINE_KEY = '__baseline';\n\nfunction readStoredMap(networkId: string): ReadMap {\n if (typeof window === 'undefined') return {};\n try {\n let raw = window.localStorage.getItem(storageKey(networkId));\n if (!raw) {\n raw = window.sessionStorage.getItem(storageKey(networkId));\n if (raw) window.localStorage.setItem(storageKey(networkId), raw);\n }\n const parsed = raw ? JSON.parse(raw) : {};\n const map: ReadMap = parsed && typeof parsed === 'object' ? parsed : {};\n // R8 first-visit floor, written SYNCHRONOUSLY on first read: an async\n // (useEffect) baseline lost the race against the first SWR render and\n // let a badge storm flash — and stick, since nothing re-triggered the\n // count. Ensuring it here means no compute can ever see a missing\n // baseline. No event dispatch: every hook instance does the same\n // idempotent write.\n if (!map[BASELINE_KEY]) {\n map[BASELINE_KEY] = new Date().toISOString();\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(map));\n }\n return map;\n } catch {\n return {};\n }\n}\n\nfunction writeStoredMap(networkId: string, next: ReadMap) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(next));\n window.dispatchEvent(new CustomEvent(UNREAD_EVENT, { detail: { networkId } }));\n } catch {}\n}\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function markChatRead(alias: string, networkId: string) {\n if (!alias) return;\n const current = readStoredMap(networkId);\n writeStoredMap(networkId, {\n ...current,\n [alias]: new Date().toISOString(),\n });\n}\n\nexport function useChatUnread() {\n const { networkId } = useNetworkId();\n // Messages are the ONLY count source: the hub mirrors every task reply as\n // a message to the originator (verified live: replied task + same-second\n // message, both present), so counting tasks too double-counted every\n // reply (E2E showed 4 where 2 was right).\n const { data: messagesData } = useSWR<{ messages?: ChatMessage[] }>(\n withNetwork('/api/hub/messages?limit=200', networkId),\n fetcher,\n { refreshInterval: 5000, dedupingInterval: 3000 },\n );\n const [readVersion, setReadVersion] = useState(0);\n\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key && event.key !== storageKey(networkId)) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n const onUnreadUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ networkId?: string }>).detail;\n if (detail?.networkId !== undefined && detail.networkId !== networkId) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n window.addEventListener('storage', onStorage);\n window.addEventListener(UNREAD_EVENT, onUnreadUpdate);\n return () => {\n window.removeEventListener('storage', onStorage);\n window.removeEventListener(UNREAD_EVENT, onUnreadUpdate);\n };\n }, [networkId, setReadVersion]);\n\n const readMap = useMemo(() => {\n void readVersion;\n return readStoredMap(networkId);\n }, [networkId, readVersion]);\n\n const unreadMap = useMemo(() => {\n // R8: count EVERY unread item per alias (Vincent: \"有几条消息显示数字\"),\n // not just a latest-activity boolean. A message from the alias counts;\n // a task's REPLY counts once when it lands after last-read. Self-sent\n // items never count (they're keyed by the counterpart alias).\n const counts = new Map<string, number>();\n // R28 (微信排序): recency tiebreak for Overview/Nodes — but ONLY for\n // conversations the user has actually OPENED (read-map entry). On this\n // fleet agents constantly report to 'admin'; counting those yanked\n // never-opened agents to the front on every report (measured: 2 cards\n // jumped 39→1 / 60→3 in one 6s window). WeChat's list holds YOUR\n // conversations — same rule here keeps the grid calm.\n const lastActivity = new Map<string, number>();\n const opened = new Set(Object.keys(readMap).filter((k) => k !== BASELINE_KEY));\n const baseline = parseHubTime(readMap[BASELINE_KEY]);\n const bump = (alias: string, at: number) => {\n if (opened.has(alias) && at > (lastActivity.get(alias) || 0)) lastActivity.set(alias, at);\n const readAt = Math.max(parseHubTime(readMap[alias]), baseline);\n if (at > readAt) counts.set(alias, (counts.get(alias) || 0) + 1);\n };\n // Scope: only the USER'S conversation — a badge on X means \"X has\n // something FOR YOU\". Fleet chatter (X's messages to other agents)\n // must NOT inflate it.\n for (const message of messagesData?.messages || []) {\n const alias = message.from_alias?.trim();\n if (!alias || isUserish(alias)) continue; // own sends never count\n if (!isUserish(message.to_alias)) continue; // must be addressed to the user\n const at = parseHubTime(message.created_at);\n if (at) bump(alias, at);\n }\n return { counts, lastActivity };\n }, [messagesData, readMap]);\n\n const hasUnread = useCallback((alias?: string | null) => {\n if (!alias) return false;\n return (unreadMap.counts.get(alias) || 0) > 0;\n }, [unreadMap]);\n\n const unreadCount = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.counts.get(alias) || 0;\n }, [unreadMap]);\n\n const lastActivityAt = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.lastActivity.get(alias) || 0;\n }, [unreadMap]);\n\n // R34: muted conversations are excluded from the global count (WeChat\n // semantics); hasMutedUnread lets entry badges fall back to a dot.\n const muteVersion = useMuteVersion();\n const { totalUnread, hasMutedUnread } = useMemo(() => {\n void muteVersion;\n let t = 0;\n let mutedAny = false;\n for (const [alias, n] of unreadMap.counts) {\n if (isMuted(alias)) { if (n > 0) mutedAny = true; continue; }\n t += n;\n }\n return { totalUnread: t, hasMutedUnread: mutedAny };\n }, [unreadMap, muteVersion]);\n\n const clearUnread = useCallback((alias: string) => {\n markChatRead(alias, networkId);\n }, [networkId]);\n\n return { unreadMap, hasUnread, unreadCount, lastActivityAt, totalUnread, hasMutedUnread, clearUnread };\n}\n\n/** WeChat badge label: 1-99 as-is, above → \"99+\"; 0/negative → '' (hide). */\nexport function badgeLabel(n: number): string {\n if (n <= 0) return '';\n return n > 99 ? '99+' : String(n);\n}\n","'use client';\n\nimport { useSyncExternalStore } from 'react';\n\n/* Loop R34 (微信消息免打扰, 克制版): per-conversation mute. Muted\n * conversations keep their red badge but show a DOT instead of the count,\n * and their unreads are excluded from the global total (WeChat semantics).\n * Same storage/reactivity pattern as chat-drafts. */\n\nconst STORE_KEY = 'anet_chat_mute_v1';\nconst MUTE_EVENT = 'anet-chat-mute-updated';\n\nfunction readSet(): Set<string> {\n if (typeof window === 'undefined') return new Set();\n try {\n const parsed = JSON.parse(window.localStorage.getItem(STORE_KEY) || '[]');\n return new Set(Array.isArray(parsed) ? parsed : []);\n } catch {\n return new Set();\n }\n}\n\nexport function isMuted(alias?: string | null): boolean {\n if (!alias) return false;\n return readSet().has(alias);\n}\n\nexport function toggleMute(alias: string) {\n if (typeof window === 'undefined' || !alias) return;\n try {\n const s = readSet();\n if (s.has(alias)) s.delete(alias);\n else s.add(alias);\n window.localStorage.setItem(STORE_KEY, JSON.stringify([...s]));\n window.dispatchEvent(new Event(MUTE_EVENT));\n } catch {}\n}\n\nlet version = 0;\nfunction subscribe(callback: () => void) {\n const bump = () => { version++; callback(); };\n window.addEventListener(MUTE_EVENT, bump);\n window.addEventListener('storage', bump);\n return () => {\n window.removeEventListener(MUTE_EVENT, bump);\n window.removeEventListener('storage', bump);\n };\n}\n\nexport function useMuted(alias?: string | null): boolean {\n return useSyncExternalStore(subscribe, () => (alias ? isMuted(alias) : false), () => false);\n}\n\n/** Monotonic version for callers that use plain isMuted() inside render\n * loops (map callbacks can't call hooks). */\nexport function useMuteVersion(): number {\n return useSyncExternalStore(subscribe, () => version, () => 0);\n}\n","import { useEffect } from 'react';\nimport { hydrateHubAvatars } from './avatars';\nimport useSWR from 'swr';\nimport { Session, Health, AnetConfig } from '../components/types';\nimport { useNetworkId } from './network-context';\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nconst SWR_OPTIONS = { refreshInterval: 5000, dedupingInterval: 3000 };\n\n/** Append network_id to URL if set */\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function useSessions() {\n const { networkId } = useNetworkId();\n const { data, error, isLoading } = useSWR<{ sessions: Session[]; _hint?: { global_count?: number; filtered_network?: string } }>(\n withNetwork('/api/hub/status', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return { sessions: data?.sessions || [], hint: data?._hint, error, isLoading };\n}\n\n// RFC-027 PR2 — alias → lifecycle_state map sourced from /api/nodes\n// (commhub-server preview.12+). /api/status reads from `sessions` which\n// doesn't carry lifecycle_state; /api/nodes does. Cheap secondary\n// fetch, same SWR cadence as useSessions; merged client-side by alias.\n// Absent alias → caller defaults to 'active'.\ninterface NodeAttrsSnapshot {\n display_name: string | null;\n team: string | null;\n tags: string[];\n attrs_revision: number;\n}\ninterface NodesResp { nodes?: Array<{\n alias?: string;\n node_id?: string;\n lifecycle_state?: string | null;\n // #492 goal-item-3: node display attributes (hub PR #497). Legacy\n // rows read as null/[]/0 respectively — no guard needed by callers.\n display_name?: string | null;\n team?: string | null;\n tags?: string[];\n attrs_revision?: number;\n // avatar 接线单: cross-device custom avatar (hub #462 projection)\n avatar_url?: string | null;\n}>; }\nexport function useNodeLifecycle() {\n const { networkId } = useNetworkId();\n const { data, error, mutate } = useSWR<NodesResp>(\n withNetwork('/api/hub/nodes', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n // avatar 接线单: every consumer of this hook keeps the avatar layer-1\n // store fresh. Effect (not render): hydrate dispatches an event that\n // re-renders avatar consumers — doing that mid-render would warn.\n useEffect(() => { hydrateHubAvatars(data?.nodes); }, [data]);\n const lifecycleByAlias: Record<string, string> = {};\n const nodeIdByAlias: Record<string, string> = {};\n const attrsByAlias: Record<string, NodeAttrsSnapshot> = {};\n for (const n of data?.nodes ?? []) {\n if (n.alias && typeof n.lifecycle_state === 'string') lifecycleByAlias[n.alias] = n.lifecycle_state;\n if (n.alias && typeof n.node_id === 'string') nodeIdByAlias[n.alias] = n.node_id;\n if (n.alias) {\n attrsByAlias[n.alias] = {\n display_name: typeof n.display_name === 'string' ? n.display_name : null,\n team: typeof n.team === 'string' ? n.team : null,\n tags: Array.isArray(n.tags) ? n.tags : [],\n attrs_revision: typeof n.attrs_revision === 'number' ? n.attrs_revision : 0,\n };\n }\n }\n return { lifecycleByAlias, nodeIdByAlias, attrsByAlias, error, refreshNodes: mutate };\n}\nexport type { NodeAttrsSnapshot };\n\nexport function useHealth() {\n const { data, error } = useSWR<Health>('/api/hub/health', fetcher, SWR_OPTIONS);\n return { health: data || null, error };\n}\n\nexport function useAnetConfig() {\n const { data } = useSWR<AnetConfig>('/api/anet/config', fetcher, { refreshInterval: 30000 });\n return { config: data || null };\n}\n\nexport function useTasks(params?: Record<string, string>) {\n const { networkId } = useNetworkId();\n const query = new URLSearchParams({ limit: '100', ...params }).toString();\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/tasks?${query}`, networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return {\n tasks: data?.tasks || [],\n count: data?.count ?? 0,\n source: data?.source,\n error,\n isLoading,\n };\n}\n\nexport function useStats() {\n const { networkId } = useNetworkId();\n const { data, error } = useSWR(withNetwork('/api/hub/stats', networkId), fetcher, SWR_OPTIONS);\n return { stats: data?.ok ? data : null, error };\n}\n\nexport function useMessages(limit = 100) {\n const { networkId } = useNetworkId();\n // keepPreviousData: /messages grows `limit` when the user asks for older\n // history (#217 M5) — without it the key change would blank the list and\n // flash the skeleton while the bigger page is in flight.\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/messages?limit=${limit}`, networkId),\n fetcher,\n { ...SWR_OPTIONS, keepPreviousData: true },\n );\n return { messages: data?.messages || [], error, isLoading };\n}\n","'use client';\n\nimport { createContext, useContext, useState, useEffect, ReactNode } from 'react';\n\ninterface NetworkContextType {\n networkId: string;\n setNetworkId: (id: string) => void;\n}\n\nconst NetworkContext = createContext<NetworkContextType>({ networkId: '', setNetworkId: () => {} });\n\nexport function NetworkProvider({ children }: { children: ReactNode }) {\n const [networkId, setNetworkId] = useState('');\n\n useEffect(() => {\n const saved = sessionStorage.getItem('anet_network_id');\n // Hydration-safe restore (see UserBar note).\n // eslint-disable-next-line react-hooks/set-state-in-effect\n if (saved) { setNetworkId(saved); return; }\n // No prior selection: auto-select the user's first/default network so\n // network-scoped pages (e.g. /scheduled-tasks) don't dead-end on a\n // \"请先在左侧选择一个网络\" error and hide existing schedules/nodes when\n // the user has exactly one network. Persist so it's stable this session.\n let cancelled = false;\n fetch('/api/hub/networks', { cache: 'no-store' })\n .then(r => (r.ok ? r.json() : { networks: [] }))\n .then((d: { networks?: { network_id?: string; network_name?: string }[] }) => {\n if (cancelled) return;\n const list = Array.isArray(d.networks) ? d.networks : [];\n const pick = list.find(n => n.network_name === 'default') || list[0];\n const id = pick?.network_id;\n if (id) {\n setNetworkId(id);\n try { sessionStorage.setItem('anet_network_id', id); } catch { /* ignore */ }\n }\n })\n .catch(() => { /* leave unselected; page shows its own prompt */ });\n return () => { cancelled = true; };\n }, []);\n\n const setAndPersist = (id: string) => {\n setNetworkId(id);\n sessionStorage.setItem('anet_network_id', id);\n };\n\n return (\n <NetworkContext.Provider value={{ networkId, setNetworkId: setAndPersist }}>\n {children}\n </NetworkContext.Provider>\n );\n}\n\nexport function useNetworkId() {\n return useContext(NetworkContext);\n}\n","// #515 / #53: single source of truth for \"is this node online?\" across\n// stats card / sidebar count / topology halos / chat popover / task\n// panel @-mention picker. If you add a new place that decides \"online\"\n// vs \"offline\", import isOnline() from here — don't roll your own.\n//\n// Definition: **SSE-reachable with at least one live connection**.\n// Adopted by #214 F2 (originally in app/page.tsx). Consolidated here so\n// consumers never disagree.\n//\n// Why `> 0` and not `!== undefined`:\n// - Hub `getSSEStats()` writes `sessions[name] = arr.length` and the\n// three removal paths (cancel, rekey, dead-pushEvent) each `delete`\n// the key when the array empties. So on the current hub the value\n// is never `0` — but this JSON comes from a hub whose version this\n// dashboard doesn't control (see the legacy alias-only fallback\n// below for the version we already know we support), so treating\n// the map defensively costs nothing and keeps the definition\n// pointing the same direction #214 F2 took: SSE-reachable = \"can I\n// talk to it right now\", and a zero-count row is not that.\n// - `!!sseLookup(s)` in the old page.tsx also treated 0 as false;\n// preserving that keeps this a pure refactor for page.tsx.\n//\n// SSE keys in health.sse_sessions are `network_id:alias` since v0.7+\n// (per-network scoping). Legacy fallback: bare alias.\n\nexport type SseSessionsMap = Record<string, unknown>;\n\nexport type PresenceSubject = {\n alias: string;\n network_id?: string;\n};\n\nexport function sseCountFor(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): number | undefined {\n if (!sseSessions) return undefined;\n const scoped = session.network_id ? sseSessions[`${session.network_id}:${session.alias}`] : undefined;\n const value = (scoped ?? sseSessions[session.alias]) as number | undefined;\n return typeof value === 'number' ? value : undefined;\n}\n\nexport function isOnline(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): boolean {\n const n = sseCountFor(session, sseSessions);\n return typeof n === 'number' && n > 0;\n}\n\n// -----------------------------------------------------------------------\n// #53: three-state ambient presence signal.\n//\n// `sse_sessions` on hub's /health is **auth-gated** (post `#495-followup`\n// / `f28a6c1b`): an anonymous or wrong-scope caller gets the field\n// **completely omitted** — indistinguishable at the JSON level from\n// \"no nodes connected\".\n//\n// If we hand that state to isOnline() and only render numbers, the UI\n// shows a confident, consistent, and *wrong* 0 online everywhere and\n// the \"three sites disagree\" signal #515 used to have — which was\n// itself the clue that something upstream was broken — is gone.\n//\n// So callers need to distinguish three cases:\n//\n// 'ready' — sseSessions is present (even if empty {}). Trust the\n// count. `filter(isOnline).length` is the answer.\n// 'blind' — sseSessions is absent but hub `sse_connections > 0`.\n// Two fields contradict → we are seeing an anonymized\n// view. Do NOT render \"0 online\"; render an alert.\n// 'loading' — sseSessions is absent and no positive contradiction\n// (either health hasn't loaded, or hub reports 0\n// connections and no map). Render a placeholder — don't\n// inflate the count, but don't cry wolf either.\n//\n// Callers that render user-visible counts MUST branch on this. Callers\n// that just need a per-node boolean (halos, chat-popover badges) can\n// stay on isOnline() — those degrade gracefully to \"everyone offline\"\n// which is the safer visual, while the ambient banner handles the\n// \"why\".\n// -----------------------------------------------------------------------\n\nexport type PresenceStatus = 'ready' | 'blind' | 'loading';\n\nexport type HealthShape = {\n sse_connections?: number;\n} | null | undefined;\n\nexport function presenceStatus(\n sseSessions: SseSessionsMap | undefined,\n health: HealthShape,\n): PresenceStatus {\n if (sseSessions !== undefined) return 'ready';\n // sseSessions is absent. Are we blind or truly empty/loading?\n const conns = health && typeof health.sse_connections === 'number' ? health.sse_connections : 0;\n // The contradiction case — hub says there are connections but the\n // map isn't in this response — is the strongest \"you're anonymous\"\n // signal we have.\n if (conns > 0) return 'blind';\n // No map AND hub reports 0 connections (or health hasn't loaded).\n // Both look identical to us, and both should render placeholders,\n // not \"0 online\" numbers. Conservative default = 'loading'.\n return 'loading';\n}\n","/** Shared timestamp helpers for hub-sourced data.\n *\n * Background — the CommHub serialises timestamps SQL-style without a\n * zone (\"2026-05-15 06:00:28\"), but some test data uses full ISO\n * (\"…T06:00:28Z\"). `Date.parse` on bare SQL is **local-time** in every\n * browser the dashboard supports, so a UTC+8 operator silently sees\n * every timestamp 8 h older than reality (Round 35 dug this out via\n * the `isGhost` filter mis-fire).\n *\n * Round 38 / Loop consolidates parsing — TopoGraph (R35), ChatPopover\n * (R37) and utils.ts::timeAgo all mirrored the same SQL→UTC rewrite;\n * one source of truth here. */\n\n/** Parse a hub timestamp to ms-since-epoch, treating SQL-style strings\n * as UTC. ISO strings (with `T`) bypass the rewrite and are parsed as-is.\n * Returns null for empty / unparseable input. */\nexport function parseHubTime(dateStr: string | null | undefined): number | null {\n if (!dateStr) return null;\n const iso = dateStr.includes('T') ? dateStr : dateStr.replace(' ', 'T') + 'Z';\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n}\n\n/** Format `dateStr` as a short relative-time string (\"6m ago\" / \"2h ago\").\n * Future timestamps (clock skew) collapse to \"just now\". Returns null when\n * the input doesn't parse — callers can decide on a fallback. */\nexport function relativeAgo(dateStr: string | null | undefined): string | null {\n const t = parseHubTime(dateStr);\n if (t === null) return null;\n const s = Math.floor((Date.now() - t) / 1000);\n if (s < 0) return 'just now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n if (s < 86400) return `${Math.floor(s / 3600)}h ago`;\n return `${Math.floor(s / 86400)}d ago`;\n}\n\n/** Loop R7 (跨面一致性): WeChat-style contextual timestamp shared by the\n * chat panel (R3) and /messages dividers. zh locales keep the native\n * wording (昨天/星期X); others get Intl output (\"Yesterday\"/\"Tue\").\n * Today → \"14:32\" · yesterday → \"昨天 14:32\" · <7d → \"星期二 14:32\" ·\n * this year → \"7月16日 14:32\" · older adds the year. */\nexport function formatWeChatTime(value: string | null | undefined): string {\n const t = parseHubTime(value);\n if (t === null) return '';\n const d = new Date(t);\n const now = new Date();\n const zh = typeof navigator !== 'undefined' && (navigator.language || '').toLowerCase().startsWith('zh');\n const hm = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n const startOfDay = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const dayDiff = Math.round((startOfDay(now) - startOfDay(d)) / 86400000);\n if (dayDiff === 0) return hm;\n if (dayDiff === 1) return zh ? `昨天 ${hm}` : `Yesterday ${hm}`;\n if (dayDiff > 1 && dayDiff < 7) {\n const wd = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, { weekday: zh ? 'long' : 'short' }).format(d);\n return `${wd} ${hm}`;\n }\n const md = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, {\n month: zh ? 'long' : 'short', day: 'numeric',\n ...(d.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n }).format(d);\n return `${md} ${hm}`;\n}\n"],"names":["STORE_KEY","AVATAR_EVENT","hubMap","hubNodeAliases","Set","hubMapKey","hydrateHubAvatars","nodes","next","nextAliases","n","alias","add","avatar_url","key","JSON","stringify","sort","join","manifest","pool","manifestRequested","poolPick","length","h","i","charCodeAt","fetchManifestOnce","readMap","getAvatarUrl","has","setAvatarUrl","url","version","subscribe","callback","bump","window","addEventListener","removeEventListener","useAvatarsVersion","useAvatarUrl","CHAT_OUTBOX_PREFIX","CHAT_DRAFT_PREFIX","LEGACY_PRIVATE_PREFIXES","AUTH_KEY","MAX_ENTRIES","MAX_CONTENT_BYTES","OUTBOX_TTL_MS","chatPrivateScope","networkId","session","undefined","auth","parse","getItem","identity","user","user_id","username","network","currentNetwork","encodeURIComponent","clearPrivateChatStorage","storage","removed","keys","index","startsWith","some","prefix","push","removeItem","valid","entry","e","requestId","test","localTaskId","panelAlias","targetAlias","content","TextEncoder","encode","byteLength","priority","createdAt","storageKey","scope","readChatOutbox","now","Date","parsed","Array","isArray","live","filter","created","Number","isFinite","slice","write","entries","setItem","putChatOutbox","item","removeChatOutbox","chatOutboxForAlias","MUTE_EVENT","readSet","isMuted","toggleMute","useMuted","useMuteVersion","fetcher","res","fetch","status","location","assign","Error","json","SWR_OPTIONS","refreshInterval","dedupingInterval","withNetwork","sep","includes","useSessions","data","error","isLoading","sessions","hint","_hint","useNodeLifecycle","mutate","lifecycleByAlias","nodeIdByAlias","attrsByAlias","lifecycle_state","node_id","display_name","team","tags","attrs_revision","refreshNodes","useHealth","health","useAnetConfig","config","useTasks","params","query","URLSearchParams","limit","toString","tasks","count","source","useStats","stats","ok","useMessages","keepPreviousData","messages","NetworkContext","setNetworkId","NetworkProvider","children","saved","sessionStorage","cancelled","cache","then","r","networks","d","list","pick","find","network_name","id","network_id","catch","setAndPersist","Provider","value","useNetworkId","sseCountFor","sseSessions","scoped","isOnline","presenceStatus","conns","sse_connections","parseHubTime","dateStr","iso","replace","t","relativeAgo","s","Math","floor","formatWeChatTime","zh","navigator","language","toLowerCase","hm","String","getHours","padStart","getMinutes","startOfDay","x","getFullYear","getMonth","getDate","getTime","dayDiff","round","wd","Intl","DateTimeFormat","weekday","format","md","month","day","year"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../app/lib/avatars.ts","../../../../app/lib/chat-outbox.ts","../../../../app/lib/chat-unread.ts","../../../../app/lib/chat-mute.ts","../../../../app/lib/hooks.ts","../../../../app/lib/network-context.tsx","../../../../app/lib/presence.ts","../../../../app/lib/time.ts"],"sourcesContent":["'use client';\n\nimport { useSyncExternalStore } from 'react';\n\n/* Loop R24 (Vincent 亲点: 头像换血) — custom avatar infrastructure.\n *\n * Resolution order, per alias (通信龙 裁定, avatar 接线单 07-31):\n * 1. hub avatar_url — nodes.avatar_url via GET /api/hub/nodes, hydrated\n * by useNodeLifecycle → hydrateHubAvatars(). The hub is the\n * CROSS-DEVICE truth, so it sits ABOVE localStorage (which is only a\n * per-browser cache); the pre-wiring order caused the \"改了头像别人\n * 看不到\" stuck-avatar report.\n * Evidence the hub side exists (this comment previously claimed it\n * didn't — that stale claim is WHY nobody wired this for weeks):\n * hub #462 shipped PUT /api/nodes/:ref/avatar (server.ts:2477,\n * validated by avatar-validate.ts) + nodes.avatar_url column\n * (db.ts:346) + the GET projection (server.ts:2784).\n * 2. user override — localStorage map, set in the node settings UI\n * (which now ALSO PUTs to the hub; localStorage is the echo)\n * 3. designed default — /avatars/manifest.json (static, alias → URL)\n * 4. shared pool — manifest \"_pool\"; stable djb2 pick per alias\n * 5. '' → caller falls back to the hue-hashed initial pill\n */\n\nconst STORE_KEY = 'anet_avatars_v1';\nconst AVATAR_EVENT = 'anet-avatars-updated';\n\nlet hubMap: Record<string, string> = {};\n/** Aliases that HAVE a nodes row — for them the hub is the whole truth,\n * INCLUDING \"cleared\" (avatar_url null): a stale localStorage override on\n * another device must not resurrect the old picture (clear-consistency\n * gap, #72 review follow-up / 通信龙 批准). Session-only aliases keep\n * localStorage as their only personalization. */\nlet hubNodeAliases: Set<string> = new Set();\nlet hubMapKey = ''; // change detector — avoid event storms on every poll\n\n/** Feed nodes from GET /api/hub/nodes into the resolution chain (layer 1).\n * Cheap to call on every SWR poll: only dispatches when content changed. */\nexport function hydrateHubAvatars(nodes: Array<{ alias?: string; avatar_url?: string | null }> | undefined) {\n if (!nodes) return;\n const next: Record<string, string> = {};\n const nextAliases = new Set<string>();\n for (const n of nodes) {\n if (!n.alias) continue;\n nextAliases.add(n.alias);\n if (typeof n.avatar_url === 'string' && n.avatar_url) next[n.alias] = n.avatar_url;\n }\n const key = JSON.stringify(next) + '|' + [...nextAliases].sort().join(',');\n if (key === hubMapKey) return;\n hubMapKey = key;\n hubMap = next;\n hubNodeAliases = nextAliases;\n if (typeof window !== 'undefined') window.dispatchEvent(new Event(AVATAR_EVENT));\n}\n\nlet manifest: Record<string, string> | null = null;\nlet pool: string[] = [];\nlet manifestRequested = false;\n\n/* Stable per-alias index so a given agent keeps the same pool avatar across\n * sessions/devices (djb2 over code units — no Math.random, no ordering). */\nfunction poolPick(alias: string): string {\n if (!pool.length) return '';\n let h = 5381;\n for (let i = 0; i < alias.length; i++) h = ((h << 5) + h + alias.charCodeAt(i)) >>> 0;\n return pool[h % pool.length];\n}\n\nfunction fetchManifestOnce() {\n if (manifestRequested || typeof window === 'undefined') return;\n manifestRequested = true;\n fetch('/avatars/manifest.json', { cache: 'no-cache' })\n .then((r) => (r.ok ? r.json() : null))\n .then((j) => {\n if (j && typeof j === 'object' && !Array.isArray(j)) {\n const clean: Record<string, string> = {};\n for (const [k, v] of Object.entries(j as Record<string, unknown>)) {\n if (k.startsWith('_')) continue; // meta keys (\"_pool\", …)\n if (typeof v === 'string' && v.startsWith('/')) clean[k] = v;\n }\n const rawPool = (j as Record<string, unknown>)._pool;\n pool = Array.isArray(rawPool)\n ? rawPool.filter((p): p is string => typeof p === 'string' && p.startsWith('/'))\n : [];\n manifest = clean;\n window.dispatchEvent(new Event(AVATAR_EVENT));\n }\n })\n .catch(() => {});\n}\n\nfunction readMap(): Record<string, string> {\n if (typeof window === 'undefined') return {};\n try {\n const parsed = JSON.parse(window.localStorage.getItem(STORE_KEY) || '{}');\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n}\n\nexport function getAvatarUrl(alias?: string | null): string {\n if (!alias) return '';\n // Node-backed: hub authority — its value, or (when cleared/none) the\n // designed default chain, SKIPPING localStorage entirely.\n if (hubNodeAliases.has(alias)) {\n return hubMap[alias] || manifest?.[alias] || poolPick(alias) || '';\n }\n // Session-only: localStorage is the only personalization layer.\n return readMap()[alias] || manifest?.[alias] || poolPick(alias) || '';\n}\n\n/** Empty/whitespace url removes the override (falls back to manifest/pill). */\nexport function setAvatarUrl(alias: string, url: string) {\n if (typeof window === 'undefined' || !alias) return;\n try {\n const m = readMap();\n if (url.trim()) m[alias] = url.trim();\n else delete m[alias];\n window.localStorage.setItem(STORE_KEY, JSON.stringify(m));\n window.dispatchEvent(new Event(AVATAR_EVENT));\n } catch {}\n}\n\nlet version = 0;\nfunction subscribe(callback: () => void) {\n fetchManifestOnce();\n const bump = () => { version++; callback(); };\n window.addEventListener(AVATAR_EVENT, bump);\n window.addEventListener('storage', bump);\n return () => {\n window.removeEventListener(AVATAR_EVENT, bump);\n window.removeEventListener('storage', bump);\n };\n}\n\n/** Monotonic version for callers that resolve many aliases via plain\n * getAvatarUrl() inside render loops (map callbacks can't call hooks —\n * same idiom as chat-mute's useMuteVersion). Subscribing also kicks off\n * the lazy manifest fetch and re-renders the caller when it lands. */\nexport function useAvatarsVersion(): number {\n return useSyncExternalStore(subscribe, () => version, () => 0);\n}\n\nexport function useAvatarUrl(alias?: string | null): string {\n return useSyncExternalStore(subscribe, () => getAvatarUrl(alias), () => '');\n}\n","'use client';\n\nexport const CHAT_OUTBOX_PREFIX = 'anet_chat_outbox_v2:';\nexport const CHAT_DRAFT_PREFIX = 'anet_chat_draft_v2:';\nconst LEGACY_PRIVATE_PREFIXES = ['anet_chat_outbox_v1', 'anet_chat_draft_v1:'];\nconst AUTH_KEY = 'anet_v3_auth';\nconst MAX_ENTRIES = 100;\nconst MAX_CONTENT_BYTES = 32 * 1024;\nconst OUTBOX_TTL_MS = 24 * 60 * 60 * 1000;\n\n/** Scope plaintext chat recovery data to the authenticated user and network.\n * If the client has no trustworthy identity snapshot, persistence is disabled. */\nexport function chatPrivateScope(\n networkId?: string | null,\n session: Storage | undefined = typeof window === 'undefined' ? undefined : window.sessionStorage,\n): string | null {\n if (!session) return null;\n try {\n const auth = JSON.parse(session.getItem(AUTH_KEY) || 'null');\n const identity = auth?.user?.user_id || auth?.user?.username;\n const network = networkId || session.getItem('anet_network_id') || auth?.currentNetwork;\n if (typeof identity !== 'string' || !identity || typeof network !== 'string' || !network) return null;\n return `${encodeURIComponent(identity)}:${encodeURIComponent(network)}`;\n } catch {\n return null;\n }\n}\n\n/** Explicit logout removes every account/network shard and legacy plaintext. */\nexport function clearPrivateChatStorage(\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n): number {\n if (!storage) return 0;\n let removed = 0;\n try {\n const keys: string[] = [];\n for (let index = 0; index < storage.length; index += 1) {\n const key = storage.key(index);\n if (key && (\n key.startsWith(CHAT_OUTBOX_PREFIX)\n || key.startsWith(CHAT_DRAFT_PREFIX)\n || LEGACY_PRIVATE_PREFIXES.some(prefix => key.startsWith(prefix))\n )) keys.push(key);\n }\n for (const key of keys) {\n storage.removeItem(key);\n removed += 1;\n }\n } catch {\n // Storage errors must not block logout.\n }\n return removed;\n}\n\nexport interface ChatOutboxEntry {\n requestId: string;\n localTaskId: string;\n panelAlias: string;\n targetAlias: string;\n content: string;\n priority: string;\n networkId: string;\n createdAt: string;\n}\n\nfunction valid(entry: unknown): entry is ChatOutboxEntry {\n if (!entry || typeof entry !== 'object') return false;\n const e = entry as Partial<ChatOutboxEntry>;\n return typeof e.requestId === 'string' && /^dreq_[A-Za-z0-9_-]{16,96}$/.test(e.requestId)\n && typeof e.localTaskId === 'string'\n && typeof e.panelAlias === 'string'\n && typeof e.targetAlias === 'string'\n && typeof e.content === 'string' && new TextEncoder().encode(e.content).byteLength <= MAX_CONTENT_BYTES\n && typeof e.priority === 'string'\n && typeof e.networkId === 'string'\n && typeof e.createdAt === 'string';\n}\n\nfunction storageKey(scope: string) { return CHAT_OUTBOX_PREFIX + scope; }\n\nexport function readChatOutbox(\n scope: string | null = chatPrivateScope(),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n now = Date.now(),\n): ChatOutboxEntry[] {\n if (!storage || !scope) return [];\n try {\n const parsed = JSON.parse(storage.getItem(storageKey(scope)) || '[]');\n if (!Array.isArray(parsed)) return [];\n const live = parsed.filter(valid).filter(entry => {\n const created = Date.parse(entry.createdAt);\n return Number.isFinite(created) && created <= now && now - created <= OUTBOX_TTL_MS;\n }).slice(-MAX_ENTRIES);\n // TTL is a storage lifecycle, not merely a display filter: erase expired,\n // malformed, and oversized plaintext opportunistically on every read.\n if (live.length !== parsed.length) write(storage, scope, live);\n return live;\n } catch {\n return [];\n }\n}\n\nfunction write(storage: Storage, scope: string, entries: ChatOutboxEntry[]): boolean {\n try {\n storage.setItem(storageKey(scope), JSON.stringify(entries.slice(-MAX_ENTRIES)));\n return true;\n } catch {\n // Storage can be disabled, full, or unavailable in a privacy-restricted\n // webview. The outbox is a recovery enhancement and must never prevent\n // the actual network send.\n return false;\n }\n}\n\nexport function putChatOutbox(\n entry: ChatOutboxEntry,\n scope: string | null = chatPrivateScope(entry.networkId),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n) {\n if (!storage || !scope || !valid(entry)) return false;\n const next = readChatOutbox(scope, storage).filter(item => item.requestId !== entry.requestId);\n next.push(entry);\n return write(storage, scope, next);\n}\n\nexport function removeChatOutbox(\n requestId: string,\n scope: string | null = chatPrivateScope(),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n) {\n if (!storage || !scope) return false;\n return write(storage, scope, readChatOutbox(scope, storage).filter(item => item.requestId !== requestId));\n}\n\nexport function chatOutboxForAlias(\n alias: string,\n scope: string | null = chatPrivateScope(),\n storage: Storage | undefined = typeof window === 'undefined' ? undefined : window.localStorage,\n) {\n return readChatOutbox(scope, storage).filter(item => item.panelAlias === alias);\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport useSWR from 'swr';\nimport { useNetworkId } from './network-context';\nimport { isMuted, useMuteVersion } from './chat-mute';\n\nconst STORAGE_PREFIX = 'anet_chat_read_v1:';\nconst UNREAD_EVENT = 'anet-chat-read-updated';\n\ninterface ChatMessage {\n from_alias?: string | null;\n to_alias?: string | null;\n created_at?: string | null;\n}\n\n/** Senders/recipients that mean \"the dashboard user\" in hub data. The chat\n * panel uses the same set to decide which bubbles are \"You\". */\nconst USERISH = new Set(['', 'dashboard', 'admin', 'api', 'hub']);\nconst isUserish = (v?: string | null) => USERISH.has((v || '').trim().toLowerCase());\n\ninterface ReadMap {\n [alias: string]: string;\n}\n\nfunction storageKey(networkId: string) {\n return `${STORAGE_PREFIX}${networkId || 'global'}`;\n}\n\nfunction parseHubTime(value?: string | null): number {\n if (!value) return 0;\n const normalized = value.includes('T') ? value : value.replace(' ', 'T');\n const withZone = /Z$|[+-]\\d{2}:\\d{2}$/.test(normalized) ? normalized : `${normalized}Z`;\n const ts = Date.parse(withZone);\n return Number.isFinite(ts) ? ts : 0;\n}\n\n// Loop R8 (Vincent: 未读数字角标): last-read moved sessionStorage →\n// localStorage so read state survives refresh/new tabs/restart (微信预期).\n// One-time migration pulls any old session value forward.\nconst BASELINE_KEY = '__baseline';\n\nfunction readStoredMap(networkId: string): ReadMap {\n if (typeof window === 'undefined') return {};\n try {\n let raw = window.localStorage.getItem(storageKey(networkId));\n if (!raw) {\n raw = window.sessionStorage.getItem(storageKey(networkId));\n if (raw) window.localStorage.setItem(storageKey(networkId), raw);\n }\n const parsed = raw ? JSON.parse(raw) : {};\n const map: ReadMap = parsed && typeof parsed === 'object' ? parsed : {};\n // R8 first-visit floor, written SYNCHRONOUSLY on first read: an async\n // (useEffect) baseline lost the race against the first SWR render and\n // let a badge storm flash — and stick, since nothing re-triggered the\n // count. Ensuring it here means no compute can ever see a missing\n // baseline. No event dispatch: every hook instance does the same\n // idempotent write.\n if (!map[BASELINE_KEY]) {\n map[BASELINE_KEY] = new Date().toISOString();\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(map));\n }\n return map;\n } catch {\n return {};\n }\n}\n\nfunction writeStoredMap(networkId: string, next: ReadMap) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey(networkId), JSON.stringify(next));\n window.dispatchEvent(new CustomEvent(UNREAD_EVENT, { detail: { networkId } }));\n } catch {}\n}\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function markChatRead(alias: string, networkId: string) {\n if (!alias) return;\n const current = readStoredMap(networkId);\n writeStoredMap(networkId, {\n ...current,\n [alias]: new Date().toISOString(),\n });\n}\n\nexport function useChatUnread() {\n const { networkId } = useNetworkId();\n // Messages are the ONLY count source: the hub mirrors every task reply as\n // a message to the originator (verified live: replied task + same-second\n // message, both present), so counting tasks too double-counted every\n // reply (E2E showed 4 where 2 was right).\n const { data: messagesData } = useSWR<{ messages?: ChatMessage[] }>(\n withNetwork('/api/hub/messages?limit=200', networkId),\n fetcher,\n { refreshInterval: 5000, dedupingInterval: 3000 },\n );\n const [readVersion, setReadVersion] = useState(0);\n\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key && event.key !== storageKey(networkId)) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n const onUnreadUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ networkId?: string }>).detail;\n if (detail?.networkId !== undefined && detail.networkId !== networkId) return;\n setReadVersion((v) => (typeof v === 'number' ? v + 1 : 1));\n };\n window.addEventListener('storage', onStorage);\n window.addEventListener(UNREAD_EVENT, onUnreadUpdate);\n return () => {\n window.removeEventListener('storage', onStorage);\n window.removeEventListener(UNREAD_EVENT, onUnreadUpdate);\n };\n }, [networkId, setReadVersion]);\n\n const readMap = useMemo(() => {\n void readVersion;\n return readStoredMap(networkId);\n }, [networkId, readVersion]);\n\n const unreadMap = useMemo(() => {\n // R8: count EVERY unread item per alias (Vincent: \"有几条消息显示数字\"),\n // not just a latest-activity boolean. A message from the alias counts;\n // a task's REPLY counts once when it lands after last-read. Self-sent\n // items never count (they're keyed by the counterpart alias).\n const counts = new Map<string, number>();\n // R28 (微信排序): recency tiebreak for Overview/Nodes — but ONLY for\n // conversations the user has actually OPENED (read-map entry). On this\n // fleet agents constantly report to 'admin'; counting those yanked\n // never-opened agents to the front on every report (measured: 2 cards\n // jumped 39→1 / 60→3 in one 6s window). WeChat's list holds YOUR\n // conversations — same rule here keeps the grid calm.\n const lastActivity = new Map<string, number>();\n const opened = new Set(Object.keys(readMap).filter((k) => k !== BASELINE_KEY));\n const baseline = parseHubTime(readMap[BASELINE_KEY]);\n const bump = (alias: string, at: number) => {\n if (opened.has(alias) && at > (lastActivity.get(alias) || 0)) lastActivity.set(alias, at);\n const readAt = Math.max(parseHubTime(readMap[alias]), baseline);\n if (at > readAt) counts.set(alias, (counts.get(alias) || 0) + 1);\n };\n // Scope: only the USER'S conversation — a badge on X means \"X has\n // something FOR YOU\". Fleet chatter (X's messages to other agents)\n // must NOT inflate it.\n for (const message of messagesData?.messages || []) {\n const alias = message.from_alias?.trim();\n if (!alias || isUserish(alias)) continue; // own sends never count\n if (!isUserish(message.to_alias)) continue; // must be addressed to the user\n const at = parseHubTime(message.created_at);\n if (at) bump(alias, at);\n }\n return { counts, lastActivity };\n }, [messagesData, readMap]);\n\n const hasUnread = useCallback((alias?: string | null) => {\n if (!alias) return false;\n return (unreadMap.counts.get(alias) || 0) > 0;\n }, [unreadMap]);\n\n const unreadCount = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.counts.get(alias) || 0;\n }, [unreadMap]);\n\n const lastActivityAt = useCallback((alias?: string | null) => {\n if (!alias) return 0;\n return unreadMap.lastActivity.get(alias) || 0;\n }, [unreadMap]);\n\n // R34: muted conversations are excluded from the global count (WeChat\n // semantics); hasMutedUnread lets entry badges fall back to a dot.\n const muteVersion = useMuteVersion();\n const { totalUnread, hasMutedUnread } = useMemo(() => {\n void muteVersion;\n let t = 0;\n let mutedAny = false;\n for (const [alias, n] of unreadMap.counts) {\n if (isMuted(alias)) { if (n > 0) mutedAny = true; continue; }\n t += n;\n }\n return { totalUnread: t, hasMutedUnread: mutedAny };\n }, [unreadMap, muteVersion]);\n\n const clearUnread = useCallback((alias: string) => {\n markChatRead(alias, networkId);\n }, [networkId]);\n\n return { unreadMap, hasUnread, unreadCount, lastActivityAt, totalUnread, hasMutedUnread, clearUnread };\n}\n\n/** WeChat badge label: 1-99 as-is, above → \"99+\"; 0/negative → '' (hide). */\nexport function badgeLabel(n: number): string {\n if (n <= 0) return '';\n return n > 99 ? '99+' : String(n);\n}\n","'use client';\n\nimport { useSyncExternalStore } from 'react';\n\n/* Loop R34 (微信消息免打扰, 克制版): per-conversation mute. Muted\n * conversations keep their red badge but show a DOT instead of the count,\n * and their unreads are excluded from the global total (WeChat semantics).\n * Same storage/reactivity pattern as chat-drafts. */\n\nconst STORE_KEY = 'anet_chat_mute_v1';\nconst MUTE_EVENT = 'anet-chat-mute-updated';\n\nfunction readSet(): Set<string> {\n if (typeof window === 'undefined') return new Set();\n try {\n const parsed = JSON.parse(window.localStorage.getItem(STORE_KEY) || '[]');\n return new Set(Array.isArray(parsed) ? parsed : []);\n } catch {\n return new Set();\n }\n}\n\nexport function isMuted(alias?: string | null): boolean {\n if (!alias) return false;\n return readSet().has(alias);\n}\n\nexport function toggleMute(alias: string) {\n if (typeof window === 'undefined' || !alias) return;\n try {\n const s = readSet();\n if (s.has(alias)) s.delete(alias);\n else s.add(alias);\n window.localStorage.setItem(STORE_KEY, JSON.stringify([...s]));\n window.dispatchEvent(new Event(MUTE_EVENT));\n } catch {}\n}\n\nlet version = 0;\nfunction subscribe(callback: () => void) {\n const bump = () => { version++; callback(); };\n window.addEventListener(MUTE_EVENT, bump);\n window.addEventListener('storage', bump);\n return () => {\n window.removeEventListener(MUTE_EVENT, bump);\n window.removeEventListener('storage', bump);\n };\n}\n\nexport function useMuted(alias?: string | null): boolean {\n return useSyncExternalStore(subscribe, () => (alias ? isMuted(alias) : false), () => false);\n}\n\n/** Monotonic version for callers that use plain isMuted() inside render\n * loops (map callbacks can't call hooks). */\nexport function useMuteVersion(): number {\n return useSyncExternalStore(subscribe, () => version, () => 0);\n}\n","import { useEffect } from 'react';\nimport { hydrateHubAvatars } from './avatars';\nimport useSWR from 'swr';\nimport { Session, Health, AnetConfig } from '../components/types';\nimport { useNetworkId } from './network-context';\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nconst SWR_OPTIONS = { refreshInterval: 5000, dedupingInterval: 3000 };\n\n/** Append network_id to URL if set */\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function useSessions() {\n const { networkId } = useNetworkId();\n const { data, error, isLoading } = useSWR<{ sessions: Session[]; _hint?: { global_count?: number; filtered_network?: string } }>(\n withNetwork('/api/hub/status', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return { sessions: data?.sessions || [], hint: data?._hint, error, isLoading };\n}\n\n// RFC-027 PR2 — alias → lifecycle_state map sourced from /api/nodes\n// (commhub-server preview.12+). /api/status reads from `sessions` which\n// doesn't carry lifecycle_state; /api/nodes does. Cheap secondary\n// fetch, same SWR cadence as useSessions; merged client-side by alias.\n// Absent alias → caller defaults to 'active'.\ninterface NodeAttrsSnapshot {\n display_name: string | null;\n team: string | null;\n tags: string[];\n attrs_revision: number;\n}\ninterface NodesResp { nodes?: Array<{\n alias?: string;\n node_id?: string;\n lifecycle_state?: string | null;\n // #492 goal-item-3: node display attributes (hub PR #497). Legacy\n // rows read as null/[]/0 respectively — no guard needed by callers.\n display_name?: string | null;\n team?: string | null;\n tags?: string[];\n attrs_revision?: number;\n // avatar 接线单: cross-device custom avatar (hub #462 projection)\n avatar_url?: string | null;\n}>; }\nexport function useNodeLifecycle() {\n const { networkId } = useNetworkId();\n const { data, error, mutate } = useSWR<NodesResp>(\n withNetwork('/api/hub/nodes', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n // avatar 接线单: every consumer of this hook keeps the avatar layer-1\n // store fresh. Effect (not render): hydrate dispatches an event that\n // re-renders avatar consumers — doing that mid-render would warn.\n useEffect(() => { hydrateHubAvatars(data?.nodes); }, [data]);\n const lifecycleByAlias: Record<string, string> = {};\n const nodeIdByAlias: Record<string, string> = {};\n const attrsByAlias: Record<string, NodeAttrsSnapshot> = {};\n for (const n of data?.nodes ?? []) {\n if (n.alias && typeof n.lifecycle_state === 'string') lifecycleByAlias[n.alias] = n.lifecycle_state;\n if (n.alias && typeof n.node_id === 'string') nodeIdByAlias[n.alias] = n.node_id;\n if (n.alias) {\n attrsByAlias[n.alias] = {\n display_name: typeof n.display_name === 'string' ? n.display_name : null,\n team: typeof n.team === 'string' ? n.team : null,\n tags: Array.isArray(n.tags) ? n.tags : [],\n attrs_revision: typeof n.attrs_revision === 'number' ? n.attrs_revision : 0,\n };\n }\n }\n return { lifecycleByAlias, nodeIdByAlias, attrsByAlias, error, refreshNodes: mutate };\n}\nexport type { NodeAttrsSnapshot };\n\nexport function useHealth() {\n const { data, error } = useSWR<Health>('/api/hub/health', fetcher, SWR_OPTIONS);\n return { health: data || null, error };\n}\n\nexport function useAnetConfig() {\n const { data } = useSWR<AnetConfig>('/api/anet/config', fetcher, { refreshInterval: 30000 });\n return { config: data || null };\n}\n\nexport function useTasks(params?: Record<string, string>) {\n const { networkId } = useNetworkId();\n const query = new URLSearchParams({ limit: '100', ...params }).toString();\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/tasks?${query}`, networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return {\n tasks: data?.tasks || [],\n count: data?.count ?? 0,\n source: data?.source,\n error,\n isLoading,\n };\n}\n\nexport function useStats() {\n const { networkId } = useNetworkId();\n const { data, error } = useSWR(withNetwork('/api/hub/stats', networkId), fetcher, SWR_OPTIONS);\n return { stats: data?.ok ? data : null, error };\n}\n\nexport function useMessages(limit = 100) {\n const { networkId } = useNetworkId();\n // keepPreviousData: /messages grows `limit` when the user asks for older\n // history (#217 M5) — without it the key change would blank the list and\n // flash the skeleton while the bigger page is in flight.\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/messages?limit=${limit}`, networkId),\n fetcher,\n { ...SWR_OPTIONS, keepPreviousData: true },\n );\n return { messages: data?.messages || [], error, isLoading };\n}\n","'use client';\n\nimport { createContext, useContext, useState, useEffect, ReactNode } from 'react';\n\ninterface NetworkContextType {\n networkId: string;\n setNetworkId: (id: string) => void;\n}\n\nconst NetworkContext = createContext<NetworkContextType>({ networkId: '', setNetworkId: () => {} });\n\nexport function NetworkProvider({ children }: { children: ReactNode }) {\n const [networkId, setNetworkId] = useState('');\n\n useEffect(() => {\n const saved = sessionStorage.getItem('anet_network_id');\n // Hydration-safe restore (see UserBar note).\n // eslint-disable-next-line react-hooks/set-state-in-effect\n if (saved) { setNetworkId(saved); return; }\n // No prior selection: auto-select the user's first/default network so\n // network-scoped pages (e.g. /scheduled-tasks) don't dead-end on a\n // \"请先在左侧选择一个网络\" error and hide existing schedules/nodes when\n // the user has exactly one network. Persist so it's stable this session.\n let cancelled = false;\n fetch('/api/hub/networks', { cache: 'no-store' })\n .then(r => (r.ok ? r.json() : { networks: [] }))\n .then((d: { networks?: { network_id?: string; network_name?: string }[] }) => {\n if (cancelled) return;\n const list = Array.isArray(d.networks) ? d.networks : [];\n const pick = list.find(n => n.network_name === 'default') || list[0];\n const id = pick?.network_id;\n if (id) {\n setNetworkId(id);\n try { sessionStorage.setItem('anet_network_id', id); } catch { /* ignore */ }\n }\n })\n .catch(() => { /* leave unselected; page shows its own prompt */ });\n return () => { cancelled = true; };\n }, []);\n\n const setAndPersist = (id: string) => {\n setNetworkId(id);\n sessionStorage.setItem('anet_network_id', id);\n };\n\n return (\n <NetworkContext.Provider value={{ networkId, setNetworkId: setAndPersist }}>\n {children}\n </NetworkContext.Provider>\n );\n}\n\nexport function useNetworkId() {\n return useContext(NetworkContext);\n}\n","// #515 / #53: single source of truth for \"is this node online?\" across\n// stats card / sidebar count / topology halos / chat popover / task\n// panel @-mention picker. If you add a new place that decides \"online\"\n// vs \"offline\", import isOnline() from here — don't roll your own.\n//\n// Definition: **SSE-reachable with at least one live connection**.\n// Adopted by #214 F2 (originally in app/page.tsx). Consolidated here so\n// consumers never disagree.\n//\n// Why `> 0` and not `!== undefined`:\n// - Hub `getSSEStats()` writes `sessions[name] = arr.length` and the\n// three removal paths (cancel, rekey, dead-pushEvent) each `delete`\n// the key when the array empties. So on the current hub the value\n// is never `0` — but this JSON comes from a hub whose version this\n// dashboard doesn't control (see the legacy alias-only fallback\n// below for the version we already know we support), so treating\n// the map defensively costs nothing and keeps the definition\n// pointing the same direction #214 F2 took: SSE-reachable = \"can I\n// talk to it right now\", and a zero-count row is not that.\n// - `!!sseLookup(s)` in the old page.tsx also treated 0 as false;\n// preserving that keeps this a pure refactor for page.tsx.\n//\n// SSE keys in health.sse_sessions are `network_id:alias` since v0.7+\n// (per-network scoping). Legacy fallback: bare alias.\n\nexport type SseSessionsMap = Record<string, unknown>;\n\nexport type PresenceSubject = {\n alias: string;\n network_id?: string;\n};\n\nexport function sseCountFor(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): number | undefined {\n if (!sseSessions) return undefined;\n const scoped = session.network_id ? sseSessions[`${session.network_id}:${session.alias}`] : undefined;\n const value = (scoped ?? sseSessions[session.alias]) as number | undefined;\n return typeof value === 'number' ? value : undefined;\n}\n\nexport function isOnline(session: PresenceSubject, sseSessions: SseSessionsMap | undefined): boolean {\n const n = sseCountFor(session, sseSessions);\n return typeof n === 'number' && n > 0;\n}\n\n// -----------------------------------------------------------------------\n// #53: three-state ambient presence signal.\n//\n// `sse_sessions` on hub's /health is **auth-gated** (post `#495-followup`\n// / `f28a6c1b`): an anonymous or wrong-scope caller gets the field\n// **completely omitted** — indistinguishable at the JSON level from\n// \"no nodes connected\".\n//\n// If we hand that state to isOnline() and only render numbers, the UI\n// shows a confident, consistent, and *wrong* 0 online everywhere and\n// the \"three sites disagree\" signal #515 used to have — which was\n// itself the clue that something upstream was broken — is gone.\n//\n// So callers need to distinguish three cases:\n//\n// 'ready' — sseSessions is present (even if empty {}). Trust the\n// count. `filter(isOnline).length` is the answer.\n// 'blind' — sseSessions is absent but hub `sse_connections > 0`.\n// Two fields contradict → we are seeing an anonymized\n// view. Do NOT render \"0 online\"; render an alert.\n// 'loading' — sseSessions is absent and no positive contradiction\n// (either health hasn't loaded, or hub reports 0\n// connections and no map). Render a placeholder — don't\n// inflate the count, but don't cry wolf either.\n//\n// Callers that render user-visible counts MUST branch on this. Callers\n// that just need a per-node boolean (halos, chat-popover badges) can\n// stay on isOnline() — those degrade gracefully to \"everyone offline\"\n// which is the safer visual, while the ambient banner handles the\n// \"why\".\n// -----------------------------------------------------------------------\n\nexport type PresenceStatus = 'ready' | 'blind' | 'loading';\n\nexport type HealthShape = {\n sse_connections?: number;\n} | null | undefined;\n\nexport function presenceStatus(\n sseSessions: SseSessionsMap | undefined,\n health: HealthShape,\n): PresenceStatus {\n if (sseSessions !== undefined) return 'ready';\n // sseSessions is absent. Are we blind or truly empty/loading?\n const conns = health && typeof health.sse_connections === 'number' ? health.sse_connections : 0;\n // The contradiction case — hub says there are connections but the\n // map isn't in this response — is the strongest \"you're anonymous\"\n // signal we have.\n if (conns > 0) return 'blind';\n // No map AND hub reports 0 connections (or health hasn't loaded).\n // Both look identical to us, and both should render placeholders,\n // not \"0 online\" numbers. Conservative default = 'loading'.\n return 'loading';\n}\n","/** Shared timestamp helpers for hub-sourced data.\n *\n * Background — the CommHub serialises timestamps SQL-style without a\n * zone (\"2026-05-15 06:00:28\"), but some test data uses full ISO\n * (\"…T06:00:28Z\"). `Date.parse` on bare SQL is **local-time** in every\n * browser the dashboard supports, so a UTC+8 operator silently sees\n * every timestamp 8 h older than reality (Round 35 dug this out via\n * the `isGhost` filter mis-fire).\n *\n * Round 38 / Loop consolidates parsing — TopoGraph (R35), ChatPopover\n * (R37) and utils.ts::timeAgo all mirrored the same SQL→UTC rewrite;\n * one source of truth here. */\n\n/** Parse a hub timestamp to ms-since-epoch, treating SQL-style strings\n * as UTC. ISO strings (with `T`) bypass the rewrite and are parsed as-is.\n * Returns null for empty / unparseable input. */\nexport function parseHubTime(dateStr: string | null | undefined): number | null {\n if (!dateStr) return null;\n const iso = dateStr.includes('T') ? dateStr : dateStr.replace(' ', 'T') + 'Z';\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n}\n\n/** 一个节点静默多久算「陈旧」。\n *\n * 这个阈值原本只活在 TopoGraph 里(Round 27 / P0 把它从 24h 收到 1h:\n * 健康 agent 每几秒心跳一次,静默一小时基本等于没了)。但同一份节点数据\n * 有多个入口,而只有拓扑图知道这个阈值 —— 定时任务的节点选择器完全不知道,\n * 于是下拉框里几个月前的死节点和刚心跳过的节点长得一模一样。\n *\n * 实测(2026-08-13 生产):171 个节点里 110 个 `updated_at` 超过一小时,\n * 最久的停在三个月前,而 **171/171 的 `lifecycle_state` 都是 \"active\"** ——\n * 除了时间戳,没有任何字段能分辨(hub 侧见 #751)。\n *\n * 提到这里是为了让两个入口不会各飘各的。注意**只有阈值可共享**:\n * TopoGraph 的 `isGhost` 还要求 `status === 'offline'` 且无 SSE 连接,\n * 那些字段 `/api/nodes` 不返回,不能照搬。 */\nexport const NODE_STALE_MS = 60 * 60 * 1000;\n\n/** 按 `NODE_STALE_MS` 判断一个 hub 时间戳是否已陈旧。\n * 时间戳缺失/不可解析时返回 false —— 保守:宁可不标记,也不误标一个新节点。 */\nexport function isHubTimeStale(dateStr: string | null | undefined): boolean {\n const t = parseHubTime(dateStr);\n return t !== null && Date.now() - t > NODE_STALE_MS;\n}\n\n/** Format `dateStr` as a short relative-time string (\"6m ago\" / \"2h ago\").\n * Future timestamps (clock skew) collapse to \"just now\". Returns null when\n * the input doesn't parse — callers can decide on a fallback. */\nexport function relativeAgo(dateStr: string | null | undefined): string | null {\n const t = parseHubTime(dateStr);\n if (t === null) return null;\n const s = Math.floor((Date.now() - t) / 1000);\n if (s < 0) return 'just now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n if (s < 86400) return `${Math.floor(s / 3600)}h ago`;\n return `${Math.floor(s / 86400)}d ago`;\n}\n\n/** Loop R7 (跨面一致性): WeChat-style contextual timestamp shared by the\n * chat panel (R3) and /messages dividers. zh locales keep the native\n * wording (昨天/星期X); others get Intl output (\"Yesterday\"/\"Tue\").\n * Today → \"14:32\" · yesterday → \"昨天 14:32\" · <7d → \"星期二 14:32\" ·\n * this year → \"7月16日 14:32\" · older adds the year. */\nexport function formatWeChatTime(value: string | null | undefined): string {\n const t = parseHubTime(value);\n if (t === null) return '';\n const d = new Date(t);\n const now = new Date();\n const zh = typeof navigator !== 'undefined' && (navigator.language || '').toLowerCase().startsWith('zh');\n const hm = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n const startOfDay = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const dayDiff = Math.round((startOfDay(now) - startOfDay(d)) / 86400000);\n if (dayDiff === 0) return hm;\n if (dayDiff === 1) return zh ? `昨天 ${hm}` : `Yesterday ${hm}`;\n if (dayDiff > 1 && dayDiff < 7) {\n const wd = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, { weekday: zh ? 'long' : 'short' }).format(d);\n return `${wd} ${hm}`;\n }\n const md = new Intl.DateTimeFormat(zh ? 'zh-CN' : undefined, {\n month: zh ? 'long' : 'short', day: 'numeric',\n ...(d.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n }).format(d);\n return `${md} ${hm}`;\n}\n"],"names":["STORE_KEY","AVATAR_EVENT","hubMap","hubNodeAliases","Set","hubMapKey","hydrateHubAvatars","nodes","next","nextAliases","n","alias","add","avatar_url","key","JSON","stringify","sort","join","manifest","pool","manifestRequested","poolPick","length","h","i","charCodeAt","fetchManifestOnce","readMap","getAvatarUrl","has","setAvatarUrl","url","version","subscribe","callback","bump","window","addEventListener","removeEventListener","useAvatarsVersion","useAvatarUrl","CHAT_OUTBOX_PREFIX","CHAT_DRAFT_PREFIX","LEGACY_PRIVATE_PREFIXES","AUTH_KEY","MAX_ENTRIES","MAX_CONTENT_BYTES","OUTBOX_TTL_MS","chatPrivateScope","networkId","session","undefined","auth","parse","getItem","identity","user","user_id","username","network","currentNetwork","encodeURIComponent","clearPrivateChatStorage","storage","removed","keys","index","startsWith","some","prefix","push","removeItem","valid","entry","e","requestId","test","localTaskId","panelAlias","targetAlias","content","TextEncoder","encode","byteLength","priority","createdAt","storageKey","scope","readChatOutbox","now","Date","parsed","Array","isArray","live","filter","created","Number","isFinite","slice","write","entries","setItem","putChatOutbox","item","removeChatOutbox","chatOutboxForAlias","MUTE_EVENT","readSet","isMuted","toggleMute","useMuted","useMuteVersion","fetcher","res","fetch","status","location","assign","Error","json","SWR_OPTIONS","refreshInterval","dedupingInterval","withNetwork","sep","includes","useSessions","data","error","isLoading","sessions","hint","_hint","useNodeLifecycle","mutate","lifecycleByAlias","nodeIdByAlias","attrsByAlias","lifecycle_state","node_id","display_name","team","tags","attrs_revision","refreshNodes","useHealth","health","useAnetConfig","config","useTasks","params","query","URLSearchParams","limit","toString","tasks","count","source","useStats","stats","ok","useMessages","keepPreviousData","messages","NetworkContext","setNetworkId","NetworkProvider","children","saved","sessionStorage","cancelled","cache","then","r","networks","d","list","pick","find","network_name","id","network_id","catch","setAndPersist","Provider","value","useNetworkId","sseCountFor","sseSessions","scoped","isOnline","presenceStatus","conns","sse_connections","parseHubTime","dateStr","iso","replace","t","NODE_STALE_MS","isHubTimeStale","relativeAgo","s","Math","floor","formatWeChatTime","zh","navigator","language","toLowerCase","hm","String","getHours","padStart","getMinutes","startOfDay","x","getFullYear","getMonth","getDate","getTime","dayDiff","round","wd","Intl","DateTimeFormat","weekday","format","md","month","day","year"],"mappings":"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"}
|