@juspay/shooter 1.24.1 → 1.25.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.
Files changed (165) hide show
  1. package/.claude/hooks/notifier.cjs +32 -4
  2. package/bin/lib/service-manager.cjs +148 -0
  3. package/bin/shooter.cjs +151 -62
  4. package/build/client/_app/immutable/assets/{4.D4EDSN4H.css → 4.ChO_hlLs.css} +1 -1
  5. package/build/client/_app/immutable/assets/4.ChO_hlLs.css.br +0 -0
  6. package/build/client/_app/immutable/assets/4.ChO_hlLs.css.gz +0 -0
  7. package/build/client/_app/immutable/chunks/{DjWRwZyr.js → BstJSK2K.js} +1 -1
  8. package/build/client/_app/immutable/chunks/BstJSK2K.js.br +0 -0
  9. package/build/client/_app/immutable/chunks/BstJSK2K.js.gz +0 -0
  10. package/build/client/_app/immutable/chunks/{CfzjLyJm.js → DINqYbXU.js} +1 -1
  11. package/build/client/_app/immutable/chunks/DINqYbXU.js.br +0 -0
  12. package/build/client/_app/immutable/chunks/DINqYbXU.js.gz +0 -0
  13. package/build/client/_app/immutable/chunks/ssAhjWfF.js +3 -0
  14. package/build/client/_app/immutable/chunks/ssAhjWfF.js.br +0 -0
  15. package/build/client/_app/immutable/chunks/ssAhjWfF.js.gz +0 -0
  16. package/build/client/_app/immutable/entry/{app.9F0rhLIY.js → app.BPK9s2o5.js} +2 -2
  17. package/build/client/_app/immutable/entry/app.BPK9s2o5.js.br +0 -0
  18. package/build/client/_app/immutable/entry/app.BPK9s2o5.js.gz +0 -0
  19. package/build/client/_app/immutable/entry/start.DFPHuGE3.js +1 -0
  20. package/build/client/_app/immutable/entry/start.DFPHuGE3.js.br +2 -0
  21. package/build/client/_app/immutable/entry/start.DFPHuGE3.js.gz +0 -0
  22. package/build/client/_app/immutable/nodes/{0.MlMcxYLT.js → 0.BEbzRcwm.js} +1 -1
  23. package/build/client/_app/immutable/nodes/0.BEbzRcwm.js.br +0 -0
  24. package/build/client/_app/immutable/nodes/0.BEbzRcwm.js.gz +0 -0
  25. package/build/client/_app/immutable/nodes/{1._Bn-HQ9b.js → 1.C_V0SOr9.js} +1 -1
  26. package/build/client/_app/immutable/nodes/1.C_V0SOr9.js.br +0 -0
  27. package/build/client/_app/immutable/nodes/1.C_V0SOr9.js.gz +0 -0
  28. package/build/client/_app/immutable/nodes/{10.CsX0V4R9.js → 10.6V-37_Rl.js} +1 -1
  29. package/build/client/_app/immutable/nodes/10.6V-37_Rl.js.br +0 -0
  30. package/build/client/_app/immutable/nodes/10.6V-37_Rl.js.gz +0 -0
  31. package/build/client/_app/immutable/nodes/{11.lM_b6yUv.js → 11.Lzf-KC6L.js} +1 -1
  32. package/build/client/_app/immutable/nodes/11.Lzf-KC6L.js.br +0 -0
  33. package/build/client/_app/immutable/nodes/11.Lzf-KC6L.js.gz +0 -0
  34. package/build/client/_app/immutable/nodes/{2.sAnHf5go.js → 2.Cl2dMP2L.js} +1 -1
  35. package/build/client/_app/immutable/nodes/2.Cl2dMP2L.js.br +0 -0
  36. package/build/client/_app/immutable/nodes/2.Cl2dMP2L.js.gz +0 -0
  37. package/build/client/_app/immutable/nodes/{3.DEHWta3G.js → 3.CuX2eSna.js} +1 -1
  38. package/build/client/_app/immutable/nodes/3.CuX2eSna.js.br +0 -0
  39. package/build/client/_app/immutable/nodes/3.CuX2eSna.js.gz +0 -0
  40. package/build/client/_app/immutable/nodes/4.2DvqoOaB.js +17 -0
  41. package/build/client/_app/immutable/nodes/4.2DvqoOaB.js.br +0 -0
  42. package/build/client/_app/immutable/nodes/4.2DvqoOaB.js.gz +0 -0
  43. package/build/client/_app/immutable/nodes/{6.-gDjaLSz.js → 6.C7e6zQyP.js} +1 -1
  44. package/build/client/_app/immutable/nodes/6.C7e6zQyP.js.br +0 -0
  45. package/build/client/_app/immutable/nodes/6.C7e6zQyP.js.gz +0 -0
  46. package/build/client/_app/immutable/nodes/{7.R-emDnvX.js → 7.1ygvNTnO.js} +1 -1
  47. package/build/client/_app/immutable/nodes/7.1ygvNTnO.js.br +0 -0
  48. package/build/client/_app/immutable/nodes/7.1ygvNTnO.js.gz +0 -0
  49. package/build/client/_app/immutable/nodes/{8.DXNcFetv.js → 8.CBVmgOk0.js} +1 -1
  50. package/build/client/_app/immutable/nodes/8.CBVmgOk0.js.br +0 -0
  51. package/build/client/_app/immutable/nodes/8.CBVmgOk0.js.gz +0 -0
  52. package/build/client/_app/immutable/nodes/{9.Brv6N-Ji.js → 9.B-_ZFZhj.js} +1 -1
  53. package/build/client/_app/immutable/nodes/9.B-_ZFZhj.js.br +0 -0
  54. package/build/client/_app/immutable/nodes/9.B-_ZFZhj.js.gz +0 -0
  55. package/build/client/_app/version.json +1 -1
  56. package/build/client/_app/version.json.br +0 -0
  57. package/build/client/_app/version.json.gz +0 -0
  58. package/build/server/chunks/{0-CezVlDLP.js → 0-BHU07xt9.js} +2 -2
  59. package/build/server/chunks/{0-CezVlDLP.js.map → 0-BHU07xt9.js.map} +1 -1
  60. package/build/server/chunks/{1-CAwGzW00.js → 1-OVOd8GUH.js} +2 -2
  61. package/build/server/chunks/{1-CAwGzW00.js.map → 1-OVOd8GUH.js.map} +1 -1
  62. package/build/server/chunks/{10-pqorW2OP.js → 10-CRHtvb_u.js} +2 -2
  63. package/build/server/chunks/{10-pqorW2OP.js.map → 10-CRHtvb_u.js.map} +1 -1
  64. package/build/server/chunks/{11-Byxg_lSY.js → 11-CdSex9j1.js} +2 -2
  65. package/build/server/chunks/{11-Byxg_lSY.js.map → 11-CdSex9j1.js.map} +1 -1
  66. package/build/server/chunks/{2-Bbck5mN2.js → 2-bb78aIZ6.js} +2 -2
  67. package/build/server/chunks/{2-Bbck5mN2.js.map → 2-bb78aIZ6.js.map} +1 -1
  68. package/build/server/chunks/{3-BBFbA1P8.js → 3-CsTC6Lrn.js} +2 -2
  69. package/build/server/chunks/{3-BBFbA1P8.js.map → 3-CsTC6Lrn.js.map} +1 -1
  70. package/build/server/chunks/{4-w2W_T8ax.js → 4-DTTu8_Gr.js} +4 -4
  71. package/build/server/chunks/{4-w2W_T8ax.js.map → 4-DTTu8_Gr.js.map} +1 -1
  72. package/build/server/chunks/{6-BI3p-t3i.js → 6-BUgQGB_4.js} +2 -2
  73. package/build/server/chunks/{6-BI3p-t3i.js.map → 6-BUgQGB_4.js.map} +1 -1
  74. package/build/server/chunks/{7-6XKPVOSu.js → 7-CsQZnkcG.js} +2 -2
  75. package/build/server/chunks/{7-6XKPVOSu.js.map → 7-CsQZnkcG.js.map} +1 -1
  76. package/build/server/chunks/{8-VOztiJG_.js → 8-DcIuPdyW.js} +2 -2
  77. package/build/server/chunks/{8-VOztiJG_.js.map → 8-DcIuPdyW.js.map} +1 -1
  78. package/build/server/chunks/{9-DNUlBLEz.js → 9-D8bkM1uj.js} +2 -2
  79. package/build/server/chunks/{9-DNUlBLEz.js.map → 9-D8bkM1uj.js.map} +1 -1
  80. package/build/server/chunks/{_page.svelte-DDE2nChH.js → _page.svelte-BBbaKwNz.js} +101 -27
  81. package/build/server/chunks/_page.svelte-BBbaKwNz.js.map +1 -0
  82. package/build/server/chunks/{_server.ts-DfscXcFe.js → _server.ts-B7BLxK5u.js} +233 -186
  83. package/build/server/chunks/_server.ts-B7BLxK5u.js.map +1 -0
  84. package/build/server/chunks/{_server.ts-EJVmhLtg.js → _server.ts-BSS8cO80.js} +15 -3
  85. package/build/server/chunks/_server.ts-BSS8cO80.js.map +1 -0
  86. package/build/server/chunks/_server.ts-DNTxPoxO.js +115 -0
  87. package/build/server/chunks/_server.ts-DNTxPoxO.js.map +1 -0
  88. package/build/server/chunks/{_server.ts-D9_hkPQ6.js → _server.ts-DUb7fbuW.js} +17 -3
  89. package/build/server/chunks/_server.ts-DUb7fbuW.js.map +1 -0
  90. package/build/server/chunks/{_server.ts-v7TaT83B.js → _server.ts-FdKi8RwL.js} +7 -3
  91. package/build/server/chunks/_server.ts-FdKi8RwL.js.map +1 -0
  92. package/build/server/chunks/device-format-DTgEz4Yr.js +29 -0
  93. package/build/server/chunks/device-format-DTgEz4Yr.js.map +1 -0
  94. package/build/server/chunks/device-token-store-Ct7aTeR8.js +259 -0
  95. package/build/server/chunks/device-token-store-Ct7aTeR8.js.map +1 -0
  96. package/build/server/chunks/{library-apns-D8RPINlv.js → library-apns-DMlL1BAg.js} +158 -26
  97. package/build/server/chunks/library-apns-DMlL1BAg.js.map +1 -0
  98. package/build/server/index.js +1 -1
  99. package/build/server/index.js.map +1 -1
  100. package/build/server/manifest.js +17 -17
  101. package/build/server/manifest.js.map +1 -1
  102. package/package.json +2 -2
  103. package/server.ts +15 -1
  104. package/src/app.d.ts +4 -0
  105. package/src/lib/modules/server/apn/apns-classify.ts +103 -0
  106. package/src/lib/modules/server/apn/library-apns.ts +151 -35
  107. package/src/lib/modules/server/apn/notify-fanout.ts +40 -0
  108. package/src/lib/modules/server/fcm/fcm-classify.ts +61 -0
  109. package/src/lib/modules/server/fcm/fcm-service.ts +128 -29
  110. package/src/lib/modules/server/push/device-format.ts +42 -0
  111. package/src/lib/modules/server/push/device-token-store.ts +354 -0
  112. package/src/lib/types/apn.ts +4 -0
  113. package/src/lib/types/device.ts +156 -0
  114. package/src/lib/types/index.ts +1 -0
  115. package/src/routes/api/debug/+server.ts +13 -1
  116. package/src/routes/api/device-token/+server.ts +122 -37
  117. package/src/routes/api/health/+server.ts +16 -2
  118. package/src/routes/api/notify/+server.ts +175 -168
  119. package/src/routes/api/qr-config/+server.ts +9 -2
  120. package/src/routes/config/+page.svelte +182 -44
  121. package/build/client/_app/immutable/assets/4.D4EDSN4H.css.br +0 -0
  122. package/build/client/_app/immutable/assets/4.D4EDSN4H.css.gz +0 -0
  123. package/build/client/_app/immutable/chunks/BzW0vlVX.js +0 -3
  124. package/build/client/_app/immutable/chunks/BzW0vlVX.js.br +0 -0
  125. package/build/client/_app/immutable/chunks/BzW0vlVX.js.gz +0 -0
  126. package/build/client/_app/immutable/chunks/CfzjLyJm.js.br +0 -0
  127. package/build/client/_app/immutable/chunks/CfzjLyJm.js.gz +0 -0
  128. package/build/client/_app/immutable/chunks/DjWRwZyr.js.br +0 -0
  129. package/build/client/_app/immutable/chunks/DjWRwZyr.js.gz +0 -0
  130. package/build/client/_app/immutable/entry/app.9F0rhLIY.js.br +0 -0
  131. package/build/client/_app/immutable/entry/app.9F0rhLIY.js.gz +0 -0
  132. package/build/client/_app/immutable/entry/start.DGFWmhrj.js +0 -1
  133. package/build/client/_app/immutable/entry/start.DGFWmhrj.js.br +0 -2
  134. package/build/client/_app/immutable/entry/start.DGFWmhrj.js.gz +0 -0
  135. package/build/client/_app/immutable/nodes/0.MlMcxYLT.js.br +0 -0
  136. package/build/client/_app/immutable/nodes/0.MlMcxYLT.js.gz +0 -0
  137. package/build/client/_app/immutable/nodes/1._Bn-HQ9b.js.br +0 -0
  138. package/build/client/_app/immutable/nodes/1._Bn-HQ9b.js.gz +0 -0
  139. package/build/client/_app/immutable/nodes/10.CsX0V4R9.js.br +0 -0
  140. package/build/client/_app/immutable/nodes/10.CsX0V4R9.js.gz +0 -0
  141. package/build/client/_app/immutable/nodes/11.lM_b6yUv.js.br +0 -0
  142. package/build/client/_app/immutable/nodes/11.lM_b6yUv.js.gz +0 -0
  143. package/build/client/_app/immutable/nodes/2.sAnHf5go.js.br +0 -0
  144. package/build/client/_app/immutable/nodes/2.sAnHf5go.js.gz +0 -0
  145. package/build/client/_app/immutable/nodes/3.DEHWta3G.js.br +0 -0
  146. package/build/client/_app/immutable/nodes/3.DEHWta3G.js.gz +0 -0
  147. package/build/client/_app/immutable/nodes/4.C9fv_m2R.js +0 -16
  148. package/build/client/_app/immutable/nodes/4.C9fv_m2R.js.br +0 -0
  149. package/build/client/_app/immutable/nodes/4.C9fv_m2R.js.gz +0 -0
  150. package/build/client/_app/immutable/nodes/6.-gDjaLSz.js.br +0 -0
  151. package/build/client/_app/immutable/nodes/6.-gDjaLSz.js.gz +0 -0
  152. package/build/client/_app/immutable/nodes/7.R-emDnvX.js.br +0 -0
  153. package/build/client/_app/immutable/nodes/7.R-emDnvX.js.gz +0 -0
  154. package/build/client/_app/immutable/nodes/8.DXNcFetv.js.br +0 -0
  155. package/build/client/_app/immutable/nodes/8.DXNcFetv.js.gz +0 -0
  156. package/build/client/_app/immutable/nodes/9.Brv6N-Ji.js.br +0 -0
  157. package/build/client/_app/immutable/nodes/9.Brv6N-Ji.js.gz +0 -0
  158. package/build/server/chunks/_page.svelte-DDE2nChH.js.map +0 -1
  159. package/build/server/chunks/_server.ts-D2RS8TFd.js +0 -72
  160. package/build/server/chunks/_server.ts-D2RS8TFd.js.map +0 -1
  161. package/build/server/chunks/_server.ts-D9_hkPQ6.js.map +0 -1
  162. package/build/server/chunks/_server.ts-DfscXcFe.js.map +0 -1
  163. package/build/server/chunks/_server.ts-EJVmhLtg.js.map +0 -1
  164. package/build/server/chunks/_server.ts-v7TaT83B.js.map +0 -1
  165. package/build/server/chunks/library-apns-D8RPINlv.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_page.svelte-BBbaKwNz.js","sources":["../../../.svelte-kit/adapter-node/entries/pages/config/_page.svelte.js"],"sourcesContent":["import { b as attr_class, a as stringify, ab as attr, e as escape_html, c as ensure_array_like, h as head } from \"../../../chunks/index2.js\";\nimport \"../../../chunks/markdown.js\";\nimport { B as Button } from \"../../../chunks/Button.js\";\n/* empty css */\nimport { I as Input } from \"../../../chunks/Input.js\";\nimport { I as Icon } from \"../../../chunks/Icon.js\";\nimport { B as Banner } from \"../../../chunks/Banner.js\";\nfunction Step($$renderer, $$props) {\n $$renderer.component(($$renderer2) => {\n let { stepIndex, label, icon, classes } = $$props;\n $$renderer2.push(`<div${attr_class(`step ${stringify(classes ?? \"\")}`, \"svelte-1i4mzd9\")} role=\"button\" tabindex=\"0\">`);\n if (typeof icon === \"string\" && icon.length > 0) {\n $$renderer2.push(\"<!--[0-->\");\n $$renderer2.push(`<div class=\"step-icon-container\"><img class=\"step-icon\"${attr(\"src\", icon)} alt=\"\"/></div>`);\n } else {\n $$renderer2.push(\"<!--[-1-->\");\n $$renderer2.push(`<div class=\"step-index-container svelte-1i4mzd9\"><div class=\"step-index-text svelte-1i4mzd9\">${escape_html(stepIndex)}</div></div>`);\n }\n $$renderer2.push(`<!--]--> <div class=\"step-text svelte-1i4mzd9\">${escape_html(label)}</div> <div class=\"separator svelte-1i4mzd9\"></div></div>`);\n });\n}\nfunction Stepper($$renderer, $$props) {\n let { steps, currentStepIndex, classes } = $$props;\n $$renderer.push(`<div${attr_class(`container ${stringify(classes ?? \"\")}`, \"svelte-dvxh34\")}><!--[-->`);\n const each_array = ensure_array_like(steps);\n for (let stepIndex = 0, $$length = each_array.length; stepIndex < $$length; stepIndex++) {\n let currentStep = each_array[stepIndex];\n $$renderer.push(`<div${attr_class(\"step-container svelte-dvxh34\", void 0, {\n \"active-step\": currentStepIndex === stepIndex,\n \"completed-step\": currentStepIndex > stepIndex\n })}>`);\n Step($$renderer, {\n label: currentStep.label,\n icon: currentStep.icon,\n stepIndex: stepIndex + 1\n });\n $$renderer.push(`<!----></div>`);\n }\n $$renderer.push(`<!--]--></div>`);\n}\nfunction Card($$renderer, $$props) {\n $$renderer.component(($$renderer2) => {\n let { children, title, description, classes } = $$props;\n $$renderer2.push(`<div${attr_class(`card ${stringify(classes ?? \"\")}`, \"svelte-15b0v7e\")}>`);\n if (typeof title === \"string\" && title.length > 0) {\n $$renderer2.push(\"<!--[0-->\");\n $$renderer2.push(`<div class=\"card-header svelte-15b0v7e\"><div class=\"card-title svelte-15b0v7e\">${escape_html(title)}</div> `);\n if (typeof description === \"string\" && description.length > 0) {\n $$renderer2.push(\"<!--[0-->\");\n $$renderer2.push(`<div class=\"card-description svelte-15b0v7e\">${escape_html(description)}</div>`);\n } else {\n $$renderer2.push(\"<!--[-1-->\");\n }\n $$renderer2.push(`<!--]--></div>`);\n } else {\n $$renderer2.push(\"<!--[-1-->\");\n }\n $$renderer2.push(`<!--]--> <div class=\"card-content svelte-15b0v7e\">`);\n children($$renderer2);\n $$renderer2.push(`<!----></div></div>`);\n });\n}\nfunction toErrorMessage(err) {\n if (err instanceof Error) {\n return err.message;\n }\n if (typeof err === \"string\") {\n return err;\n }\n return String(err);\n}\nconst PROVIDERS = [\n {\n cors: \"proxy\",\n envKeys: [\"GOOGLE_AI_API_KEY\"],\n id: \"google-ai\",\n label: \"Google AI\",\n model: \"gemini-3.1-flash-lite-preview\"\n },\n {\n cors: \"proxy\",\n envKeys: [\"ANTHROPIC_API_KEY\"],\n id: \"anthropic\",\n label: \"Anthropic\",\n model: \"claude-haiku-4-5-20251001\"\n },\n {\n cors: \"proxy\",\n envKeys: [\"OPENAI_API_KEY\"],\n id: \"openai\",\n label: \"OpenAI\",\n model: \"gpt-4o-mini\"\n },\n {\n cors: \"proxy\",\n envKeys: [\"MISTRAL_API_KEY\"],\n id: \"mistral\",\n label: \"Mistral\",\n model: \"mistral-small-2506\"\n },\n {\n cors: \"proxy\",\n envKeys: [\"LITELLM_BASE_URL\"],\n id: \"litellm\",\n label: \"LiteLLM\",\n model: \"open-large\"\n }\n];\nconst AlertTriangleSvg = '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/>\\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/>\\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\\n</svg>\\n';\nconst CheckCircleSvg = '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\\n</svg>\\n';\nconst PlaySvg = '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\\n <polygon points=\"5 3 19 12 5 21 5 3\"/>\\n</svg>\\n';\nconst XCircleSvg = '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/>\\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\\n</svg>\\n';\nfunction _page($$renderer, $$props) {\n $$renderer.component(($$renderer2) => {\n const { data } = $$props;\n let serverUrl = \"\";\n let apiKey = \"\";\n let registeredDevices = [];\n let loadingDevices = false;\n let loadDevicesError = \"\";\n let thisDeviceId = \"\";\n let result = \"\";\n let loading = false;\n let statusType = \"\";\n let qrDataUrl = \"\";\n let qrServerUrl = \"\";\n let qrLoading = false;\n let qrError = \"\";\n async function fetchQrCode() {\n if (!apiKey.trim()) {\n qrError = \"Save an API key first to generate a QR code\";\n return;\n }\n qrLoading = true;\n qrError = \"\";\n qrDataUrl = \"\";\n qrServerUrl = \"\";\n try {\n const response = await fetch(\"/api/qr-config\", { headers: { Authorization: `Bearer ${apiKey.trim()}` } });\n if (!response.ok) {\n const data3 = await response.json();\n qrError = data3.error || \"Failed to generate QR code\";\n return;\n }\n const data2 = await response.json();\n qrDataUrl = data2.dataUrl;\n qrServerUrl = data2.serverUrl;\n } catch (error) {\n qrError = `Network error: ${toErrorMessage(error)}`;\n } finally {\n qrLoading = false;\n }\n }\n function getNativeBridge() {\n if (typeof window === \"undefined\") {\n return null;\n }\n if (window.ShooterBridge) {\n return window.ShooterBridge;\n }\n if (window.ShooterNativeBridge) {\n return window.ShooterNativeBridge;\n }\n return null;\n }\n function getDefaultServerUrl() {\n return window.location.origin;\n }\n async function saveConfiguration() {\n loading = true;\n result = \"\";\n statusType = \"\";\n try {\n const trimmedUrl = serverUrl.trim().replace(/\\/+$/, \"\");\n localStorage.setItem(\"shooter_config\", JSON.stringify({\n apiKey: apiKey.trim(),\n deviceToken: null,\n lastUpdated: Date.now(),\n serverUrl: trimmedUrl || getDefaultServerUrl()\n }));\n const bridge = getNativeBridge();\n if (bridge) {\n bridge.saveConfig?.(JSON.stringify({\n apiKey: apiKey.trim(),\n serverUrl: trimmedUrl || getDefaultServerUrl()\n }));\n }\n const response = await fetch(\"/api/health\");\n if (response.ok) {\n result = \"Configuration saved successfully\";\n statusType = \"success\";\n } else {\n result = \"Configuration saved but system health check failed\";\n statusType = \"warning\";\n }\n void loadDevices();\n } catch (error) {\n result = `Configuration failed: ${toErrorMessage(error)}`;\n statusType = \"error\";\n }\n loading = false;\n }\n async function testConfiguration() {\n if (!apiKey.trim()) {\n result = \"API key is required for testing\";\n statusType = \"error\";\n return;\n }\n loading = true;\n result = \"\";\n statusType = \"\";\n try {\n const testPayload = {\n data: { source: \"config-test\", timestamp: Date.now() },\n message: `Configuration test at ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`,\n title: \"Configuration Test\"\n };\n const response = await fetch(\"/api/notify\", {\n body: JSON.stringify(testPayload),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n method: \"POST\"\n });\n const data2 = await response.json();\n if (response.ok) {\n result = \"Test notification sent successfully\";\n statusType = \"success\";\n } else {\n result = `Test failed: ${typeof data2.error === \"string\" ? data2.error : \"Unknown error\"}`;\n statusType = \"error\";\n }\n } catch (error) {\n result = `Network error: ${toErrorMessage(error)}`;\n statusType = \"error\";\n }\n loading = false;\n }\n function clearConfiguration() {\n }\n async function loadDevices() {\n if (!apiKey.trim()) {\n registeredDevices = [];\n loadDevicesError = \"\";\n return;\n }\n loadingDevices = true;\n try {\n const response = await fetch(\"/api/device-token\", { headers: { Authorization: `Bearer ${apiKey.trim()}` } });\n if (response.ok) {\n const data2 = await response.json();\n registeredDevices = Array.isArray(data2.devices) ? data2.devices : [];\n loadDevicesError = \"\";\n } else {\n registeredDevices = [];\n loadDevicesError = response.status === 401 ? \"Could not load devices: the API key was rejected (401). Check the key above.\" : `Could not load devices (HTTP ${response.status}).`;\n }\n } catch (error) {\n registeredDevices = [];\n loadDevicesError = `Could not load devices: ${toErrorMessage(error)}`;\n }\n loadingDevices = false;\n }\n async function removeDevice(id) {\n result = \"\";\n statusType = \"\";\n try {\n const response = await fetch(\"/api/device-token\", {\n body: JSON.stringify({ id }),\n headers: {\n Authorization: `Bearer ${apiKey.trim()}`,\n \"Content-Type\": \"application/json\"\n },\n method: \"DELETE\"\n });\n if (!response.ok) {\n const data2 = await response.json().catch(() => ({}));\n result = `Failed to remove device: ${data2.error ?? response.statusText}`;\n statusType = \"error\";\n return;\n }\n } catch (error) {\n result = `Failed to remove device: ${toErrorMessage(error)}`;\n statusType = \"error\";\n return;\n }\n await loadDevices();\n }\n let $$settled = true;\n let $$inner_renderer;\n function $$render_inner($$renderer3) {\n head(\"1gp6n77\", $$renderer3, ($$renderer4) => {\n $$renderer4.title(($$renderer5) => {\n $$renderer5.push(`<title>Settings - Shooter</title>`);\n });\n $$renderer4.push(`<meta name=\"description\" content=\"Configure notification system settings\"/>`);\n });\n $$renderer3.push(`<main class=\"main\"><div class=\"settings-container svelte-1gp6n77\"><div style=\"margin-bottom: var(--space-4);\"><a href=\"/\" class=\"back-link\">← Back to Projects</a></div> <div class=\"page-header\"><h1 class=\"page-title\">Settings</h1> <p class=\"page-description\">Configure your API credentials and notification preferences</p></div> <div class=\"settings-grid svelte-1gp6n77\"><section class=\"settings-section svelte-1gp6n77\">`);\n Card($$renderer3, {\n title: \"Server Configuration\",\n description: \"Configure server connection and credentials\",\n children: ($$renderer4) => {\n Input($$renderer4, {\n name: \"serverUrl\",\n label: \"Server URL\",\n dataType: \"text\",\n placeholder: \"https://shooter.breezehq.dev\",\n infoMessage: \"Base URL of your Shooter server. Apps will reload with this URL on next launch.\",\n get value() {\n return serverUrl;\n },\n set value($$value) {\n serverUrl = $$value;\n $$settled = false;\n }\n });\n $$renderer4.push(`<!----> `);\n Input($$renderer4, {\n name: \"apiKey\",\n label: \"API Key\",\n dataType: \"password\",\n placeholder: \"Enter your API key\",\n infoMessage: \"Required for sending notifications\",\n get value() {\n return apiKey;\n },\n set value($$value) {\n apiKey = $$value;\n $$settled = false;\n }\n });\n $$renderer4.push(`<!----> <p class=\"input-help svelte-1gp6n77\">Find this in your <code class=\"svelte-1gp6n77\">~/.shooter/.env</code> file. Run <code class=\"svelte-1gp6n77\">shooter setup</code> to generate\n one.</p>`);\n }\n });\n $$renderer3.push(`<!----> `);\n Card($$renderer3, {\n title: \"Registered Devices\",\n description: \"Phones that receive push notifications\",\n children: ($$renderer4) => {\n if (loadingDevices) {\n $$renderer4.push(\"<!--[0-->\");\n $$renderer4.push(`<p class=\"input-help svelte-1gp6n77\">Loading…</p>`);\n } else if (loadDevicesError) {\n $$renderer4.push(\"<!--[1-->\");\n $$renderer4.push(`<p class=\"input-help svelte-1gp6n77\" style=\"color: var(--color-error, #f87171);\">${escape_html(loadDevicesError)}</p>`);\n } else if (registeredDevices.length === 0) {\n $$renderer4.push(\"<!--[2-->\");\n $$renderer4.push(`<p class=\"input-help svelte-1gp6n77\">No devices registered yet. Open the Shooter app on your phone with this server's URL +\n API key — it registers automatically. Every notification fans out to all devices here.</p>`);\n } else {\n $$renderer4.push(\"<!--[-1-->\");\n $$renderer4.push(`<ul class=\"device-list svelte-1gp6n77\"><!--[-->`);\n const each_array = ensure_array_like(registeredDevices);\n for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n let device = each_array[$$index];\n $$renderer4.push(`<li class=\"device-row svelte-1gp6n77\"><div class=\"device-meta svelte-1gp6n77\"><span class=\"device-name svelte-1gp6n77\">${escape_html(device.friendlyName || device.deviceId || \"Unknown device\")} `);\n if (device.deviceId && device.deviceId === thisDeviceId) {\n $$renderer4.push(\"<!--[0-->\");\n $$renderer4.push(`<span class=\"device-badge svelte-1gp6n77\">this device</span>`);\n } else {\n $$renderer4.push(\"<!--[-1-->\");\n }\n $$renderer4.push(`<!--]--></span> <span class=\"device-sub svelte-1gp6n77\">${escape_html(device.platform)} · ${escape_html(device.appEnv)} · ${escape_html(device.tokenMasked)}</span></div> `);\n Button($$renderer4, {\n classes: \"btn-secondary\",\n onclick: () => void removeDevice(device.id),\n text: \"Remove\"\n });\n $$renderer4.push(`<!----></li>`);\n }\n $$renderer4.push(`<!--]--></ul>`);\n }\n $$renderer4.push(`<!--]-->`);\n }\n });\n $$renderer3.push(`<!----> `);\n if (result) {\n $$renderer3.push(\"<!--[0-->\");\n const bannerSvg = statusType === \"success\" ? CheckCircleSvg : statusType === \"error\" ? XCircleSvg : AlertTriangleSvg;\n {\n let icon = function($$renderer4) {\n Icon($$renderer4, { svg: bannerSvg, classes: \"icon-16\" });\n };\n Banner($$renderer3, {\n text: result,\n classes: `banner-${stringify(statusType || \"info\")}`,\n icon,\n $$slots: { icon: true }\n });\n }\n } else {\n $$renderer3.push(\"<!--[-1-->\");\n }\n $$renderer3.push(`<!--]--> <div class=\"button-group svelte-1gp6n77\">`);\n Button($$renderer3, {\n classes: \"btn-secondary\",\n onclick: testConfiguration,\n disabled: loading || !apiKey.trim(),\n children: ($$renderer4) => {\n if (!loading) {\n $$renderer4.push(\"<!--[0-->\");\n Icon($$renderer4, { svg: PlaySvg, classes: \"icon-14\" });\n } else {\n $$renderer4.push(\"<!--[-1-->\");\n }\n $$renderer4.push(`<!--]--> Test Connection`);\n },\n $$slots: { default: true }\n });\n $$renderer3.push(`<!----> `);\n Button($$renderer3, {\n classes: \"btn-primary\",\n onclick: saveConfiguration,\n disabled: loading || !apiKey.trim(),\n showLoader: loading,\n text: \"Save Changes\"\n });\n $$renderer3.push(`<!----></div></section> <aside class=\"settings-sidebar svelte-1gp6n77\">`);\n Card($$renderer3, {\n title: \"Setup Guide\",\n children: ($$renderer4) => {\n Stepper($$renderer4, {\n steps: [\n { label: \"Get API Key\" },\n { label: \"Register a Device\" },\n { label: \"Test Connection\" }\n ],\n currentStepIndex: apiKey.trim() && registeredDevices.length > 0 ? 2 : apiKey.trim() ? 1 : 0,\n classes: \"setup-stepper\"\n });\n }\n });\n $$renderer3.push(`<!----> `);\n Card($$renderer3, {\n title: \"Mobile App Setup\",\n description: \"Scan to connect your mobile app\",\n children: ($$renderer4) => {\n $$renderer4.push(`<div class=\"qr-section svelte-1gp6n77\">`);\n {\n $$renderer4.push(\"<!--[-1-->\");\n if (qrDataUrl) {\n $$renderer4.push(\"<!--[0-->\");\n $$renderer4.push(`<div class=\"qr-container svelte-1gp6n77\"><img${attr(\"src\", qrDataUrl)} alt=\"QR code for mobile app pairing\" class=\"qr-image svelte-1gp6n77\"/></div> <p class=\"qr-hint svelte-1gp6n77\">Scan this QR code with the Shooter iOS or Android app to connect.</p> `);\n if (qrServerUrl) {\n $$renderer4.push(\"<!--[0-->\");\n $$renderer4.push(`<p class=\"qr-server-url svelte-1gp6n77\">Server: <code class=\"svelte-1gp6n77\">${escape_html(qrServerUrl)}</code></p>`);\n } else {\n $$renderer4.push(\"<!--[-1-->\");\n }\n $$renderer4.push(`<!--]-->`);\n } else if (qrLoading) {\n $$renderer4.push(\"<!--[1-->\");\n $$renderer4.push(`<div class=\"qr-placeholder svelte-1gp6n77\"><p class=\"qr-loading-text svelte-1gp6n77\">Generating QR code...</p></div>`);\n } else if (qrError) {\n $$renderer4.push(\"<!--[2-->\");\n $$renderer4.push(`<p class=\"qr-error svelte-1gp6n77\">${escape_html(qrError)}</p>`);\n } else {\n $$renderer4.push(\"<!--[-1-->\");\n $$renderer4.push(`<p class=\"qr-description svelte-1gp6n77\">Generate a QR code containing your server URL and API key. Your mobile app can\n scan it to auto-configure the connection.</p>`);\n }\n $$renderer4.push(`<!--]--> `);\n Button($$renderer4, {\n classes: \"btn-secondary btn-sm\",\n onclick: fetchQrCode,\n disabled: qrLoading || !apiKey.trim(),\n text: qrDataUrl ? \"Regenerate QR Code\" : \"Generate QR Code\"\n });\n $$renderer4.push(`<!---->`);\n }\n $$renderer4.push(`<!--]--></div>`);\n }\n });\n $$renderer3.push(`<!----> `);\n Card($$renderer3, {\n title: \"AI Providers\",\n description: \"NeuroLink-powered summaries and AI features\",\n children: ($$renderer4) => {\n $$renderer4.push(`<div class=\"ai-providers svelte-1gp6n77\"><!--[-->`);\n const each_array_1 = ensure_array_like(PROVIDERS);\n for (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {\n let provider = each_array_1[$$index_1];\n $$renderer4.push(`<div class=\"provider-row svelte-1gp6n77\">`);\n Icon($$renderer4, {\n svg: data.aiProviders[provider.id] ? CheckCircleSvg : XCircleSvg,\n classes: \"icon-14\"\n });\n $$renderer4.push(`<!----> <span class=\"provider-label svelte-1gp6n77\">${escape_html(provider.label)}</span> <span${attr_class(\"provider-status svelte-1gp6n77\", void 0, { \"configured\": data.aiProviders[provider.id] })}>${escape_html(data.aiProviders[provider.id] ? \"configured\" : \"not configured\")}</span></div>`);\n }\n $$renderer4.push(`<!--]--> `);\n if (data.activeProvider) {\n $$renderer4.push(\"<!--[0-->\");\n $$renderer4.push(`<div class=\"active-provider svelte-1gp6n77\">Active: <strong>${escape_html(data.activeProvider)}</strong></div>`);\n } else if (Object.values(data.aiProviders).some(Boolean)) {\n $$renderer4.push(\"<!--[1-->\");\n $$renderer4.push(`<div class=\"active-provider svelte-1gp6n77\">Auto-detected from configured keys</div>`);\n } else {\n $$renderer4.push(\"<!--[-1-->\");\n $$renderer4.push(`<p class=\"ai-help svelte-1gp6n77\">Run <code class=\"svelte-1gp6n77\">shooter setup</code> to configure AI providers for summaries.</p>`);\n }\n $$renderer4.push(`<!--]--></div>`);\n }\n });\n $$renderer3.push(`<!----> `);\n Card($$renderer3, {\n title: \"Danger Zone\",\n children: ($$renderer4) => {\n $$renderer4.push(`<p class=\"danger-description svelte-1gp6n77\">Clear all saved configuration data from this device.</p> `);\n Button($$renderer4, {\n classes: \"btn-danger btn-sm\",\n onclick: clearConfiguration,\n text: \"Clear Configuration\"\n });\n $$renderer4.push(`<!---->`);\n }\n });\n $$renderer3.push(`<!----></aside></div></div></main>`);\n }\n do {\n $$settled = true;\n $$inner_renderer = $$renderer2.copy();\n $$render_inner($$inner_renderer);\n } while (!$$settled);\n $$renderer2.subsume($$inner_renderer);\n });\n}\nexport {\n _page as default\n};\n"],"names":[],"mappings":"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"}
