9router 0.4.31 → 0.4.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/.next/BUILD_ID +1 -1
- package/app/.next/app-path-routes-manifest.json +7 -7
- package/app/.next/build-manifest.json +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/skills/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error.html +1 -1
- package/app/.next/server/app/_global-error.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_not-found.html +1 -1
- package/app/.next/server/app/_not-found.rsc +3 -3
- package/app/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/app/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/api/models/route.js +1 -1
- package/app/.next/server/app/api/models/test/route.js +1 -1
- package/app/.next/server/app/api/providers/[id]/test-models/route.js +1 -1
- package/app/.next/server/app/api/providers/route.js +1 -1
- package/app/.next/server/app/api/translator/console-logs/route.js +1 -1
- package/app/.next/server/app/api/translator/console-logs/stream/route.js +1 -1
- package/app/.next/server/app/api/version/route.js +1 -1
- package/app/.next/server/app/api/version/shutdown/route.js +1 -1
- package/app/.next/server/app/api/version/update/route.js +1 -1
- package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback.html +1 -1
- package/app/.next/server/app/callback.rsc +3 -3
- package/app/.next/server/app/callback.segments/_full.segment.rsc +3 -3
- package/app/.next/server/app/callback.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/callback.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/basic-chat.html +1 -1
- package/app/.next/server/app/dashboard/basic-chat.rsc +5 -5
- package/app/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.html +1 -1
- package/app/.next/server/app/dashboard/cli-tools.rsc +5 -5
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.html +1 -1
- package/app/.next/server/app/dashboard/combos.rsc +5 -5
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.html +1 -1
- package/app/.next/server/app/dashboard/endpoint.rsc +5 -5
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/media-providers/web.html +1 -1
- package/app/.next/server/app/dashboard/media-providers/web.rsc +5 -5
- package/app/.next/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/media-providers/web.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/media-providers/web.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.html +1 -1
- package/app/.next/server/app/dashboard/mitm.rsc +5 -5
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.html +1 -1
- package/app/.next/server/app/dashboard/profile.rsc +5 -5
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.html +1 -1
- package/app/.next/server/app/dashboard/providers/new.rsc +5 -5
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.html +1 -1
- package/app/.next/server/app/dashboard/providers.rsc +5 -5
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.html +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.rsc +5 -5
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.html +2 -2
- package/app/.next/server/app/dashboard/quota.rsc +6 -6
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.html +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.rsc +3 -3
- package/app/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/skills.html +1 -1
- package/app/.next/server/app/dashboard/skills.rsc +5 -5
- package/app/.next/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/skills.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/skills.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/skills.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/skills.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.html +1 -1
- package/app/.next/server/app/dashboard/translator.rsc +5 -5
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.html +1 -1
- package/app/.next/server/app/dashboard/usage.rsc +5 -5
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.html +1 -1
- package/app/.next/server/app/dashboard.rsc +5 -5
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/index.html +1 -1
- package/app/.next/server/app/index.rsc +3 -3
- package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/app/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/landing.html +1 -1
- package/app/.next/server/app/landing.rsc +3 -3
- package/app/.next/server/app/landing.segments/_full.segment.rsc +3 -3
- package/app/.next/server/app/landing.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/landing.segment.rsc +1 -1
- package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/login.html +1 -1
- package/app/.next/server/app/login.rsc +4 -4
- package/app/.next/server/app/login.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/login.segments/_index.segment.rsc +3 -3
- package/app/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/app/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app-paths-manifest.json +7 -7
- package/app/.next/server/chunks/1795.js +1 -1
- package/app/.next/server/chunks/6263.js +1 -1
- package/app/.next/server/chunks/6283.js +1 -1
- package/app/.next/server/chunks/6634.js +1 -1
- package/app/.next/server/middleware-build-manifest.js +1 -1
- package/app/.next/server/pages/404.html +1 -1
- package/app/.next/server/pages/500.html +1 -1
- package/app/.next/static/chunks/{505-39ae32473371c4a3.js → 505-b06cfc156450639a.js} +1 -1
- package/app/package.json +1 -1
- package/cli.js +4 -0
- package/hooks/postinstall.js +7 -0
- package/hooks/trayRuntime.js +84 -0
- package/package.json +3 -3
- package/src/cli/tray/tray.js +136 -104
- package/src/cli/tray/tray.ps1 +79 -0
- package/src/cli/tray/trayWin.js +89 -0
- /package/app/.next/static/{xjtYx1FfVtGAPQbE4LiMu → xilRJjRhqJhUZ2VStWKZh}/_buildManifest.js +0 -0
- /package/app/.next/static/{xjtYx1FfVtGAPQbE4LiMu → xilRJjRhqJhUZ2VStWKZh}/_ssgManifest.js +0 -0
package/app/package.json
CHANGED
package/cli.js
CHANGED
|
@@ -44,6 +44,7 @@ function createSpinner(text) {
|
|
|
44
44
|
|
|
45
45
|
const pkg = require("./package.json");
|
|
46
46
|
const { ensureSqliteRuntime, buildEnvWithRuntime } = require("./hooks/sqliteRuntime");
|
|
47
|
+
const { ensureTrayRuntime } = require("./hooks/trayRuntime");
|
|
47
48
|
const args = process.argv.slice(2);
|
|
48
49
|
|
|
49
50
|
// Self-heal SQLite runtime deps (sql.js + better-sqlite3) into ~/.9router/runtime
|
|
@@ -51,6 +52,9 @@ const args = process.argv.slice(2);
|
|
|
51
52
|
// better-sqlite3 is optional. Logs to stderr only on failure.
|
|
52
53
|
try { ensureSqliteRuntime({ silent: true }); } catch {}
|
|
53
54
|
|
|
55
|
+
// Self-heal tray runtime (systray for macOS/Linux only). Windows skipped.
|
|
56
|
+
try { ensureTrayRuntime({ silent: true }); } catch {}
|
|
57
|
+
|
|
54
58
|
// Configuration constants
|
|
55
59
|
const APP_NAME = pkg.name; // Use from package.json
|
|
56
60
|
const INSTALL_CMD_LATEST = `npm i -g ${APP_NAME}@latest --prefer-online`;
|
package/hooks/postinstall.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// `9router` start doesn't need network. Failure here is non-fatal —
|
|
5
5
|
// cli.js will retry at runtime if anything is missing.
|
|
6
6
|
const { ensureSqliteRuntime } = require("./sqliteRuntime");
|
|
7
|
+
const { ensureTrayRuntime } = require("./trayRuntime");
|
|
7
8
|
|
|
8
9
|
try {
|
|
9
10
|
ensureSqliteRuntime({ silent: false });
|
|
@@ -12,4 +13,10 @@ try {
|
|
|
12
13
|
console.warn(`[9router] runtime warm-up skipped: ${e.message}`);
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
try {
|
|
17
|
+
ensureTrayRuntime({ silent: false });
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.warn(`[9router] tray runtime skipped: ${e.message}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
process.exit(0);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Lazy install systray for macOS/Linux into USER_DATA_DIR/runtime/node_modules.
|
|
2
|
+
// Windows uses PowerShell NotifyIcon (no binary) → no systray needed.
|
|
3
|
+
// This keeps the published npm tarball free of unsigned Go binaries that
|
|
4
|
+
// trigger antivirus false positives (e.g. Kaspersky flagging tray_windows.exe).
|
|
5
|
+
const { spawnSync } = require("child_process");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const { getRuntimeDir, getRuntimeNodeModules } = require("./sqliteRuntime");
|
|
9
|
+
|
|
10
|
+
const SYSTRAY_VERSION = "1.0.5";
|
|
11
|
+
|
|
12
|
+
function hasSystray() {
|
|
13
|
+
return fs.existsSync(path.join(getRuntimeNodeModules(), "systray", "package.json"));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Remove legacy systray from all known locations on Windows (AV false positive cleanup)
|
|
17
|
+
function cleanupWindowsSystray({ silent = false } = {}) {
|
|
18
|
+
if (process.platform !== "win32") return;
|
|
19
|
+
// 1) Runtime dir: %APPDATA%\9router\runtime\node_modules\systray
|
|
20
|
+
// 2) npm global nested: <npm_prefix>\node_modules\9router\node_modules\systray
|
|
21
|
+
// __dirname here = <npm_prefix>\node_modules\9router\hooks → up 1 = pkg root
|
|
22
|
+
const targets = [
|
|
23
|
+
path.join(getRuntimeNodeModules(), "systray"),
|
|
24
|
+
path.join(__dirname, "..", "node_modules", "systray")
|
|
25
|
+
];
|
|
26
|
+
for (const dir of targets) {
|
|
27
|
+
if (fs.existsSync(dir)) {
|
|
28
|
+
try {
|
|
29
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
30
|
+
if (!silent) console.log(`[9router][runtime] removed legacy systray: ${dir}`);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
if (!silent) console.warn(`[9router][runtime] failed to remove ${dir}: ${e.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function ensureRuntimeDir() {
|
|
39
|
+
const dir = getRuntimeDir();
|
|
40
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
41
|
+
const pkgPath = path.join(dir, "package.json");
|
|
42
|
+
if (!fs.existsSync(pkgPath)) {
|
|
43
|
+
fs.writeFileSync(pkgPath, JSON.stringify({
|
|
44
|
+
name: "9router-runtime",
|
|
45
|
+
version: "1.0.0",
|
|
46
|
+
private: true
|
|
47
|
+
}, null, 2));
|
|
48
|
+
}
|
|
49
|
+
return dir;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function npmInstall(pkgs, { silent = false } = {}) {
|
|
53
|
+
const cwd = ensureRuntimeDir();
|
|
54
|
+
const args = ["install", ...pkgs, "--no-audit", "--no-fund", "--no-save", "--prefer-online"];
|
|
55
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
56
|
+
if (!silent) console.log(`[9router][runtime] ${npmCmd} ${args.join(" ")} (cwd: ${cwd})`);
|
|
57
|
+
const res = spawnSync(npmCmd, args, {
|
|
58
|
+
cwd,
|
|
59
|
+
stdio: silent ? "ignore" : "inherit",
|
|
60
|
+
timeout: 120000,
|
|
61
|
+
shell: process.platform === "win32"
|
|
62
|
+
});
|
|
63
|
+
return res.status === 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Public: ensure systray is installed on macOS/Linux only.
|
|
67
|
+
// Windows skips entirely (uses PowerShell tray).
|
|
68
|
+
function ensureTrayRuntime({ silent = false } = {}) {
|
|
69
|
+
if (process.platform === "win32") {
|
|
70
|
+
cleanupWindowsSystray({ silent });
|
|
71
|
+
return { systray: false, skipped: true };
|
|
72
|
+
}
|
|
73
|
+
if (hasSystray()) {
|
|
74
|
+
if (!silent) console.log("[9router][runtime] systray OK");
|
|
75
|
+
return { systray: true };
|
|
76
|
+
}
|
|
77
|
+
const ok = npmInstall([`systray@${SYSTRAY_VERSION}`], { silent });
|
|
78
|
+
if (!ok && !silent) {
|
|
79
|
+
console.warn("[9router][runtime] systray install failed (tray will be disabled)");
|
|
80
|
+
}
|
|
81
|
+
return { systray: ok && hasSystray() };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = { ensureTrayRuntime };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "9router",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.33",
|
|
4
4
|
"description": "9Router CLI - Start and manage 9Router server",
|
|
5
5
|
"bin": {
|
|
6
6
|
"9router": "./cli.js"
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"node-forge": "^1.3.3",
|
|
22
22
|
"node-machine-id": "^1.1.12",
|
|
23
23
|
"react": "19.2.1",
|
|
24
|
-
"react-dom": "19.2.1"
|
|
25
|
-
"systray": "^1.0.5"
|
|
24
|
+
"react-dom": "19.2.1"
|
|
26
25
|
},
|
|
27
26
|
"comment_sqlite": "sql.js + better-sqlite3 are NOT bundled here. They are installed into ~/.9router/runtime/node_modules by hooks/postinstall.js (and re-checked at runtime by cli.js). This avoids Windows EBUSY errors when updating the global CLI, since native .node files no longer live under the locked install dir.",
|
|
27
|
+
"comment_systray": "systray is NOT bundled here. It is lazy-installed into ~/.9router/runtime/node_modules by hooks/postinstall.js on macOS/Linux only. Windows uses PowerShell NotifyIcon (zero binary). This avoids shipping the unsigned Go binary tray_windows.exe that triggers antivirus false positives (Kaspersky).",
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=18.0.0"
|
|
30
30
|
},
|
package/src/cli/tray/tray.js
CHANGED
|
@@ -3,9 +3,10 @@ const fs = require("fs");
|
|
|
3
3
|
const path = require("path");
|
|
4
4
|
|
|
5
5
|
let trayInstance = null;
|
|
6
|
+
let isWinTray = false;
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
* Get icon base64 from file —
|
|
9
|
+
* Get icon base64 from file — used for systray (mac/linux)
|
|
9
10
|
*/
|
|
10
11
|
function getIconBase64() {
|
|
11
12
|
const isWin = process.platform === "win32";
|
|
@@ -26,11 +27,9 @@ function getIconBase64() {
|
|
|
26
27
|
*/
|
|
27
28
|
function isTraySupported() {
|
|
28
29
|
const platform = process.platform;
|
|
29
|
-
// Supported platforms: darwin (macOS), win32 (Windows), linux
|
|
30
30
|
if (!["darwin", "win32", "linux"].includes(platform)) {
|
|
31
31
|
return false;
|
|
32
32
|
}
|
|
33
|
-
// Skip on Linux without display (headless server)
|
|
34
33
|
if (platform === "linux" && !process.env.DISPLAY) {
|
|
35
34
|
return false;
|
|
36
35
|
}
|
|
@@ -43,122 +42,156 @@ function isTraySupported() {
|
|
|
43
42
|
* @returns {Object|null} tray instance or null if not supported/failed
|
|
44
43
|
*/
|
|
45
44
|
function initTray(options) {
|
|
46
|
-
// Check OS support first
|
|
47
45
|
if (!isTraySupported()) {
|
|
48
46
|
return null;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
// Windows uses PowerShell NotifyIcon (AV-safe), others use systray
|
|
50
|
+
if (process.platform === "win32") {
|
|
51
|
+
return initWindowsTray(options);
|
|
52
|
+
}
|
|
53
|
+
return initUnixTray(options);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build menu items array shared between platforms
|
|
58
|
+
*/
|
|
59
|
+
function buildMenuItems(port, autostartEnabled) {
|
|
60
|
+
return [
|
|
61
|
+
{ title: `9Router (Port ${port})`, tooltip: "Server is running", enabled: false },
|
|
62
|
+
{ title: "Open Dashboard", tooltip: "Open in browser", enabled: true },
|
|
63
|
+
{
|
|
64
|
+
title: autostartEnabled ? "✓ Auto-start Enabled" : "Enable Auto-start",
|
|
65
|
+
tooltip: "Run on OS startup",
|
|
66
|
+
enabled: true
|
|
67
|
+
},
|
|
68
|
+
{ title: "Quit", tooltip: "Stop server and exit", enabled: true }
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Menu item indexes
|
|
73
|
+
const MENU_INDEX = { STATUS: 0, DASHBOARD: 1, AUTOSTART: 2, QUIT: 3 };
|
|
52
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Get current autostart state
|
|
77
|
+
*/
|
|
78
|
+
function getAutostartEnabled() {
|
|
53
79
|
try {
|
|
54
|
-
const
|
|
80
|
+
const { isAutoStartEnabled } = require("./autostart");
|
|
81
|
+
return isAutoStartEnabled();
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
55
86
|
|
|
56
|
-
|
|
57
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Handle menu item click (shared logic)
|
|
89
|
+
*/
|
|
90
|
+
function handleClick(index, options, onAutostartToggle) {
|
|
91
|
+
const { onQuit, onOpenDashboard, port } = options;
|
|
92
|
+
if (index === MENU_INDEX.DASHBOARD) {
|
|
93
|
+
if (onOpenDashboard) onOpenDashboard();
|
|
94
|
+
else openBrowser(`http://localhost:${port}/dashboard`);
|
|
95
|
+
} else if (index === MENU_INDEX.AUTOSTART) {
|
|
96
|
+
const enabled = getAutostartEnabled();
|
|
58
97
|
try {
|
|
59
|
-
const {
|
|
60
|
-
|
|
98
|
+
const { enableAutoStart, disableAutoStart } = require("./autostart");
|
|
99
|
+
if (enabled) disableAutoStart();
|
|
100
|
+
else enableAutoStart();
|
|
101
|
+
onAutostartToggle(!enabled);
|
|
61
102
|
} catch (e) {}
|
|
103
|
+
} else if (index === MENU_INDEX.QUIT) {
|
|
104
|
+
console.log("\n👋 Shutting down...");
|
|
105
|
+
if (onQuit) onQuit();
|
|
106
|
+
killTray();
|
|
107
|
+
setTimeout(() => process.exit(0), 500);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Windows tray via PowerShell NotifyIcon
|
|
113
|
+
*/
|
|
114
|
+
function initWindowsTray(options) {
|
|
115
|
+
const { port } = options;
|
|
116
|
+
try {
|
|
117
|
+
const { initWinTray } = require("./trayWin");
|
|
118
|
+
const iconPath = path.join(__dirname, "icon.ico");
|
|
119
|
+
const autostartEnabled = getAutostartEnabled();
|
|
120
|
+
const items = buildMenuItems(port, autostartEnabled);
|
|
121
|
+
|
|
122
|
+
trayInstance = initWinTray({
|
|
123
|
+
iconPath,
|
|
124
|
+
tooltip: `9Router - Port ${port}`,
|
|
125
|
+
items,
|
|
126
|
+
onClick: (index) => {
|
|
127
|
+
handleClick(index, options, (newEnabled) => {
|
|
128
|
+
const newTitle = newEnabled ? "✓ Auto-start Enabled" : "Enable Auto-start";
|
|
129
|
+
trayInstance.updateItem(MENU_INDEX.AUTOSTART, newTitle, true);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
isWinTray = true;
|
|
135
|
+
return trayInstance;
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* macOS/Linux tray via systray binary
|
|
143
|
+
*/
|
|
144
|
+
function resolveSystray() {
|
|
145
|
+
// Try local first (dev), then runtime dir (production lazy install)
|
|
146
|
+
try {
|
|
147
|
+
return require("systray").default;
|
|
148
|
+
} catch (e) {}
|
|
149
|
+
try {
|
|
150
|
+
const { getRuntimeNodeModules } = require("../../../hooks/sqliteRuntime");
|
|
151
|
+
const systrayPath = path.join(getRuntimeNodeModules(), "systray");
|
|
152
|
+
return require(systrayPath).default;
|
|
153
|
+
} catch (e) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function initUnixTray(options) {
|
|
159
|
+
const { port } = options;
|
|
160
|
+
try {
|
|
161
|
+
const SysTray = resolveSystray();
|
|
162
|
+
if (!SysTray) return null;
|
|
163
|
+
const autostartEnabled = getAutostartEnabled();
|
|
164
|
+
const items = buildMenuItems(port, autostartEnabled);
|
|
62
165
|
|
|
63
|
-
const isWin = process.platform === "win32";
|
|
64
166
|
const menu = {
|
|
65
167
|
icon: getIconBase64(),
|
|
66
|
-
|
|
67
|
-
title: isWin ? `9Router - Port ${port}` : "",
|
|
168
|
+
title: "",
|
|
68
169
|
tooltip: `9Router - Port ${port}`,
|
|
69
|
-
items
|
|
70
|
-
{
|
|
71
|
-
title: `9Router (Port ${port})`,
|
|
72
|
-
tooltip: "Server is running",
|
|
73
|
-
enabled: false
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
title: "Open Dashboard",
|
|
77
|
-
tooltip: "Open in browser",
|
|
78
|
-
enabled: true
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
title: autostartEnabled ? "✓ Auto-start Enabled" : "Enable Auto-start",
|
|
82
|
-
tooltip: "Run on OS startup",
|
|
83
|
-
enabled: true
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
title: "Quit",
|
|
87
|
-
tooltip: "Stop server and exit",
|
|
88
|
-
enabled: true
|
|
89
|
-
}
|
|
90
|
-
]
|
|
170
|
+
items
|
|
91
171
|
};
|
|
92
172
|
|
|
93
|
-
trayInstance = new SysTray({
|
|
94
|
-
|
|
95
|
-
debug: false,
|
|
96
|
-
copyDir: true
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Menu item index: 0=status, 1=dashboard, 2=autostart, 3=quit
|
|
100
|
-
const AUTOSTART_INDEX = 2;
|
|
173
|
+
trayInstance = new SysTray({ menu, debug: false, copyDir: true });
|
|
174
|
+
isWinTray = false;
|
|
101
175
|
|
|
102
176
|
trayInstance.onClick((action) => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// Update menu item
|
|
115
|
-
trayInstance.sendAction({
|
|
116
|
-
type: "update-item",
|
|
117
|
-
item: {
|
|
118
|
-
title: "Enable Auto-start",
|
|
119
|
-
tooltip: "Run on OS startup",
|
|
120
|
-
enabled: true
|
|
121
|
-
},
|
|
122
|
-
seq_id: AUTOSTART_INDEX
|
|
123
|
-
});
|
|
124
|
-
} catch (e) {}
|
|
125
|
-
} else if (action.item.title === "Enable Auto-start") {
|
|
126
|
-
// Enable autostart
|
|
127
|
-
try {
|
|
128
|
-
const { enableAutoStart } = require("./autostart");
|
|
129
|
-
enableAutoStart();
|
|
130
|
-
// Update menu item
|
|
131
|
-
trayInstance.sendAction({
|
|
132
|
-
type: "update-item",
|
|
133
|
-
item: {
|
|
134
|
-
title: "✓ Auto-start Enabled",
|
|
135
|
-
tooltip: "Run on OS startup",
|
|
136
|
-
enabled: true
|
|
137
|
-
},
|
|
138
|
-
seq_id: AUTOSTART_INDEX
|
|
139
|
-
});
|
|
140
|
-
} catch (e) {}
|
|
141
|
-
} else if (action.item.title === "Quit") {
|
|
142
|
-
console.log("\n👋 Shutting down...");
|
|
143
|
-
if (onQuit) {
|
|
144
|
-
onQuit();
|
|
145
|
-
}
|
|
146
|
-
killTray();
|
|
147
|
-
setTimeout(() => process.exit(0), 500);
|
|
148
|
-
}
|
|
177
|
+
handleClick(action.seq_id, options, (newEnabled) => {
|
|
178
|
+
trayInstance.sendAction({
|
|
179
|
+
type: "update-item",
|
|
180
|
+
item: {
|
|
181
|
+
title: newEnabled ? "✓ Auto-start Enabled" : "Enable Auto-start",
|
|
182
|
+
tooltip: "Run on OS startup",
|
|
183
|
+
enabled: true
|
|
184
|
+
},
|
|
185
|
+
seq_id: MENU_INDEX.AUTOSTART
|
|
186
|
+
});
|
|
187
|
+
});
|
|
149
188
|
});
|
|
150
189
|
|
|
151
|
-
trayInstance.onReady(() => {
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
trayInstance.onError((err) => {
|
|
156
|
-
// Ignore errors during shutdown
|
|
157
|
-
});
|
|
190
|
+
trayInstance.onReady(() => {});
|
|
191
|
+
trayInstance.onError(() => {});
|
|
158
192
|
|
|
159
193
|
return trayInstance;
|
|
160
194
|
} catch (err) {
|
|
161
|
-
// Silent fail - tray is optional, app continues without it
|
|
162
195
|
return null;
|
|
163
196
|
}
|
|
164
197
|
}
|
|
@@ -168,15 +201,14 @@ function initTray(options) {
|
|
|
168
201
|
*/
|
|
169
202
|
function killTray() {
|
|
170
203
|
const instance = trayInstance;
|
|
171
|
-
|
|
172
|
-
|
|
204
|
+
const wasWin = isWinTray;
|
|
205
|
+
trayInstance = null;
|
|
206
|
+
|
|
173
207
|
if (instance) {
|
|
174
208
|
try {
|
|
175
|
-
|
|
176
|
-
instance.kill(true);
|
|
177
|
-
} catch (e) {
|
|
178
|
-
// Ignore kill errors - tray binary may already be dead
|
|
179
|
-
}
|
|
209
|
+
if (wasWin) instance.kill();
|
|
210
|
+
else instance.kill(true);
|
|
211
|
+
} catch (e) {}
|
|
180
212
|
}
|
|
181
213
|
}
|
|
182
214
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# 9Router tray icon for Windows using NotifyIcon
|
|
2
|
+
# IPC: stdin JSON commands, stdout JSON events
|
|
3
|
+
param([string]$IconPath, [string]$Tooltip)
|
|
4
|
+
|
|
5
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
6
|
+
Add-Type -AssemblyName System.Drawing
|
|
7
|
+
|
|
8
|
+
$ErrorActionPreference = "Stop"
|
|
9
|
+
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
10
|
+
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
|
|
11
|
+
$OutputEncoding = [System.Text.Encoding]::UTF8
|
|
12
|
+
|
|
13
|
+
$script:notifyIcon = New-Object System.Windows.Forms.NotifyIcon
|
|
14
|
+
$script:notifyIcon.Icon = New-Object System.Drawing.Icon($IconPath)
|
|
15
|
+
$script:notifyIcon.Text = $Tooltip
|
|
16
|
+
$script:notifyIcon.Visible = $true
|
|
17
|
+
|
|
18
|
+
$script:menu = New-Object System.Windows.Forms.ContextMenuStrip
|
|
19
|
+
$script:notifyIcon.ContextMenuStrip = $script:menu
|
|
20
|
+
$script:items = @()
|
|
21
|
+
|
|
22
|
+
function Write-Event($obj) {
|
|
23
|
+
$json = $obj | ConvertTo-Json -Compress
|
|
24
|
+
[Console]::Out.WriteLine($json)
|
|
25
|
+
[Console]::Out.Flush()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function Add-MenuItem($index, $title, $enabled) {
|
|
29
|
+
$item = New-Object System.Windows.Forms.ToolStripMenuItem
|
|
30
|
+
$item.Text = $title
|
|
31
|
+
$item.Enabled = $enabled
|
|
32
|
+
$idx = $index
|
|
33
|
+
$item.Add_Click({ Write-Event @{ type = "click"; index = $idx } }.GetNewClosure())
|
|
34
|
+
$script:menu.Items.Add($item) | Out-Null
|
|
35
|
+
$script:items += $item
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function Update-MenuItem($index, $title, $enabled) {
|
|
39
|
+
if ($index -lt $script:items.Count) {
|
|
40
|
+
$script:items[$index].Text = $title
|
|
41
|
+
$script:items[$index].Enabled = $enabled
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function Set-Tooltip($text) {
|
|
46
|
+
# NotifyIcon.Text max 63 chars
|
|
47
|
+
if ($text.Length -gt 63) { $text = $text.Substring(0, 63) }
|
|
48
|
+
$script:notifyIcon.Text = $text
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Background reader thread polls stdin via timer on UI thread
|
|
52
|
+
$script:timer = New-Object System.Windows.Forms.Timer
|
|
53
|
+
$script:timer.Interval = 100
|
|
54
|
+
$script:timer.Add_Tick({
|
|
55
|
+
try {
|
|
56
|
+
while ([Console]::In.Peek() -ne -1) {
|
|
57
|
+
$line = [Console]::In.ReadLine()
|
|
58
|
+
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
|
59
|
+
$cmd = $line | ConvertFrom-Json
|
|
60
|
+
switch ($cmd.action) {
|
|
61
|
+
"add-item" { Add-MenuItem $cmd.index $cmd.title $cmd.enabled }
|
|
62
|
+
"update-item" { Update-MenuItem $cmd.index $cmd.title $cmd.enabled }
|
|
63
|
+
"set-tooltip" { Set-Tooltip $cmd.text }
|
|
64
|
+
"ready" { Write-Event @{ type = "ready" } }
|
|
65
|
+
"kill" {
|
|
66
|
+
$script:notifyIcon.Visible = $false
|
|
67
|
+
$script:notifyIcon.Dispose()
|
|
68
|
+
[System.Windows.Forms.Application]::Exit()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
Write-Event @{ type = "error"; message = $_.Exception.Message }
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
$script:timer.Start()
|
|
77
|
+
|
|
78
|
+
Write-Event @{ type = "started" }
|
|
79
|
+
[System.Windows.Forms.Application]::Run()
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const { spawn } = require("child_process");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const readline = require("readline");
|
|
4
|
+
|
|
5
|
+
// PowerShell-based tray for Windows (AV-safe, zero binary deps)
|
|
6
|
+
|
|
7
|
+
let psProcess = null;
|
|
8
|
+
let clickHandler = null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Send JSON command to PowerShell tray process via stdin
|
|
12
|
+
*/
|
|
13
|
+
function sendCommand(cmd) {
|
|
14
|
+
if (psProcess && psProcess.stdin.writable) {
|
|
15
|
+
psProcess.stdin.write(`${JSON.stringify(cmd)}\n`, "utf8");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initialize Windows tray using PowerShell NotifyIcon
|
|
21
|
+
* @param {Object} options - { iconPath, tooltip, items, onClick }
|
|
22
|
+
* items: [{ title, enabled }]
|
|
23
|
+
* @returns {Object|null} controller with sendAction/kill
|
|
24
|
+
*/
|
|
25
|
+
function initWinTray(options) {
|
|
26
|
+
const { iconPath, tooltip, items, onClick } = options;
|
|
27
|
+
clickHandler = onClick;
|
|
28
|
+
|
|
29
|
+
const scriptPath = path.join(__dirname, "tray.ps1");
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
psProcess = spawn(
|
|
33
|
+
"powershell.exe",
|
|
34
|
+
[
|
|
35
|
+
"-NoProfile",
|
|
36
|
+
"-ExecutionPolicy", "Bypass",
|
|
37
|
+
"-WindowStyle", "Hidden",
|
|
38
|
+
"-InputFormat", "Text",
|
|
39
|
+
"-OutputFormat", "Text",
|
|
40
|
+
"-File", scriptPath,
|
|
41
|
+
"-IconPath", iconPath,
|
|
42
|
+
"-Tooltip", tooltip
|
|
43
|
+
],
|
|
44
|
+
{ windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }
|
|
45
|
+
);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rl = readline.createInterface({ input: psProcess.stdout });
|
|
51
|
+
rl.on("line", (line) => {
|
|
52
|
+
try {
|
|
53
|
+
const evt = JSON.parse(line);
|
|
54
|
+
if (evt.type === "click" && clickHandler) {
|
|
55
|
+
clickHandler(evt.index);
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
psProcess.on("error", () => {});
|
|
61
|
+
psProcess.stderr.on("data", () => {});
|
|
62
|
+
|
|
63
|
+
// Send initial menu items
|
|
64
|
+
items.forEach((item, index) => {
|
|
65
|
+
sendCommand({ action: "add-item", index, title: item.title, enabled: item.enabled });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
updateItem(index, title, enabled) {
|
|
70
|
+
sendCommand({ action: "update-item", index, title, enabled });
|
|
71
|
+
},
|
|
72
|
+
setTooltip(text) {
|
|
73
|
+
sendCommand({ action: "set-tooltip", text });
|
|
74
|
+
},
|
|
75
|
+
kill() {
|
|
76
|
+
try {
|
|
77
|
+
sendCommand({ action: "kill" });
|
|
78
|
+
} catch (e) {}
|
|
79
|
+
setTimeout(() => {
|
|
80
|
+
if (psProcess && !psProcess.killed) {
|
|
81
|
+
try { psProcess.kill(); } catch (e) {}
|
|
82
|
+
}
|
|
83
|
+
psProcess = null;
|
|
84
|
+
}, 300);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { initWinTray };
|
|
File without changes
|
|
File without changes
|