@juspay/shooter 1.0.0 → 1.2.0
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/.claude/hooks/notifier.cjs +117 -33
- package/.claude/settings.json +14 -14
- package/README.md +116 -84
- package/bin/shooter.cjs +471 -102
- package/build/client/_app/immutable/assets/{0.CM9Hl6d-.css → 0.BhZOCxO4.css} +1 -1
- package/build/client/_app/immutable/assets/0.BhZOCxO4.css.br +0 -0
- package/build/client/_app/immutable/assets/0.BhZOCxO4.css.gz +0 -0
- package/build/client/_app/immutable/assets/1.BYutk3aU.css +1 -0
- package/build/client/_app/immutable/assets/1.BYutk3aU.css.br +0 -0
- package/build/client/_app/immutable/assets/1.BYutk3aU.css.gz +0 -0
- package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
- package/build/client/_app/immutable/assets/3.DGDHCVnW.css +1 -0
- package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
- package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
- package/build/client/_app/immutable/assets/4.BFUut--w.css +1 -0
- package/build/client/_app/immutable/assets/4.BFUut--w.css.br +0 -0
- package/build/client/_app/immutable/assets/4.BFUut--w.css.gz +0 -0
- package/build/client/_app/immutable/assets/5.BTOx7yt7.css +1 -0
- package/build/client/_app/immutable/assets/5.BTOx7yt7.css.br +0 -0
- package/build/client/_app/immutable/assets/5.BTOx7yt7.css.gz +0 -0
- package/build/client/_app/immutable/assets/6.eZGZN-BF.css +1 -0
- package/build/client/_app/immutable/assets/6.eZGZN-BF.css.br +0 -0
- package/build/client/_app/immutable/assets/6.eZGZN-BF.css.gz +0 -0
- package/build/client/_app/immutable/assets/7.DwS5ZHBh.css +1 -0
- package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.br +0 -0
- package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.gz +0 -0
- package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css +1 -0
- package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.br +0 -0
- package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.gz +0 -0
- package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css +1 -0
- package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css.br +0 -0
- package/build/client/_app/immutable/assets/Phone.FQEfwCX2.css.gz +0 -0
- package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css +1 -0
- package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css.br +0 -0
- package/build/client/_app/immutable/assets/markdown.Dc-OSJWY.css.gz +0 -0
- package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.gz +0 -0
- package/build/client/_app/immutable/chunks/B-K5Sh65.js +1 -0
- package/build/client/_app/immutable/chunks/B-K5Sh65.js.br +0 -0
- package/build/client/_app/immutable/chunks/B-K5Sh65.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B5NAKyil.js +20 -0
- package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
- package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B8XegpSE.js +1 -0
- package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
- package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B8zoBsv3.js +6 -0
- package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
- package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BLszSzTT.js +1 -0
- package/build/client/_app/immutable/chunks/BLszSzTT.js.br +0 -0
- package/build/client/_app/immutable/chunks/BLszSzTT.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BOYo8yTr.js +1 -0
- package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
- package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BTGVxaYV.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BYqGCrTe.js +1 -0
- package/build/client/_app/immutable/chunks/BYqGCrTe.js.br +0 -0
- package/build/client/_app/immutable/chunks/BYqGCrTe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BlxrFPDK.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bu1aqm5j.js +1 -0
- package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C4mLaWWx.js +1 -0
- package/build/client/_app/immutable/chunks/C4mLaWWx.js.br +0 -0
- package/build/client/_app/immutable/chunks/C4mLaWWx.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CQjSATpv.js +61 -0
- package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
- package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CSoRdFvv.js +1 -0
- package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
- package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CZHsSL_X.js +1 -0
- package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
- package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DLu6yJIZ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DSU1n5N_.js +1 -0
- package/build/client/_app/immutable/chunks/DSU1n5N_.js.br +0 -0
- package/build/client/_app/immutable/chunks/DSU1n5N_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DVkn4r72.js +1 -0
- package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
- package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DjsDGxCa.js +41 -0
- package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
- package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
- package/build/client/_app/immutable/chunks/PPVm8Dsz.js.gz +0 -0
- package/build/client/_app/immutable/chunks/UJOiqIYE.js +1 -0
- package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
- package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/r0JawsZc.js +2 -0
- package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
- package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.Z3zMnuSx.js +2 -0
- package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.br +0 -0
- package/build/client/_app/immutable/entry/app.Z3zMnuSx.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.Dd-gIP4y.js +1 -0
- package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.br +2 -0
- package/build/client/_app/immutable/entry/start.Dd-gIP4y.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.D2YR8tTD.js +1 -0
- package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.D2YR8tTD.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.B3m6rO4C.js +1 -0
- package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.B3m6rO4C.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.CyRB2euU.js +1 -0
- package/build/client/_app/immutable/nodes/2.CyRB2euU.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.CyRB2euU.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.3yohCM25.js +3 -0
- package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.DEAcwl7l.js +1 -0
- package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.DEAcwl7l.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.C6bLGWQR.js +4 -0
- package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.C6bLGWQR.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.ByTzlA2D.js +2 -0
- package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.ByTzlA2D.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.BPMfwzd2.js +2 -0
- package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.BPMfwzd2.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/client/favicon.svg.gz +0 -0
- package/build/client/manifest.json +13 -0
- package/build/client/manifest.json.br +0 -0
- package/build/client/manifest.json.gz +0 -0
- package/build/pty-holder.cjs +37 -8
- package/build/server/chunks/0-Vk38tI2J.js +9 -0
- package/build/server/chunks/0-Vk38tI2J.js.map +1 -0
- package/build/server/chunks/1-BvYQX5MR.js +9 -0
- package/build/server/chunks/1-BvYQX5MR.js.map +1 -0
- package/build/server/chunks/2-Cl7R4Qk2.js +9 -0
- package/build/server/chunks/2-Cl7R4Qk2.js.map +1 -0
- package/build/server/chunks/3-Ck7ewhOX.js +9 -0
- package/build/server/chunks/3-Ck7ewhOX.js.map +1 -0
- package/build/server/chunks/4-CnDeRm2Z.js +9 -0
- package/build/server/chunks/4-CnDeRm2Z.js.map +1 -0
- package/build/server/chunks/5-IxitzEvN.js +9 -0
- package/build/server/chunks/5-IxitzEvN.js.map +1 -0
- package/build/server/chunks/6-CyZ3r1iS.js +9 -0
- package/build/server/chunks/6-CyZ3r1iS.js.map +1 -0
- package/build/server/chunks/7-BmI7du46.js +9 -0
- package/build/server/chunks/7-BmI7du46.js.map +1 -0
- package/build/server/chunks/Button-Cs1aE6ka.js +80 -0
- package/build/server/chunks/Button-Cs1aE6ka.js.map +1 -0
- package/build/server/chunks/EmptyState-DDFH1K8g.js +26 -0
- package/build/server/chunks/EmptyState-DDFH1K8g.js.map +1 -0
- package/build/server/chunks/Icon-CEUrotA6.js +36 -0
- package/build/server/chunks/Icon-CEUrotA6.js.map +1 -0
- package/build/server/chunks/Shimmer-DB8W1zt6.js +10 -0
- package/build/server/chunks/Shimmer-DB8W1zt6.js.map +1 -0
- package/build/server/chunks/_error.svelte-uCOJNxvr.js +39 -0
- package/build/server/chunks/_error.svelte-uCOJNxvr.js.map +1 -0
- package/build/server/chunks/_layout.svelte-CtWmEJwe.js +56 -0
- package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +1 -0
- package/build/server/chunks/_page.svelte-BcZaKdX9.js +45 -0
- package/build/server/chunks/_page.svelte-BcZaKdX9.js.map +1 -0
- package/build/server/chunks/_page.svelte-BdYynOck.js +85 -0
- package/build/server/chunks/_page.svelte-BdYynOck.js.map +1 -0
- package/build/server/chunks/_page.svelte-BgevQjq1.js +101 -0
- package/build/server/chunks/_page.svelte-BgevQjq1.js.map +1 -0
- package/build/server/chunks/_page.svelte-CVq6tRb3.js +550 -0
- package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +1 -0
- package/build/server/chunks/_page.svelte-CxWcQ0Am.js +651 -0
- package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +1 -0
- package/build/server/chunks/_page.svelte-DO4oa_LY.js +44 -0
- package/build/server/chunks/_page.svelte-DO4oa_LY.js.map +1 -0
- package/build/server/chunks/{_server.ts-CbDRDIoP.js → _server.ts-BStnNIcq.js} +9 -11
- package/build/server/chunks/_server.ts-BStnNIcq.js.map +1 -0
- package/build/server/chunks/{_server.ts-DRVbgm6k.js → _server.ts-CAxsWKvS.js} +22 -25
- package/build/server/chunks/_server.ts-CAxsWKvS.js.map +1 -0
- package/build/server/chunks/{_server.ts-CPa6DgIt.js → _server.ts-COu0vNpd.js} +6 -6
- package/build/server/chunks/_server.ts-COu0vNpd.js.map +1 -0
- package/build/server/chunks/{_server.ts-C29xzfaw.js → _server.ts-CTpcLUH8.js} +10 -10
- package/build/server/chunks/_server.ts-CTpcLUH8.js.map +1 -0
- package/build/server/chunks/{_server.ts-D4MNi4cD.js → _server.ts-Cf84YIaW.js} +3 -3
- package/build/server/chunks/{_server.ts-D4MNi4cD.js.map → _server.ts-Cf84YIaW.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BL2FGb5Z.js → _server.ts-Ch-6iOHp.js} +99 -53
- package/build/server/chunks/_server.ts-Ch-6iOHp.js.map +1 -0
- package/build/server/chunks/_server.ts-CtH0dhUp.js +71 -0
- package/build/server/chunks/_server.ts-CtH0dhUp.js.map +1 -0
- package/build/server/chunks/_server.ts-DB_Kg97c.js +73 -0
- package/build/server/chunks/_server.ts-DB_Kg97c.js.map +1 -0
- package/build/server/chunks/{_server.ts-DfajWaqh.js → _server.ts-DV8zTCF9.js} +7 -9
- package/build/server/chunks/_server.ts-DV8zTCF9.js.map +1 -0
- package/build/server/chunks/_server.ts-DYpJImqd.js +99 -0
- package/build/server/chunks/_server.ts-DYpJImqd.js.map +1 -0
- package/build/server/chunks/{_server.ts-ColfDHW8.js → _server.ts-DYvb9ijZ.js} +21 -10
- package/build/server/chunks/_server.ts-DYvb9ijZ.js.map +1 -0
- package/build/server/chunks/{_server.ts-Cv_OrRuL.js → _server.ts-Deok2y88.js} +209 -34
- package/build/server/chunks/_server.ts-Deok2y88.js.map +1 -0
- package/build/server/chunks/{_server.ts-y9-WYDMa.js → _server.ts-WhTJBEJy.js} +5 -4
- package/build/server/chunks/{_server.ts-y9-WYDMa.js.map → _server.ts-WhTJBEJy.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BjOJsoy4.js → _server.ts-XzT2UHM1.js} +6 -5
- package/build/server/chunks/_server.ts-XzT2UHM1.js.map +1 -0
- package/build/server/chunks/{_server.ts-BgdjBZco.js → _server.ts-tSpgyl1D.js} +7 -5
- package/build/server/chunks/_server.ts-tSpgyl1D.js.map +1 -0
- package/build/server/chunks/{_server.ts-BihKSdj_.js → _server.ts-vekTmWAx.js} +8 -8
- package/build/server/chunks/_server.ts-vekTmWAx.js.map +1 -0
- package/build/server/chunks/{auth-CEgFis71.js → auth-DeCdZ83n.js} +2 -2
- package/build/server/chunks/{auth-CEgFis71.js.map → auth-DeCdZ83n.js.map} +1 -1
- package/build/server/chunks/client-BdGHe_hY.js +25 -0
- package/build/server/chunks/client-BdGHe_hY.js.map +1 -0
- package/build/server/chunks/client2-CCBGA-2V.js +7 -0
- package/build/server/chunks/client2-CCBGA-2V.js.map +1 -0
- package/build/server/chunks/error-DDXB3duW.js +12 -0
- package/build/server/chunks/error-DDXB3duW.js.map +1 -0
- package/build/server/chunks/{exports-CJ0Q5XmL.js → index-DwaY1cAm.js} +1111 -1634
- package/build/server/chunks/index-DwaY1cAm.js.map +1 -0
- package/build/server/chunks/index-server-CrDaL06Y.js +9 -0
- package/build/server/chunks/index-server-CrDaL06Y.js.map +1 -0
- package/build/server/chunks/index2-CgclKpUj.js +58 -0
- package/build/server/chunks/index2-CgclKpUj.js.map +1 -0
- package/build/server/chunks/{library-apns-BHxLmuIx.js → library-apns-BqJbvSKh.js} +4 -4
- package/build/server/chunks/library-apns-BqJbvSKh.js.map +1 -0
- package/build/server/chunks/markdown-W_mTBct0.js +8 -0
- package/build/server/chunks/markdown-W_mTBct0.js.map +1 -0
- package/build/server/chunks/opencode-db-path-DcfhJtJy.js +15 -0
- package/build/server/chunks/opencode-db-path-DcfhJtJy.js.map +1 -0
- package/build/server/chunks/{pty-manager-C0FhBiVq.js → pty-manager-BQVB7IVj.js} +155 -326
- package/build/server/chunks/pty-manager-BQVB7IVj.js.map +1 -0
- package/build/server/chunks/root-DDSnEAZv.js +1171 -0
- package/build/server/chunks/root-DDSnEAZv.js.map +1 -0
- package/build/server/chunks/{shared-server-BDY8jh20.js → shared-server-sSGG17Df.js} +2 -3
- package/build/server/chunks/{shared-server-BDY8jh20.js.map → shared-server-sSGG17Df.js.map} +1 -1
- package/build/server/chunks/state.svelte-hBbXlUak.js +11 -0
- package/build/server/chunks/state.svelte-hBbXlUak.js.map +1 -0
- package/build/server/chunks/stores-DHNzYNpX.js +28 -0
- package/build/server/chunks/stores-DHNzYNpX.js.map +1 -0
- package/build/server/index.js +1085 -2242
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +39 -25
- package/build/server/manifest.js.map +1 -1
- package/package.json +32 -9
- package/scripts/fix-generated-types.sh +37 -0
- package/scripts/homebrew/shooter.rb +51 -0
- package/scripts/install.sh +348 -186
- package/scripts/setup.cjs +215 -45
- package/server.ts +114 -71
- package/src/app.css +12 -3
- package/src/app.d.ts +13 -20
- package/src/app.html +3 -2
- package/src/generated/types/API.ts +280 -0
- package/src/generated/types/APN.ts +186 -203
- package/src/generated/types/CLI.ts +18 -25
- package/src/generated/types/Client.ts +589 -0
- package/src/generated/types/Config.ts +53 -0
- package/src/generated/types/Holder.ts +638 -0
- package/src/generated/types/JWT.ts +39 -50
- package/src/generated/types/Notification.ts +426 -0
- package/src/generated/types/OpenCode.ts +356 -0
- package/src/generated/types/Sessions.ts +570 -0
- package/src/generated/types/Terminal.ts +2184 -2071
- package/src/generated/types/WsProtocol.ts +2004 -0
- package/src/generated/types/index.ts +9 -3
- package/src/lib/env.ts +29 -0
- package/src/lib/modules/client/common/cache.ts +10 -2
- package/src/lib/modules/client/common/config-guard.ts +37 -5
- package/src/lib/modules/client/common/error.ts +10 -0
- package/src/lib/modules/client/common/index.ts +6 -5
- package/src/lib/modules/client/common/markdown.ts +22 -1
- package/src/lib/modules/client/common/native-bridge.ts +28 -20
- package/src/lib/modules/client/common/time.ts +13 -11
- package/src/lib/modules/client/terminal/ChatView.svelte +354 -74
- package/src/lib/modules/client/terminal/CommandPalette.svelte +3 -2
- package/src/lib/modules/client/terminal/ConnectionStatus.svelte +7 -1
- package/src/lib/modules/client/terminal/LaunchSheet.svelte +147 -84
- package/src/lib/modules/client/terminal/QuickKeys.svelte +3 -1
- package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +2 -5
- package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +27 -24
- package/src/lib/modules/client/terminal/xterm-wrapper.ts +74 -45
- package/src/lib/modules/server/apn/library-apns.ts +3 -2
- package/src/lib/modules/server/apn/notification-history.ts +2 -13
- package/src/lib/modules/server/apn/notification-sessions.ts +3 -13
- package/src/lib/modules/server/apn/pending-requests.ts +3 -8
- package/src/lib/modules/server/apn/types.ts +5 -4
- package/src/lib/modules/server/cli/index.ts +3 -2
- package/src/lib/modules/server/fcm/fcm-service.ts +8 -6
- package/src/lib/modules/server/sessions/jsonl-parser.ts +3 -3
- package/src/lib/modules/server/sessions/jsonl-reader.ts +86 -26
- package/src/lib/modules/server/sessions/opencode-db-path.ts +26 -0
- package/src/lib/modules/server/sessions/opencode-reader.ts +13 -15
- package/src/lib/modules/server/sessions/process-detector.ts +103 -0
- package/src/lib/modules/server/sessions/types.ts +11 -22
- package/src/lib/modules/server/terminal/holder-client.ts +272 -248
- package/src/lib/modules/server/terminal/opencode-watcher.ts +547 -556
- package/src/lib/modules/server/terminal/pty-holder.cjs +37 -8
- package/src/lib/modules/server/terminal/pty-manager.ts +157 -115
- package/src/lib/modules/server/terminal/session-watcher.ts +6 -4
- package/src/lib/modules/server/terminal/terminal-store.ts +131 -128
- package/src/lib/modules/server/utils/error.ts +9 -0
- package/src/lib/modules/server/ws/events-handler.ts +12 -6
- package/src/lib/modules/server/ws/keepalive.ts +86 -69
- package/src/lib/modules/server/ws/server.ts +43 -37
- package/src/lib/modules/server/ws/session-handler.ts +332 -147
- package/src/lib/modules/server/ws/terminal-handler.ts +29 -17
- package/src/lib/modules/server/ws/ticket-store.ts +29 -26
- package/src/lib/theme.css +30 -0
- package/src/lib/types/config.ts +1 -6
- package/src/routes/+error.svelte +94 -0
- package/src/routes/+layout.svelte +66 -31
- package/src/routes/+page.svelte +25 -22
- package/src/routes/api/debug/+server.ts +3 -1
- package/src/routes/api/device-token/+server.ts +60 -60
- package/src/routes/api/health/+server.ts +81 -73
- package/src/routes/api/notify/+server.ts +115 -68
- package/src/routes/api/qr-config/+server.ts +30 -32
- package/src/routes/api/response/+server.ts +9 -4
- package/src/routes/api/sessions/+server.ts +15 -5
- package/src/routes/api/sessions/connect/+server.ts +125 -0
- package/src/routes/api/sessions/detect/+server.ts +27 -0
- package/src/routes/api/terminals/+server.ts +26 -24
- package/src/routes/api/terminals/[id]/+server.ts +13 -7
- package/src/routes/api/terminals/[id]/paste-image/+server.ts +54 -52
- package/src/routes/api/terminals/[id]/resize/+server.ts +6 -3
- package/src/routes/api/webhook/+server.ts +8 -10
- package/src/routes/api/ws-status/+server.ts +7 -5
- package/src/routes/api/ws-ticket/+server.ts +42 -41
- package/src/routes/config/+page.svelte +149 -75
- package/src/routes/project/+page.svelte +165 -35
- package/src/routes/session/[id]/+page.svelte +479 -283
- package/src/routes/terminals/+page.svelte +58 -45
- package/src/routes/terminals/[id]/+page.svelte +223 -91
- package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.br +0 -0
- package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.gz +0 -0
- package/build/client/_app/immutable/assets/3.C0uFg0IS.css +0 -1
- package/build/client/_app/immutable/assets/3.C0uFg0IS.css.br +0 -0
- package/build/client/_app/immutable/assets/3.C0uFg0IS.css.gz +0 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +0 -1
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css +0 -1
- package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
- package/build/client/_app/immutable/assets/6.AraZrY8I.css +0 -1
- package/build/client/_app/immutable/assets/6.AraZrY8I.css.br +0 -0
- package/build/client/_app/immutable/assets/6.AraZrY8I.css.gz +0 -0
- package/build/client/_app/immutable/assets/7.BCJ1IuMx.css +0 -1
- package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.br +0 -0
- package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.gz +0 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +0 -1
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
- package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css +0 -1
- package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.br +0 -0
- package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BNJphC1q.js +0 -56
- package/build/client/_app/immutable/chunks/BNJphC1q.js.br +0 -0
- package/build/client/_app/immutable/chunks/BNJphC1q.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bvk7mfPM.js +0 -1
- package/build/client/_app/immutable/chunks/Bvk7mfPM.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bvk7mfPM.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CAokzuPQ.js +0 -1
- package/build/client/_app/immutable/chunks/CAokzuPQ.js.br +0 -0
- package/build/client/_app/immutable/chunks/CAokzuPQ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js +0 -1
- package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CgCpWzEA.js +0 -1
- package/build/client/_app/immutable/chunks/CgCpWzEA.js.br +0 -0
- package/build/client/_app/immutable/chunks/CgCpWzEA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cjwk_cGO.js +0 -6
- package/build/client/_app/immutable/chunks/Cjwk_cGO.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cjwk_cGO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CtQ8EED1.js +0 -11
- package/build/client/_app/immutable/chunks/CtQ8EED1.js.br +0 -0
- package/build/client/_app/immutable/chunks/CtQ8EED1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DERQCisl.js +0 -1
- package/build/client/_app/immutable/chunks/DERQCisl.js.br +0 -0
- package/build/client/_app/immutable/chunks/DERQCisl.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DKrg8TQs.js +0 -1
- package/build/client/_app/immutable/chunks/DKrg8TQs.js.br +0 -0
- package/build/client/_app/immutable/chunks/DKrg8TQs.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dkkpz_4D.js +0 -126
- package/build/client/_app/immutable/chunks/Dkkpz_4D.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dkkpz_4D.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DoczjQhA.js +0 -1
- package/build/client/_app/immutable/chunks/DoczjQhA.js.br +0 -0
- package/build/client/_app/immutable/chunks/DoczjQhA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/RpcNruLP.js +0 -2
- package/build/client/_app/immutable/chunks/RpcNruLP.js.br +0 -0
- package/build/client/_app/immutable/chunks/RpcNruLP.js.gz +0 -0
- package/build/client/_app/immutable/chunks/a-St0Zwo.js +0 -1
- package/build/client/_app/immutable/chunks/a-St0Zwo.js.br +0 -0
- package/build/client/_app/immutable/chunks/a-St0Zwo.js.gz +0 -0
- package/build/client/_app/immutable/chunks/bo70OQUZ.js +0 -1
- package/build/client/_app/immutable/chunks/bo70OQUZ.js.br +0 -0
- package/build/client/_app/immutable/chunks/bo70OQUZ.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.QvGgdvTI.js +0 -2
- package/build/client/_app/immutable/entry/app.QvGgdvTI.js.br +0 -0
- package/build/client/_app/immutable/entry/app.QvGgdvTI.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BntDNRMC.js +0 -1
- package/build/client/_app/immutable/entry/start.BntDNRMC.js.br +0 -0
- package/build/client/_app/immutable/entry/start.BntDNRMC.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js +0 -1
- package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.MG1QhfrI.js +0 -1
- package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.B4MlOSh6.js +0 -1
- package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.DIwYkjDn.js +0 -3
- package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.D-cIe70D.js +0 -1
- package/build/client/_app/immutable/nodes/4.D-cIe70D.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.D-cIe70D.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.D7zPRe3L.js +0 -1
- package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.BB7QE48r.js +0 -2
- package/build/client/_app/immutable/nodes/6.BB7QE48r.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.BB7QE48r.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.D8mqsrZG.js +0 -2
- package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.gz +0 -0
- package/build/client/manifest.webmanifest +0 -1
- package/build/client/registerSW.js +0 -1
- package/build/client/registerSW.js.br +0 -0
- package/build/client/registerSW.js.gz +0 -0
- package/build/client/sw.js +0 -222
- package/build/client/sw.js.br +0 -0
- package/build/client/sw.js.gz +0 -0
- package/build/client/workbox-5119daf5.js +0 -3395
- package/build/client/workbox-5119daf5.js.br +0 -0
- package/build/client/workbox-5119daf5.js.gz +0 -0
- package/build/server/chunks/0-q2IUp76Y.js +0 -9
- package/build/server/chunks/0-q2IUp76Y.js.map +0 -1
- package/build/server/chunks/1-CU50G5wZ.js +0 -9
- package/build/server/chunks/1-CU50G5wZ.js.map +0 -1
- package/build/server/chunks/2-D01t9s8T.js +0 -9
- package/build/server/chunks/2-D01t9s8T.js.map +0 -1
- package/build/server/chunks/3-5PUQ04wC.js +0 -9
- package/build/server/chunks/3-5PUQ04wC.js.map +0 -1
- package/build/server/chunks/4-e7gywnSG.js +0 -9
- package/build/server/chunks/4-e7gywnSG.js.map +0 -1
- package/build/server/chunks/5-CA1SA6KZ.js +0 -9
- package/build/server/chunks/5-CA1SA6KZ.js.map +0 -1
- package/build/server/chunks/6-71H221sV.js +0 -9
- package/build/server/chunks/6-71H221sV.js.map +0 -1
- package/build/server/chunks/7-Bo-vmdyz.js +0 -9
- package/build/server/chunks/7-Bo-vmdyz.js.map +0 -1
- package/build/server/chunks/_layout.svelte-SFHOxs74.js +0 -132
- package/build/server/chunks/_layout.svelte-SFHOxs74.js.map +0 -1
- package/build/server/chunks/_page.svelte-B4w-2wD-.js +0 -120
- package/build/server/chunks/_page.svelte-B4w-2wD-.js.map +0 -1
- package/build/server/chunks/_page.svelte-B_qAXjkh.js +0 -213
- package/build/server/chunks/_page.svelte-B_qAXjkh.js.map +0 -1
- package/build/server/chunks/_page.svelte-CsF1_TRG.js +0 -50
- package/build/server/chunks/_page.svelte-CsF1_TRG.js.map +0 -1
- package/build/server/chunks/_page.svelte-DJC6U-P0.js +0 -68
- package/build/server/chunks/_page.svelte-DJC6U-P0.js.map +0 -1
- package/build/server/chunks/_page.svelte-DQ6HBtsz.js +0 -407
- package/build/server/chunks/_page.svelte-DQ6HBtsz.js.map +0 -1
- package/build/server/chunks/_page.svelte-LbhhjP21.js +0 -148
- package/build/server/chunks/_page.svelte-LbhhjP21.js.map +0 -1
- package/build/server/chunks/_server.ts-BL2FGb5Z.js.map +0 -1
- package/build/server/chunks/_server.ts-BgdjBZco.js.map +0 -1
- package/build/server/chunks/_server.ts-BihKSdj_.js.map +0 -1
- package/build/server/chunks/_server.ts-BjOJsoy4.js.map +0 -1
- package/build/server/chunks/_server.ts-C29xzfaw.js.map +0 -1
- package/build/server/chunks/_server.ts-CPa6DgIt.js.map +0 -1
- package/build/server/chunks/_server.ts-CbDRDIoP.js.map +0 -1
- package/build/server/chunks/_server.ts-Cl1OEWL4.js +0 -54
- package/build/server/chunks/_server.ts-Cl1OEWL4.js.map +0 -1
- package/build/server/chunks/_server.ts-ColfDHW8.js.map +0 -1
- package/build/server/chunks/_server.ts-Cv_OrRuL.js.map +0 -1
- package/build/server/chunks/_server.ts-DRVbgm6k.js.map +0 -1
- package/build/server/chunks/_server.ts-DfajWaqh.js.map +0 -1
- package/build/server/chunks/client-CxCatAKr.js +0 -255
- package/build/server/chunks/client-CxCatAKr.js.map +0 -1
- package/build/server/chunks/error.svelte-BqdwMWdK.js +0 -26
- package/build/server/chunks/error.svelte-BqdwMWdK.js.map +0 -1
- package/build/server/chunks/exports-CJ0Q5XmL.js.map +0 -1
- package/build/server/chunks/index2-DAxIoAO-.js +0 -36
- package/build/server/chunks/index2-DAxIoAO-.js.map +0 -1
- package/build/server/chunks/jsonl-parser-dmZU_Hyu.js +0 -137
- package/build/server/chunks/jsonl-parser-dmZU_Hyu.js.map +0 -1
- package/build/server/chunks/library-apns-BHxLmuIx.js.map +0 -1
- package/build/server/chunks/markdown-Bxrl3cCF.js +0 -1241
- package/build/server/chunks/markdown-Bxrl3cCF.js.map +0 -1
- package/build/server/chunks/pty-manager-C0FhBiVq.js.map +0 -1
- package/build/server/chunks/stores-D0HorpgL.js +0 -36
- package/build/server/chunks/stores-D0HorpgL.js.map +0 -1
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
// Relays terminal output to connected clients and routes client input
|
|
3
3
|
// (keystrokes, resize, signals) back to the PTY.
|
|
4
4
|
|
|
5
|
+
import type { TerminalSignal } from '$generated/types';
|
|
5
6
|
import type { WebSocket } from 'ws';
|
|
6
7
|
|
|
7
8
|
// ── Types ────────────────────────────────────────────────────────────
|
|
8
9
|
|
|
9
10
|
/** Inbound messages from the client. */
|
|
10
11
|
type ClientMessage =
|
|
11
|
-
| { cols: number; rows: number; type: 'resize'
|
|
12
|
-
| { data: string; type: 'input'
|
|
13
|
-
| { signal:
|
|
12
|
+
| { cols: number; rows: number; type: 'resize' }
|
|
13
|
+
| { data: string; type: 'input' }
|
|
14
|
+
| { signal: TerminalSignal; type: 'signal' };
|
|
14
15
|
|
|
15
16
|
/** Outbound messages to the client. */
|
|
16
17
|
type ServerMessage =
|
|
17
|
-
| { bytes: number; type: 'output-dropped'
|
|
18
|
-
| { chunk: number; data: string; total: number; type: 'scrollback'
|
|
19
|
-
| { code: null | number; signal: null | string; type: 'exit'
|
|
20
|
-
| { data: string; type: 'output'
|
|
21
|
-
| { message: string; type: 'error'
|
|
18
|
+
| { bytes: number; type: 'output-dropped' }
|
|
19
|
+
| { chunk: number; data: string; total: number; type: 'scrollback' }
|
|
20
|
+
| { code: null | number; signal: null | string; type: 'exit' }
|
|
21
|
+
| { data: string; type: 'output' }
|
|
22
|
+
| { message: string; type: 'error' };
|
|
22
23
|
|
|
23
24
|
// ── Constants ────────────────────────────────────────────────────────
|
|
24
25
|
|
|
@@ -29,8 +30,8 @@ const SIGNAL_MAP: Record<string, NodeJS.Signals> = {
|
|
|
29
30
|
SIGTSTP: 'SIGTSTP',
|
|
30
31
|
};
|
|
31
32
|
|
|
32
|
-
// ── PTY Manager
|
|
33
|
-
// Minimal duck-typed
|
|
33
|
+
// ── PTY Manager type ─────────────────────────────────────────────────
|
|
34
|
+
// Minimal duck-typed shape matching the real pty-manager singleton.
|
|
34
35
|
|
|
35
36
|
interface ManagedTerminal {
|
|
36
37
|
clients: Set<WebSocket>;
|
|
@@ -159,18 +160,29 @@ function parseClientMessage(raw: string): ClientMessage | null {
|
|
|
159
160
|
|
|
160
161
|
switch (msg.type) {
|
|
161
162
|
case 'input':
|
|
162
|
-
if (typeof msg.data !== 'string') {
|
|
163
|
+
if (typeof msg.data !== 'string') {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
163
166
|
return { data: msg.data, type: 'input' };
|
|
164
167
|
case 'resize':
|
|
165
|
-
if (
|
|
166
|
-
|
|
168
|
+
if (
|
|
169
|
+
typeof msg.cols !== 'number' ||
|
|
170
|
+
typeof msg.rows !== 'number' ||
|
|
171
|
+
!Number.isFinite(msg.cols) ||
|
|
172
|
+
!Number.isFinite(msg.rows)
|
|
173
|
+
) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
if (msg.cols < 1 || msg.rows < 1 || msg.cols > 500 || msg.rows > 200) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
167
179
|
return { cols: Math.floor(msg.cols), rows: Math.floor(msg.rows), type: 'resize' };
|
|
168
180
|
case 'signal':
|
|
169
|
-
if (typeof msg.signal !== 'string' || !(msg.signal
|
|
181
|
+
if (typeof msg.signal !== 'string' || !Object.hasOwn(SIGNAL_MAP, msg.signal)) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
170
184
|
return {
|
|
171
|
-
signal: msg.signal as
|
|
172
|
-
? S
|
|
173
|
-
: never,
|
|
185
|
+
signal: msg.signal as TerminalSignal,
|
|
174
186
|
type: 'signal',
|
|
175
187
|
};
|
|
176
188
|
default:
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
// WebSocket ticket store.
|
|
2
2
|
// Generates short-lived, single-use tickets for authenticating WebSocket upgrades.
|
|
3
|
-
// Tickets expire after 30 seconds and are cleaned up every
|
|
3
|
+
// Tickets expire after 30 seconds and are cleaned up every 30 seconds.
|
|
4
4
|
//
|
|
5
5
|
// This avoids putting the long-lived API_KEY in WebSocket URL query parameters,
|
|
6
6
|
// which would appear in proxy logs, Cloudflare access logs, and browser history.
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import type { Ticket } from '$generated/types';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
createdAt: number;
|
|
12
|
-
used: boolean;
|
|
13
|
-
}
|
|
10
|
+
import { randomBytes } from 'crypto';
|
|
14
11
|
|
|
15
12
|
// Use globalThis to ensure a single shared Map across module instances.
|
|
16
13
|
// server.ts (via tsx) and SvelteKit's build handler load this module separately,
|
|
17
14
|
// creating two different module scopes. globalThis bridges them.
|
|
18
15
|
const GLOBAL_KEY = '__shooter_ws_tickets';
|
|
19
16
|
const tickets: Map<string, Ticket> =
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
((globalThis as Record<string, unknown>)[GLOBAL_KEY] as Map<string, Ticket>) ||
|
|
18
|
+
new Map<string, Ticket>();
|
|
22
19
|
(globalThis as Record<string, unknown>)[GLOBAL_KEY] = tickets;
|
|
23
20
|
|
|
24
21
|
/**
|
|
@@ -26,9 +23,9 @@ const tickets: Map<string, Ticket> =
|
|
|
26
23
|
* The ticket is valid for 30 seconds and can only be consumed once.
|
|
27
24
|
*/
|
|
28
25
|
export function generateTicket(): string {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
const ticket = randomBytes(32).toString('hex');
|
|
27
|
+
tickets.set(ticket, { createdAt: Date.now(), used: false });
|
|
28
|
+
return ticket;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
/**
|
|
@@ -37,22 +34,28 @@ export function generateTicket(): string {
|
|
|
37
34
|
* A valid ticket is marked as used (single-use) and cannot be reused.
|
|
38
35
|
*/
|
|
39
36
|
export function validateTicket(ticket: null | string): boolean {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
if (!ticket) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const entry = tickets.get(ticket);
|
|
41
|
+
if (!entry || entry.used) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (Date.now() - entry.createdAt > 30_000) {
|
|
45
|
+
tickets.delete(ticket);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
entry.used = true;
|
|
49
|
+
return true;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
// Cleanup expired tickets every
|
|
52
|
+
// Cleanup expired tickets every 30 seconds (matches ticket lifetime).
|
|
52
53
|
// .unref() ensures this timer does not prevent Node.js from exiting.
|
|
53
54
|
setInterval(() => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
for (const [key, val] of tickets) {
|
|
57
|
+
if (now - val.createdAt > 30_000) {
|
|
58
|
+
tickets.delete(key);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}, 30_000).unref();
|
package/src/lib/theme.css
CHANGED
|
@@ -276,12 +276,37 @@
|
|
|
276
276
|
--button-hover-text-color: var(--ds-background-100);
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
.btn-connect {
|
|
280
|
+
--button-color: #0d9488;
|
|
281
|
+
--button-text-color: #fff;
|
|
282
|
+
--button-hover-color: #14b8a6;
|
|
283
|
+
--button-hover-text-color: #fff;
|
|
284
|
+
--button-border: 1px solid #0d9488;
|
|
285
|
+
--button-hover-border: 1px solid #14b8a6;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.btn-resume {
|
|
289
|
+
--button-color: transparent;
|
|
290
|
+
--button-text-color: var(--ds-gray-900);
|
|
291
|
+
--button-border: 1px solid var(--ds-gray-400);
|
|
292
|
+
--button-hover-color: var(--ds-gray-100);
|
|
293
|
+
--button-hover-text-color: var(--ds-gray-1000);
|
|
294
|
+
--button-hover-border: 1px solid var(--ds-gray-600);
|
|
295
|
+
}
|
|
296
|
+
|
|
279
297
|
.btn-sm {
|
|
280
298
|
--button-height: 32px;
|
|
281
299
|
--button-padding: 0 10px;
|
|
282
300
|
--button-font-size: var(--text-base);
|
|
283
301
|
}
|
|
284
302
|
|
|
303
|
+
.btn-xs {
|
|
304
|
+
--button-height: 28px;
|
|
305
|
+
--button-padding: 0 8px;
|
|
306
|
+
--button-font-size: var(--text-xs);
|
|
307
|
+
--button-border-radius: var(--radius-sm);
|
|
308
|
+
}
|
|
309
|
+
|
|
285
310
|
.btn-lg {
|
|
286
311
|
--button-height: 48px;
|
|
287
312
|
--button-padding: 0 20px;
|
|
@@ -526,4 +551,9 @@
|
|
|
526
551
|
.shimmer-card {
|
|
527
552
|
--shimmer-height: 90px;
|
|
528
553
|
}
|
|
554
|
+
|
|
555
|
+
.btn-xs {
|
|
556
|
+
min-height: 36px;
|
|
557
|
+
padding: 6px 12px;
|
|
558
|
+
}
|
|
529
559
|
}
|
package/src/lib/types/config.ts
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { goto } from '$app/navigation';
|
|
3
|
+
import { page } from '$app/stores';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<svelte:head>
|
|
7
|
+
<title>Error - Shooter</title>
|
|
8
|
+
</svelte:head>
|
|
9
|
+
|
|
10
|
+
<main class="error-page">
|
|
11
|
+
<div class="error-content">
|
|
12
|
+
<div class="error-code">{$page.status}</div>
|
|
13
|
+
<h1 class="error-title">
|
|
14
|
+
{#if $page.status === 404}
|
|
15
|
+
Page not found
|
|
16
|
+
{:else}
|
|
17
|
+
Something went wrong
|
|
18
|
+
{/if}
|
|
19
|
+
</h1>
|
|
20
|
+
<p class="error-message">
|
|
21
|
+
{#if $page.error?.message}
|
|
22
|
+
{$page.error.message}
|
|
23
|
+
{:else if $page.status === 404}
|
|
24
|
+
The page you're looking for doesn't exist or has been moved.
|
|
25
|
+
{:else}
|
|
26
|
+
An unexpected error occurred. Try refreshing or going back.
|
|
27
|
+
{/if}
|
|
28
|
+
</p>
|
|
29
|
+
<div class="error-actions">
|
|
30
|
+
<button class="error-btn" onclick={() => goto('/')}>Go Home</button>
|
|
31
|
+
<button class="error-btn error-btn-secondary" onclick={() => { history.back(); }}>Go Back</button>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</main>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
.error-page {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
min-height: 60vh;
|
|
42
|
+
padding: var(--space-6);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.error-content {
|
|
46
|
+
text-align: center;
|
|
47
|
+
max-width: 400px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.error-code {
|
|
51
|
+
font-size: 4rem;
|
|
52
|
+
font-weight: 700;
|
|
53
|
+
color: var(--color-text-tertiary, #555);
|
|
54
|
+
line-height: 1;
|
|
55
|
+
margin-bottom: var(--space-2);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.error-title {
|
|
59
|
+
font-size: 1.25rem;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
margin-bottom: var(--space-3);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.error-message {
|
|
65
|
+
color: var(--color-text-secondary, #888);
|
|
66
|
+
font-size: 0.875rem;
|
|
67
|
+
line-height: 1.5;
|
|
68
|
+
margin-bottom: var(--space-5);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.error-actions {
|
|
72
|
+
display: flex;
|
|
73
|
+
gap: var(--space-3);
|
|
74
|
+
justify-content: center;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.error-btn {
|
|
78
|
+
padding: 10px 20px;
|
|
79
|
+
border-radius: 8px;
|
|
80
|
+
font-size: 0.875rem;
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
border: none;
|
|
84
|
+
background: var(--color-accent, #0d9488);
|
|
85
|
+
color: white;
|
|
86
|
+
min-height: 44px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.error-btn-secondary {
|
|
90
|
+
background: transparent;
|
|
91
|
+
border: 1px solid var(--border, #333);
|
|
92
|
+
color: var(--color-text-secondary, #888);
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import '$lib/theme.css';
|
|
4
4
|
import { goto } from '$app/navigation';
|
|
5
5
|
import { page } from '$app/stores';
|
|
6
|
-
import { Button } from '@juspay/svelte-ui-components';
|
|
7
6
|
import { StatusBadge } from '$lib/modules/client/common';
|
|
8
7
|
import { onMount, type Snippet } from 'svelte';
|
|
9
8
|
|
|
@@ -50,18 +49,27 @@
|
|
|
50
49
|
|
|
51
50
|
<div class="nav-right">
|
|
52
51
|
<StatusBadge status={systemStatus} />
|
|
53
|
-
<
|
|
54
|
-
|
|
52
|
+
<button
|
|
53
|
+
class="btn-gear {$page.url.pathname === '/config' ? 'btn-gear-active' : ''}"
|
|
55
54
|
onclick={() => goto('/config')}
|
|
56
55
|
aria-label="Settings"
|
|
57
56
|
>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
<svg
|
|
58
|
+
width="18"
|
|
59
|
+
height="18"
|
|
60
|
+
viewBox="0 0 24 24"
|
|
61
|
+
fill="none"
|
|
62
|
+
stroke="currentColor"
|
|
63
|
+
stroke-width="2"
|
|
64
|
+
stroke-linecap="round"
|
|
65
|
+
stroke-linejoin="round"
|
|
66
|
+
>
|
|
67
|
+
<circle cx="12" cy="12" r="3"></circle>
|
|
68
|
+
<path
|
|
69
|
+
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
|
|
70
|
+
></path>
|
|
71
|
+
</svg>
|
|
72
|
+
</button>
|
|
65
73
|
</div>
|
|
66
74
|
</div>
|
|
67
75
|
</header>
|
|
@@ -77,10 +85,20 @@
|
|
|
77
85
|
<a
|
|
78
86
|
href="/"
|
|
79
87
|
class="tab-item"
|
|
80
|
-
class:active={$page.url.pathname === '/' ||
|
|
88
|
+
class:active={$page.url.pathname === '/' ||
|
|
89
|
+
$page.url.pathname.startsWith('/project') ||
|
|
90
|
+
$page.url.pathname.startsWith('/session')}
|
|
81
91
|
>
|
|
82
|
-
<svg
|
|
83
|
-
|
|
92
|
+
<svg
|
|
93
|
+
viewBox="0 0 24 24"
|
|
94
|
+
fill="none"
|
|
95
|
+
stroke="currentColor"
|
|
96
|
+
stroke-width="1.8"
|
|
97
|
+
stroke-linecap="round"
|
|
98
|
+
stroke-linejoin="round"
|
|
99
|
+
>
|
|
100
|
+
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
|
|
101
|
+
></path>
|
|
84
102
|
</svg>
|
|
85
103
|
<span>Projects</span>
|
|
86
104
|
</a>
|
|
@@ -89,7 +107,14 @@
|
|
|
89
107
|
class="tab-item"
|
|
90
108
|
class:active={$page.url.pathname.startsWith('/terminals')}
|
|
91
109
|
>
|
|
92
|
-
<svg
|
|
110
|
+
<svg
|
|
111
|
+
viewBox="0 0 24 24"
|
|
112
|
+
fill="none"
|
|
113
|
+
stroke="currentColor"
|
|
114
|
+
stroke-width="1.8"
|
|
115
|
+
stroke-linecap="round"
|
|
116
|
+
stroke-linejoin="round"
|
|
117
|
+
>
|
|
93
118
|
<polyline points="4 17 10 11 4 5"></polyline>
|
|
94
119
|
<line x1="12" y1="19" x2="20" y2="19"></line>
|
|
95
120
|
</svg>
|
|
@@ -106,27 +131,37 @@
|
|
|
106
131
|
gap: var(--space-2);
|
|
107
132
|
}
|
|
108
133
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
134
|
+
.btn-gear {
|
|
135
|
+
background: transparent;
|
|
136
|
+
color: var(--text-muted);
|
|
137
|
+
border: none;
|
|
138
|
+
padding: 0;
|
|
139
|
+
height: 36px;
|
|
140
|
+
width: 36px;
|
|
141
|
+
border-radius: var(--radius-md);
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
}
|
|
147
|
+
.btn-gear:hover {
|
|
148
|
+
background: var(--component-bg);
|
|
149
|
+
color: var(--text-primary);
|
|
150
|
+
}
|
|
151
|
+
.btn-gear:focus-visible {
|
|
152
|
+
outline: 2px solid var(--ds-green-700);
|
|
153
|
+
outline-offset: 2px;
|
|
120
154
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
155
|
+
.btn-gear-active {
|
|
156
|
+
background: var(--component-bg);
|
|
157
|
+
color: var(--text-primary);
|
|
124
158
|
}
|
|
125
159
|
|
|
126
160
|
.content-area {
|
|
127
161
|
flex: 1;
|
|
128
162
|
overflow-y: auto;
|
|
129
163
|
-webkit-overflow-scrolling: touch;
|
|
164
|
+
padding-bottom: env(safe-area-inset-bottom, 0px);
|
|
130
165
|
}
|
|
131
166
|
|
|
132
167
|
.bottom-tabs {
|
|
@@ -178,9 +213,9 @@
|
|
|
178
213
|
|
|
179
214
|
/* Mobile: page headers stack vertically, buttons wrap */
|
|
180
215
|
@media (max-width: 480px) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
216
|
+
.btn-gear {
|
|
217
|
+
height: 44px;
|
|
218
|
+
width: 44px;
|
|
184
219
|
}
|
|
185
220
|
.bottom-tabs {
|
|
186
221
|
height: 60px;
|
package/src/routes/+page.svelte
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { ShooterConfig } from '$
|
|
2
|
+
import type { ProjectGroup, ShooterConfig } from '$generated/types';
|
|
3
3
|
|
|
4
4
|
import { goto } from '$app/navigation';
|
|
5
|
-
import { Button, Pill, Shimmer } from '@juspay/svelte-ui-components';
|
|
6
5
|
import {
|
|
6
|
+
clearCache,
|
|
7
7
|
EmptyState,
|
|
8
8
|
formatRelativeTime,
|
|
9
9
|
getCached,
|
|
@@ -11,17 +11,10 @@
|
|
|
11
11
|
isShooterConfig,
|
|
12
12
|
setCache,
|
|
13
13
|
} from '$lib/modules/client/common';
|
|
14
|
+
import { Banner, Button, Pill, Shimmer } from '@juspay/svelte-ui-components';
|
|
14
15
|
import { onDestroy, onMount } from 'svelte';
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
fullPath: string;
|
|
18
|
-
id: string;
|
|
19
|
-
lastModified: string;
|
|
20
|
-
name: string;
|
|
21
|
-
sessionCount: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const POLL_INTERVAL_MS = 30_000; // 30s - avoid heavy reflows
|
|
17
|
+
const POLL_INTERVAL_MS = 10_000;
|
|
25
18
|
const PAGE_SIZE = 20;
|
|
26
19
|
|
|
27
20
|
let projects = $state<ProjectGroup[]>([]);
|
|
@@ -29,6 +22,7 @@
|
|
|
29
22
|
let fetching = false; // non-reactive guard to prevent overlapping fetches
|
|
30
23
|
let config = $state<null | ShooterConfig>(null);
|
|
31
24
|
let pollTimer: null | ReturnType<typeof setInterval> = null;
|
|
25
|
+
let fetchError = $state<null | string>(null);
|
|
32
26
|
let hasMore = $state(false);
|
|
33
27
|
let currentOffset = $state(0);
|
|
34
28
|
|
|
@@ -46,7 +40,7 @@
|
|
|
46
40
|
void fetchSessions();
|
|
47
41
|
|
|
48
42
|
pollTimer = setInterval(() => {
|
|
49
|
-
if (config?.apiKey) {
|
|
43
|
+
if (config?.apiKey && currentOffset <= PAGE_SIZE) {
|
|
50
44
|
void fetchSessions();
|
|
51
45
|
}
|
|
52
46
|
}, POLL_INTERVAL_MS);
|
|
@@ -76,7 +70,7 @@
|
|
|
76
70
|
}
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
async function fetchSessions(append = false): Promise<void> {
|
|
73
|
+
async function fetchSessions(append = false, bustCache = false): Promise<void> {
|
|
80
74
|
if (!config?.apiKey || fetching) {
|
|
81
75
|
return;
|
|
82
76
|
}
|
|
@@ -90,16 +84,19 @@
|
|
|
90
84
|
const offset = append ? currentOffset : 0;
|
|
91
85
|
|
|
92
86
|
try {
|
|
93
|
-
const
|
|
87
|
+
const base = bustCache ? '/api/sessions?refresh=true&' : '/api/sessions?';
|
|
88
|
+
const response = await fetch(`${base}limit=${PAGE_SIZE}&offset=${offset}`, {
|
|
94
89
|
headers: {
|
|
95
90
|
Authorization: `Bearer ${config.apiKey}`,
|
|
96
91
|
},
|
|
97
92
|
});
|
|
98
93
|
|
|
99
94
|
if (!response.ok) {
|
|
95
|
+
fetchError = `Failed to load projects (HTTP ${response.status})`;
|
|
100
96
|
return;
|
|
101
97
|
}
|
|
102
98
|
|
|
99
|
+
fetchError = null;
|
|
103
100
|
const result: { projects: ProjectGroup[]; total?: number } = await response.json();
|
|
104
101
|
if (append) {
|
|
105
102
|
projects = [...projects, ...result.projects];
|
|
@@ -110,6 +107,7 @@
|
|
|
110
107
|
hasMore = result.total !== undefined ? projects.length < result.total : false;
|
|
111
108
|
setCache('shooter_projects', projects);
|
|
112
109
|
} catch (error) {
|
|
110
|
+
fetchError = 'Failed to load projects';
|
|
113
111
|
console.error('Failed to fetch sessions:', error);
|
|
114
112
|
} finally {
|
|
115
113
|
loading = false;
|
|
@@ -123,8 +121,8 @@
|
|
|
123
121
|
|
|
124
122
|
async function forceRefresh(): Promise<void> {
|
|
125
123
|
loading = true;
|
|
126
|
-
|
|
127
|
-
await fetchSessions();
|
|
124
|
+
clearCache('shooter_projects');
|
|
125
|
+
await fetchSessions(false, true);
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
function navigateToConfig(): void {
|
|
@@ -150,15 +148,17 @@
|
|
|
150
148
|
</div>
|
|
151
149
|
<div class="page-actions">
|
|
152
150
|
<Button classes="btn-secondary" onclick={forceRefresh} disabled={loading}>
|
|
153
|
-
{
|
|
154
|
-
|
|
155
|
-
Refresh
|
|
156
|
-
{/snippet}
|
|
151
|
+
<Icon name="refresh" size={14} />
|
|
152
|
+
Refresh
|
|
157
153
|
</Button>
|
|
158
154
|
</div>
|
|
159
155
|
</div>
|
|
160
156
|
</div>
|
|
161
157
|
|
|
158
|
+
{#if fetchError}
|
|
159
|
+
<Banner text={fetchError} classes="banner-error" />
|
|
160
|
+
{/if}
|
|
161
|
+
|
|
162
162
|
{#if loading && projects.length === 0}
|
|
163
163
|
<div class="loading-container">
|
|
164
164
|
{#each Array(5) as _, i (i)}
|
|
@@ -188,10 +188,13 @@
|
|
|
188
188
|
<h3 class="session-card-title">{project.name}</h3>
|
|
189
189
|
<div class="session-card-subtitle">{project.fullPath}</div>
|
|
190
190
|
</div>
|
|
191
|
-
<Pill text={formatRelativeTime(project.lastModified)} classes="pill-session-time" />
|
|
191
|
+
<Pill text="Last updated {formatRelativeTime(project.lastModified)}" classes="pill-session-time" />
|
|
192
192
|
</div>
|
|
193
193
|
<div class="session-stats">
|
|
194
|
-
<span
|
|
194
|
+
<span
|
|
195
|
+
><strong>{project.sessionCount}</strong>
|
|
196
|
+
{project.sessionCount === 1 ? 'session' : 'sessions'}</span
|
|
197
|
+
>
|
|
195
198
|
</div>
|
|
196
199
|
</a>
|
|
197
200
|
{/each}
|
|
@@ -7,7 +7,9 @@ import type { RequestHandler } from './$types';
|
|
|
7
7
|
|
|
8
8
|
export const GET: RequestHandler = ({ request }) => {
|
|
9
9
|
const authError = validateAuth(request);
|
|
10
|
-
if (authError) {
|
|
10
|
+
if (authError) {
|
|
11
|
+
return authError;
|
|
12
|
+
}
|
|
11
13
|
|
|
12
14
|
const apnsClient = new LibraryAPNsService();
|
|
13
15
|
const deviceToken = env.DEVICE_TOKEN?.trim();
|