@@ -1,11 +1,10 @@
1
1
  import { b as private_env } from './shared-server-DaWdgxVh.js';
2
- import { existsSync, readFileSync } from 'fs';
3
- import { homedir } from 'os';
4
- import { join } from 'path';
5
- import { L as LibraryAPNsService } from './library-apns-D8RPINlv.js';
2
+ import { L as LibraryAPNsService } from './library-apns-DMlL1BAg.js';
6
3
  import { c as createPendingRequest } from './pending-requests-8rWjrF6d.js';
7
4
  import { v as validateAuth } from './auth-DuunT7Cg.js';
8
5
  import admin from 'firebase-admin';
6
+ import { m as maskToken } from './device-format-DTgEz4Yr.js';
7
+ import { d as deviceTokenStore } from './device-token-store-Ct7aTeR8.js';
9
8
  import { t as toErrorMessage } from './error-DDXB3duW.js';
10
9
  import { b as broadcastEvent } from './guest-registry-Dxvd7p-g.js';
11
10
  import './super-session-handler-DPyxFgmz.js';
@@ -14,34 +13,15 @@ import 'child_process';
14
13
  import 'jsonwebtoken';
15
14
  import 'util';
16
15
  import 'better-sqlite3';
16
+ import 'fs';
17
+ import 'path';
17
18
  import './shooter-home-4f_HkdGI.js';
19
+ import 'os';
18
20
  import 'crypto';
19
21
  import './registry-D4J_CuzW.js';
20
22
  import './qwen-reader-DGfUbKaJ.js';
21
23
  import './coordinator-DMU_ADXf.js';
22
24
 
23
- const normalize = (value) => {
24
- const trimmed = value?.trim();
25
- return trimmed ? trimmed : void 0;
26
- };
27
- function readPersistedDeviceToken(platform) {
28
- const tokensFile = join(homedir(), ".shooter", "device-tokens.json");
29
- if (!existsSync(tokensFile)) {
30
- return void 0;
31
- }
32
- try {
33
- const parsed = JSON.parse(readFileSync(tokensFile, "utf-8"));
34
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
35
- const value = parsed[platform];
36
- return typeof value === "string" && value ? value : void 0;
37
- }
38
- } catch {
39
- }
40
- return void 0;
41
- }
42
- function resolveDeviceToken(requestToken, persistedToken, envToken) {
43
- return normalize(requestToken) ?? normalize(persistedToken) ?? normalize(envToken);
44
- }
45
25
  const MAX_HISTORY = 100;
46
26
  const history = [];
47
27
  function addNotification(record) {
@@ -53,42 +33,140 @@ function addNotification(record) {
53
33
  function getNotifications(limit = 50) {
54
34
  return history.slice(0, limit);
55
35
  }
36
+ function selectPlatforms(platformFilter) {
37
+ if (platformFilter === "ios") {
38
+ return { doAndroid: false, doIos: true };
39
+ }
40
+ if (platformFilter === "android") {
41
+ return { doAndroid: true, doIos: false };
42
+ }
43
+ return { doAndroid: true, doIos: true };
44
+ }
45
+ function summarizeNotifyDelivery(apns, fcm) {
46
+ const sent = apns.totalSent + fcm.successCount;
47
+ const failed = apns.totalFailed + fcm.failureCount;
48
+ const staleTokens = [...apns.staleTokens, ...fcm.staleTokens];
49
+ const succeededTokens = [
50
+ ...apns.results.filter((r) => r.success).map((r) => r.token),
51
+ ...fcm.results.filter((r) => r.success).map((r) => r.token)
52
+ ];
53
+ return { delivered: sent > 0, failed, sent, staleTokens, succeededTokens };
54
+ }
55
+ const PRUNABLE_FCM_CODES = /* @__PURE__ */ new Set([
56
+ "messaging/registration-token-not-registered"
57
+ ]);
58
+ function chunk(items, size) {
59
+ const out = [];
60
+ for (let i = 0; i < items.length; i += size) {
61
+ out.push(items.slice(i, i + size));
62
+ }
63
+ return out;
64
+ }
65
+ function classifyFcmError(code) {
66
+ return code && PRUNABLE_FCM_CODES.has(code) ? "prune" : "keep";
67
+ }
68
+ function summarizeFcmFanOut(outcomes) {
69
+ const results = [];
70
+ const staleTokens = [];
71
+ let successCount = 0;
72
+ let failureCount = 0;
73
+ for (const o of outcomes) {
74
+ if (o.success) {
75
+ successCount += 1;
76
+ } else {
77
+ failureCount += 1;
78
+ if (classifyFcmError(o.errorCode) === "prune") {
79
+ staleTokens.push(o.token);
80
+ }
81
+ }
82
+ results.push({
83
+ error: o.errorCode,
84
+ messageId: o.messageId,
85
+ success: o.success,
86
+ token: o.token
87
+ });
88
+ }
89
+ return { failureCount, results, staleTokens, successCount };
90
+ }
56
91
  let app = null;
92
+ const FCM_MULTICAST_CHUNK = 100;
57
93
  function isFCMConfigured() {
58
94
  return !!(process.env.FCM_PROJECT_ID && process.env.FCM_CLIENT_EMAIL && process.env.FCM_PRIVATE_KEY);
59
95
  }
60
- async function sendFCMNotification(deviceToken, payload) {
96
+ async function sendFCMNotificationMulti(tokens, payload) {
97
+ if (tokens.length === 0) {
98
+ return { failureCount: 0, results: [], staleTokens: [], successCount: 0 };
99
+ }
100
+ let fcmApp;
61
101
  try {
62
- const fcmApp = getApp();
63
- const message = {
64
- android: {
65
- priority: "high",
66
- // Ensures delivery even in Doze mode
67
- ttl: 3e5
68
- // 5 minutes TTL (matches pending request expiry)
69
- },
70
- data: {
71
- body: payload.body || payload.message || "",
72
- category: payload.category ?? (typeof payload.data?.category === "string" ? payload.data.category : ""),
73
- project: typeof payload.data?.project === "string" ? payload.data.project : "",
74
- requestId: typeof payload.data?.requestId === "string" ? payload.data.requestId : "",
75
- source: typeof payload.data?.source === "string" ? payload.data.source : "",
76
- subtitle: payload.subtitle ?? "",
77
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
78
- title: payload.title,
79
- toolInput: payload.data?.toolInput ? JSON.stringify(payload.data.toolInput) : "",
80
- toolName: typeof payload.data?.toolName === "string" ? payload.data.toolName : "",
81
- type: typeof payload.data?.type === "string" ? payload.data.type : ""
82
- },
83
- token: deviceToken
84
- };
85
- const messageId = await admin.messaging(fcmApp).send(message);
86
- return { messageId, success: true };
102
+ fcmApp = getApp();
87
103
  } catch (error) {
88
- const errorMessage = error instanceof Error ? error.message : String(error);
89
- console.error("[FCM] Send failed:", errorMessage);
90
- return { error: errorMessage, success: false };
104
+ const msg = error instanceof Error ? error.message : String(error);
105
+ console.error("[FCM] multi-send setup failed:", fcmErrorLabel(error));
106
+ return {
107
+ failureCount: tokens.length,
108
+ results: tokens.map((token) => ({ error: msg, messageId: null, success: false, token })),
109
+ staleTokens: [],
110
+ successCount: 0
111
+ };
91
112
  }
113
+ const base = buildDataMessage(payload);
114
+ const outcomes = [];
115
+ for (const group of chunk(tokens, FCM_MULTICAST_CHUNK)) {
116
+ try {
117
+ const batch = await admin.messaging(fcmApp).sendEachForMulticast({ ...base, tokens: [...group] });
118
+ batch.responses.forEach((resp, i) => {
119
+ const errorCode = resp.error?.code ?? null;
120
+ if (errorCode === "messaging/invalid-argument") {
121
+ console.error(`[FCM] invalid-argument for token ${maskToken(group[i])}: ${errorCode}`);
122
+ }
123
+ outcomes.push({
124
+ errorCode,
125
+ messageId: resp.messageId ?? null,
126
+ success: resp.success,
127
+ token: group[i]
128
+ });
129
+ });
130
+ } catch (error) {
131
+ console.error("[FCM] multicast chunk failed:", fcmErrorLabel(error));
132
+ for (const token of group) {
133
+ outcomes.push({ errorCode: null, messageId: null, success: false, token });
134
+ }
135
+ }
136
+ }
137
+ return summarizeFcmFanOut(outcomes);
138
+ }
139
+ function buildDataMessage(payload) {
140
+ return {
141
+ android: {
142
+ priority: "high",
143
+ // Ensures delivery even in Doze mode
144
+ ttl: 3e5
145
+ // 5 minutes TTL (matches pending request expiry)
146
+ },
147
+ data: {
148
+ body: payload.body || payload.message || "",
149
+ category: payload.category ?? (typeof payload.data?.category === "string" ? payload.data.category : ""),
150
+ project: typeof payload.data?.project === "string" ? payload.data.project : "",
151
+ requestId: typeof payload.data?.requestId === "string" ? payload.data.requestId : "",
152
+ source: typeof payload.data?.source === "string" ? payload.data.source : "",
153
+ subtitle: payload.subtitle ?? "",
154
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
155
+ title: payload.title,
156
+ toolInput: payload.data?.toolInput ? JSON.stringify(payload.data.toolInput) : "",
157
+ toolName: typeof payload.data?.toolName === "string" ? payload.data.toolName : "",
158
+ type: typeof payload.data?.type === "string" ? payload.data.type : ""
159
+ }
160
+ };
161
+ }
162
+ function fcmErrorLabel(error) {
163
+ if (error && typeof error === "object" && "code" in error) {
164
+ const code = error.code;
165
+ if (typeof code === "string" && code.length > 0) {
166
+ return code;
167
+ }
168
+ }
169
+ return error instanceof Error ? error.message : String(error);
92
170
  }
93
171
  function getApp() {
94
172
  if (!app) {
@@ -113,6 +191,57 @@ function getAPNsClient() {
113
191
  }
114
192
  return apnsSingleton;
115
193
  }
194
+ const EMPTY_APNS_RESULT = {
195
+ results: [],
196
+ staleTokens: [],
197
+ totalFailed: 0,
198
+ totalSent: 0
199
+ };
200
+ const EMPTY_FCM_RESULT = {
201
+ failureCount: 0,
202
+ results: [],
203
+ staleTokens: [],
204
+ successCount: 0
205
+ };
206
+ function resolveAndroidTokens() {
207
+ const rows = deviceTokenStore.listActive("android");
208
+ if (rows.length > 0) {
209
+ return rows.map((r) => r.token);
210
+ }
211
+ const seed = private_env.ANDROID_DEVICE_TOKEN?.trim();
212
+ return seed ? [seed] : [];
213
+ }
214
+ function resolveIosDevices(override) {
215
+ const appEnv = serverApnEnv();
216
+ if (override) {
217
+ return [syntheticSeedDevice(override, "ios", appEnv)];
218
+ }
219
+ const rows = deviceTokenStore.listActiveForEnv("ios", appEnv);
220
+ if (rows.length > 0) {
221
+ return rows;
222
+ }
223
+ const seed = private_env.DEVICE_TOKEN?.trim();
224
+ return seed ? [syntheticSeedDevice(seed, "ios", appEnv)] : [];
225
+ }
226
+ function serverApnEnv() {
227
+ return private_env.APNS_PRODUCTION === "true" ? "production" : "sandbox";
228
+ }
229
+ function syntheticSeedDevice(token, platform, appEnv) {
230
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
231
+ return {
232
+ appEnv,
233
+ bundleId: null,
234
+ deviceId: null,
235
+ failureCount: 0,
236
+ friendlyName: null,
237
+ id: `seed-${platform}`,
238
+ isActive: true,
239
+ lastSeenAt: nowIso,
240
+ platform,
241
+ registeredAt: nowIso,
242
+ token
243
+ };
244
+ }
116
245
  const notificationCache = /* @__PURE__ */ new Map();
117
246
  const DEDUP_WINDOW = 1e4;
118
247
  function broadcastHookEvent(body) {
@@ -189,6 +318,9 @@ function buildNotificationRecord(id, title, message, status, data, error) {
189
318
  }
190
319
  function intelligentNotificationFilter(title, message, data, waitForResponse = false) {
191
320
  const source = data?.source || "unknown";
321
+ if (waitForResponse) {
322
+ return { reason: "Bidirectional request — never filtered", send: true };
323
+ }
192
324
  if (isDuplicateNotification(title, message, data, waitForResponse)) {
193
325
  return {
194
326
  reason: "Duplicate notification within 10-second window",
@@ -372,138 +504,53 @@ const POST = async ({ request }) => {
372
504
  ...subtitle ? { subtitle } : {},
373
505
  title
374
506
  };
375
- const platform = private_env.DEVICE_PLATFORM || "ios";
376
- if (platform === "android") {
377
- if (!isFCMConfigured()) {
378
- return json(
379
- {
380
- details: "Missing FCM_PROJECT_ID, FCM_CLIENT_EMAIL, or FCM_PRIVATE_KEY environment variables",
381
- error: "FCM not configured"
382
- },
383
- { status: 500 }
384
- );
385
- }
386
- const androidToken = resolveDeviceToken(
387
- requestDeviceToken,
388
- readPersistedDeviceToken("android"),
389
- private_env.ANDROID_DEVICE_TOKEN
390
- );
391
- if (!androidToken) {
392
- return json(
393
- {
394
- details: "No Android device token available — set ANDROID_DEVICE_TOKEN, pass deviceToken in the request body, or open the Android app so it can auto-register its FCM token.",
395
- error: "No device token configured"
396
- },
397
- { status: 500 }
398
- );
399
- }
400
- const fcmResult = await sendFCMNotification(androidToken, payload);
401
- if (fcmResult.success) {
402
- recordNotification(title, message, data);
403
- if (waitForResponse) {
404
- createPendingRequest(canonicalRequestId, {
405
- options,
406
- question: question ?? null,
407
- responseKind: responseKind ?? "hook",
408
- sessionId: data?.sessionId || "",
409
- toolInput: data?.toolInput || {},
410
- toolName: data?.toolName || ""
411
- });
412
- }
413
- addNotification(buildNotificationRecord(canonicalRequestId, title, message, "sent", data));
414
- return json({
415
- message: "Notification sent successfully",
416
- requestId: canonicalRequestId,
417
- result: { messageId: fcmResult.messageId },
418
- success: true,
419
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
420
- });
421
- } else {
422
- console.error(`[notify] FCM delivery failed: ${fcmResult.error}`);
423
- releaseNotification(title, message, data);
424
- addNotification(
425
- buildNotificationRecord(
426
- canonicalRequestId,
427
- title,
428
- message,
429
- "failed",
430
- data,
431
- fcmResult.error
432
- )
433
- );
434
- return json(
435
- {
436
- details: fcmResult.error,
437
- error: "Failed to send notification",
438
- requestId: canonicalRequestId,
439
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
440
- },
441
- { status: 500 }
442
- );
443
- }
507
+ const override = requestDeviceToken?.trim() || void 0;
508
+ const { doAndroid, doIos } = selectPlatforms(private_env.DEVICE_PLATFORM);
509
+ const iosDevices = doIos ? override ? resolveIosDevices(override) : resolveIosDevices() : [];
510
+ const androidTokens = doAndroid ? override ? [override] : resolveAndroidTokens() : [];
511
+ const collapseId = waitForResponse ? canonicalRequestId : void 0;
512
+ const [apnsResult, fcmResult] = await Promise.all([
513
+ iosDevices.length > 0 && apnsClient.isConfigured() ? apnsClient.sendToMany(iosDevices, payload, collapseId) : Promise.resolve(EMPTY_APNS_RESULT),
514
+ androidTokens.length > 0 && isFCMConfigured() ? sendFCMNotificationMulti(androidTokens, payload) : Promise.resolve(EMPTY_FCM_RESULT)
515
+ ]);
516
+ const summary = summarizeNotifyDelivery(apnsResult, fcmResult);
517
+ const pruned = !override && summary.staleTokens.length ? deviceTokenStore.pruneByTokens(summary.staleTokens) : 0;
518
+ if (summary.succeededTokens.length > 0) {
519
+ deviceTokenStore.touchLastSeen(summary.succeededTokens);
520
+ }
521
+ if (summary.delivered && summary.failed === 0) {
522
+ recordNotification(title, message, data);
444
523
  } else {
445
- if (!apnsClient.isConfigured()) {
446
- return json(
447
- {
448
- details: "Missing APNS_KEY, APNS_KEY_ID, or APNS_TEAM_ID environment variables",
449
- error: "APNs client not configured"
450
- },
451
- { status: 500 }
452
- );
453
- }
454
- const deviceToken = resolveDeviceToken(
455
- requestDeviceToken,
456
- readPersistedDeviceToken("ios"),
457
- private_env.DEVICE_TOKEN
458
- );
459
- if (!deviceToken) {
460
- return json(
461
- {
462
- details: "No iOS device token available — pass deviceToken in the request body, ensure ~/.shooter/device-tokens.json contains an ios token, or set DEVICE_TOKEN.",
463
- error: "No device token configured"
464
- },
465
- { status: 500 }
466
- );
467
- }
468
- try {
469
- const result = await apnsClient.sendNotification(deviceToken, payload);
470
- recordNotification(title, message, data);
471
- if (waitForResponse) {
472
- createPendingRequest(canonicalRequestId, {
473
- options,
474
- question: question ?? null,
475
- responseKind: responseKind ?? "hook",
476
- sessionId: data?.sessionId || "",
477
- toolInput: data?.toolInput || {},
478
- toolName: data?.toolName || ""
479
- });
480
- }
481
- addNotification(buildNotificationRecord(canonicalRequestId, title, message, "sent", data));
482
- return json({
483
- message: "Notification sent successfully",
484
- requestId: canonicalRequestId,
485
- result,
486
- success: true,
487
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
488
- });
489
- } catch (notificationError) {
490
- const notifErrMsg = toErrorMessage(notificationError);
491
- console.error(`[notify] APNs delivery failed: ${notifErrMsg}`);
492
- releaseNotification(title, message, data);
493
- addNotification(
494
- buildNotificationRecord(canonicalRequestId, title, message, "failed", data, notifErrMsg)
495
- );
496
- return json(
497
- {
498
- details: notifErrMsg,
499
- error: "Failed to send notification",
500
- requestId: canonicalRequestId,
501
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
502
- },
503
- { status: 500 }
504
- );
505
- }
524
+ releaseNotification(title, message, data);
506
525
  }
526
+ if (waitForResponse && summary.delivered) {
527
+ createPendingRequest(canonicalRequestId, {
528
+ options,
529
+ question: question ?? null,
530
+ responseKind: responseKind ?? "hook",
531
+ sessionId: data?.sessionId || "",
532
+ toolInput: data?.toolInput || {},
533
+ toolName: data?.toolName || ""
534
+ });
535
+ }
536
+ addNotification(
537
+ buildNotificationRecord(
538
+ canonicalRequestId,
539
+ title,
540
+ message,
541
+ summary.delivered ? "sent" : "failed",
542
+ data,
543
+ summary.delivered ? null : "No registered device accepted the notification"
544
+ )
545
+ );
546
+ return json({
547
+ failed: summary.failed,
548
+ pruned,
549
+ requestId: canonicalRequestId,
550
+ sent: summary.sent,
551
+ success: summary.delivered,
552
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
553
+ });
507
554
  } catch (error) {
508
555
  console.error("Notification error:", error);
509
556
  return json(
@@ -531,4 +578,4 @@ const GET = ({ request, url }) => {
531
578
  };
532
579
 
533
580
  export { GET, POST };
534
- //# sourceMappingURL=_server.ts-DfscXcFe.js.map
581
+ //# sourceMappingURL=_server.ts-B7BLxK5u.js.map