specrails-desktop 2.3.0 → 2.4.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/client/dist/assets/ActivityFeedPage-DJJlZ3mF.js +1 -0
- package/client/dist/assets/AgentsPage-49JaEDjR.js +86 -0
- package/client/dist/assets/{AnalyticsPage-Dyyz1ht3.js → AnalyticsPage-BUd3gWYC.js} +1 -1
- package/client/dist/assets/{BarChart-CMdLa6Es.js → BarChart-HDe_YoUD.js} +2 -2
- package/client/dist/assets/CodePage-CqPPND47.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-CTNwb639.js → DesktopAnalyticsPage-CgvmSvF0.js} +1 -1
- package/client/dist/assets/DocsDialog-hHFd3Ejs.js +11 -0
- package/client/dist/assets/DocsPage-B4R1aksg.js +11 -0
- package/client/dist/assets/{ExportDropdown-DuoZcdYN.js → ExportDropdown-f4dwQjlT.js} +1 -1
- package/client/dist/assets/IntegrationsPage-CX2Ybxx0.js +3 -0
- package/client/dist/assets/JobDetailPage-DN2Jc8Ti.js +16 -0
- package/client/dist/assets/JobsPage-DmdpqijT.js +1 -0
- package/client/dist/assets/{cssMode-Cc6ozl-J.js → cssMode-DzNPAYFh.js} +1 -1
- package/client/dist/assets/{dist-js-H6hyhSuv.js → dist-js-COfIfLRE.js} +1 -1
- package/client/dist/assets/{dist-js-4UEGaKhD.js → dist-js-CvScGQU_.js} +1 -1
- package/client/dist/assets/{editor.main-CfXxHimg.js → editor.main-C7Rmw-hR.js} +2 -2
- package/client/dist/assets/{freemarker2-DP7J1gG3.js → freemarker2-Cszs4SVo.js} +1 -1
- package/client/dist/assets/{handlebars-BjRlucw6.js → handlebars-Dp7Lsuym.js} +1 -1
- package/client/dist/assets/{html-OumBQJ-U.js → html-BURidrEm.js} +1 -1
- package/client/dist/assets/{htmlMode-CStc3zXM.js → htmlMode--k5M7GjZ.js} +1 -1
- package/client/dist/assets/index-DBpvYrDK.css +2 -0
- package/client/dist/assets/index-DGIXKRHE.js +142 -0
- package/client/dist/assets/{integrations-Cublz3m6.js → integrations-2C7MkGT0.js} +1 -1
- package/client/dist/assets/{integrations-HIlUxXVs.js → integrations-BDC670cg.js} +1 -1
- package/client/dist/assets/integrations-BqUmRUef.js +1 -0
- package/client/dist/assets/{integrations-DmQYCUvN.js → integrations-C2jQtv-s.js} +1 -1
- package/client/dist/assets/{integrations-DRdbki5W.js → integrations-CB98NeH5.js} +1 -1
- package/client/dist/assets/{integrations-C3p12Ms6.js → integrations-CX4p_bij.js} +1 -1
- package/client/dist/assets/{integrations-DaC4SzzL.js → integrations-_SuVeQIG.js} +1 -1
- package/client/dist/assets/{integrations-Cr6hH7XR.js → integrations-eQPHAYsE.js} +1 -1
- package/client/dist/assets/{javascript-CMk--e7g.js → javascript-kJQz__44.js} +1 -1
- package/client/dist/assets/jira-C-ATCti0.js +1 -0
- package/client/dist/assets/jira-CmVfRM-b.js +1 -0
- package/client/dist/assets/jira-D7bkKAX8.js +1 -0
- package/client/dist/assets/jira-DKImM1YH.js +1 -0
- package/client/dist/assets/jira-DOw8bkIR.js +1 -0
- package/client/dist/assets/jira-DlA-wGp-.js +1 -0
- package/client/dist/assets/jira-Fob8EGxN.js +1 -0
- package/client/dist/assets/jira-xZA2lixb.js +1 -0
- package/client/dist/assets/{jsonMode-C2h3ZcjZ.js → jsonMode-v5JYPpnz.js} +1 -1
- package/client/dist/assets/{lib-Cs5FrUJI.js → lib-Bro9Z0gp.js} +1 -1
- package/client/dist/assets/{liquid-mI3KJrBE.js → liquid-Dl9I6gWt.js} +1 -1
- package/client/dist/assets/{lspLanguageFeatures-DU09ggWi.js → lspLanguageFeatures-CPlEe0NK.js} +1 -1
- package/client/dist/assets/{mdx-C41VDTR_.js → mdx-Byl7TtzQ.js} +1 -1
- package/client/dist/assets/{monaco.contribution-CPObAXMC.js → monaco.contribution-YMAkHQcQ.js} +2 -2
- package/client/dist/assets/{python-Y27rKQtk.js → python-jWQwT6j2.js} +1 -1
- package/client/dist/assets/{razor-Cd5-q9Bp.js → razor-BWS3sP-E.js} +1 -1
- package/client/dist/assets/setup-C0dzw8j4.js +1 -0
- package/client/dist/assets/setup-C1IA-9YS.js +1 -0
- package/client/dist/assets/setup-CpfjaNut.js +1 -0
- package/client/dist/assets/setup-D3rNZA9A.js +1 -0
- package/client/dist/assets/setup-UD2aanGs.js +1 -0
- package/client/dist/assets/setup-WP6WOYQh.js +1 -0
- package/client/dist/assets/setup-gzLG8T6F.js +1 -0
- package/client/dist/assets/setup-pjgmYHx6.js +1 -0
- package/client/dist/assets/specs-4lA_u79w.js +1 -0
- package/client/dist/assets/{specs-D2FzlLn9.js → specs-BHjxcjOf.js} +1 -1
- package/client/dist/assets/{specs-CZ1PsXsC.js → specs-CXNQzPk9.js} +1 -1
- package/client/dist/assets/{specs-Dyc5hYeE.js → specs-DFnc2Huj.js} +1 -1
- package/client/dist/assets/{specs-BFfu3u-a.js → specs-DZCLH2-l.js} +1 -1
- package/client/dist/assets/{specs-B__C8-8a.js → specs-DgmyAE3N.js} +1 -1
- package/client/dist/assets/{specs-DaUTrNF9.js → specs-DicWhvwi.js} +1 -1
- package/client/dist/assets/{specs-k0PyLDVt.js → specs-dkro6lSM.js} +1 -1
- package/client/dist/assets/{tsMode-B0y_xEci.js → tsMode-BbOGOuSV.js} +1 -1
- package/client/dist/assets/{typescript-BzK0OgwW.js → typescript-eBtFQJLs.js} +1 -1
- package/client/dist/assets/{useProjectCache-BZWYV-w-.js → useProjectCache-D9juBhsO.js} +1 -1
- package/client/dist/assets/{workers-rt--R2Qy.js → workers-BvicOoDf.js} +1 -1
- package/client/dist/assets/{xml-eX9QXAmI.js → xml-BJepAPyM.js} +1 -1
- package/client/dist/assets/{yaml-fcsNkpOt.js → yaml-DabgV-eA.js} +1 -1
- package/client/dist/index.html +12 -11
- package/docs/jira-integration-plan.md +321 -0
- package/package.json +1 -1
- package/server/dist/db.js +80 -0
- package/server/dist/feature-flags.js +11 -0
- package/server/dist/jira/jira-adf.js +113 -0
- package/server/dist/jira/jira-backlog-config.js +58 -0
- package/server/dist/jira/jira-client.js +279 -0
- package/server/dist/jira/jira-credential-store.js +103 -0
- package/server/dist/jira/jira-db.js +341 -0
- package/server/dist/jira/jira-issue-fields.js +428 -0
- package/server/dist/jira/jira-materializer.js +250 -0
- package/server/dist/jira/jira-status-resolver.js +211 -0
- package/server/dist/jira/jira-sync-manager.js +1014 -0
- package/server/dist/jira/types.js +9 -0
- package/server/dist/jira-router.js +304 -0
- package/server/dist/project-registry.js +43 -1
- package/server/dist/project-router-tickets.js +49 -1
- package/server/dist/project-router.js +4 -0
- package/server/dist/rails-router.js +12 -0
- package/client/dist/assets/ActivityFeedPage-3Veccrvk.js +0 -1
- package/client/dist/assets/AgentsPage-2mFPghP4.js +0 -86
- package/client/dist/assets/CodePage-D7Xwjhut.js +0 -2
- package/client/dist/assets/DocsDialog-D8yoyZDD.js +0 -11
- package/client/dist/assets/DocsPage-CeO-fAxy.js +0 -11
- package/client/dist/assets/IntegrationsPage-iIZ0UEzf.js +0 -3
- package/client/dist/assets/JobDetailPage-DgJHAH2m.js +0 -16
- package/client/dist/assets/JobsPage-Bv_RpRAE.js +0 -1
- package/client/dist/assets/index-CGHKpC-N.js +0 -142
- package/client/dist/assets/index-D17R4Cjc.css +0 -2
- package/client/dist/assets/integrations-D28q1kF6.js +0 -1
- package/client/dist/assets/setup--FMCsnQS.js +0 -1
- package/client/dist/assets/setup-B19ZpBNi.js +0 -1
- package/client/dist/assets/setup-BZPmkjSN.js +0 -1
- package/client/dist/assets/setup-BqYA02rS.js +0 -1
- package/client/dist/assets/setup-ChKQDHN9.js +0 -1
- package/client/dist/assets/setup-D2n9jMfM.js +0 -1
- package/client/dist/assets/setup-P3r6YP1D.js +0 -1
- package/client/dist/assets/setup-fnfEbwlv.js +0 -1
- package/client/dist/assets/specs-cKEh2LXt.js +0 -1
- /package/client/dist/assets/{abap-Bw6f2wDG.js → abap-s65oMlhi.js} +0 -0
- /package/client/dist/assets/{activity-BdrPln96.js → activity-BqqwnH_h.js} +0 -0
- /package/client/dist/assets/{activity-BEIp_Y1A.js → activity-C8qqEIoP.js} +0 -0
- /package/client/dist/assets/{activity-CpkRS8Sx.js → activity-CZVM4nlJ.js} +0 -0
- /package/client/dist/assets/{activity-DOUVEjJi.js → activity-Cyy07Tgo.js} +0 -0
- /package/client/dist/assets/{activity-DRwkql_y.js → activity-DlbWCa4y.js} +0 -0
- /package/client/dist/assets/{activity-DKCpESPt.js → activity-Dwq0heud.js} +0 -0
- /package/client/dist/assets/{activity-DcDQ7tjw.js → activity-qFTcMyW9.js} +0 -0
- /package/client/dist/assets/{addon-image-3WCl5Vhd.js → addon-image-CpF0L0jM.js} +0 -0
- /package/client/dist/assets/{addon-ligatures-C5OdliKs.js → addon-ligatures-hXysGZrA.js} +0 -0
- /package/client/dist/assets/{addon-webgl-BbX6pSjl.js → addon-webgl-Cn1slavz.js} +0 -0
- /package/client/dist/assets/{addspec-D33ocMxf.js → addspec-B1FTtI2a.js} +0 -0
- /package/client/dist/assets/{addspec-DFswZ0jK.js → addspec-BCT9vm_c.js} +0 -0
- /package/client/dist/assets/{addspec-DVZ15Jp8.js → addspec-DeDOztDr.js} +0 -0
- /package/client/dist/assets/{addspec-Fkv91Opc.js → addspec-DpRgmfmx.js} +0 -0
- /package/client/dist/assets/{addspec-BEeF5-zc.js → addspec-Dw-0Dg-4.js} +0 -0
- /package/client/dist/assets/{addspec-B5yl4Loj.js → addspec-rp496P_F.js} +0 -0
- /package/client/dist/assets/{addspec-DRE-jZv7.js → addspec-v8j6A7CD.js} +0 -0
- /package/client/dist/assets/{agents-DK-Dlc0i.js → agents-23iPejcA.js} +0 -0
- /package/client/dist/assets/{agents-Q6Ldfpxx.js → agents-BDx1RXcl.js} +0 -0
- /package/client/dist/assets/{agents-TeOSy-ax.js → agents-BFr3kUhK.js} +0 -0
- /package/client/dist/assets/{agents-Bm9rPqnt.js → agents-B_1L9xRg.js} +0 -0
- /package/client/dist/assets/{agents-1nCDWRmP.js → agents-BlPnx-mz.js} +0 -0
- /package/client/dist/assets/{agents-iTqjRajS.js → agents-DcxZHzNr.js} +0 -0
- /package/client/dist/assets/{agents-s87sMGzL.js → agents-G3shOewU.js} +0 -0
- /package/client/dist/assets/{agentstudio-B6Wb59E7.js → agentstudio-B-CMAQqy.js} +0 -0
- /package/client/dist/assets/{agentstudio-D3I62TLJ.js → agentstudio-Bk1eZcv4.js} +0 -0
- /package/client/dist/assets/{agentstudio-DuH9TogZ.js → agentstudio-ChxNuGAu.js} +0 -0
- /package/client/dist/assets/{agentstudio-Kw88_dUF.js → agentstudio-DNlme601.js} +0 -0
- /package/client/dist/assets/{agentstudio-BdidyBzZ.js → agentstudio-DpP9caEE.js} +0 -0
- /package/client/dist/assets/{agentstudio-BSnWLR63.js → agentstudio-Y3G0ddJ2.js} +0 -0
- /package/client/dist/assets/{agentstudio-BADhZ41e.js → agentstudio-kk9RB7Se.js} +0 -0
- /package/client/dist/assets/{aiedit-DJMny-D5.js → aiedit-5ETerMK1.js} +0 -0
- /package/client/dist/assets/{aiedit-D2ji6Qy0.js → aiedit-BBCrOpHq.js} +0 -0
- /package/client/dist/assets/{aiedit-DAhZTvtk.js → aiedit-BMtcGYNE.js} +0 -0
- /package/client/dist/assets/{aiedit-DvrcbwGv.js → aiedit-D9ddlgkM.js} +0 -0
- /package/client/dist/assets/{aiedit-WBSjT_C1.js → aiedit-De0SOH6S.js} +0 -0
- /package/client/dist/assets/{aiedit-BWxHGsYA.js → aiedit-DrfzQroF.js} +0 -0
- /package/client/dist/assets/{aiedit-DOcxERkU.js → aiedit-fMltW101.js} +0 -0
- /package/client/dist/assets/{analytics-C9Zc-rkM.js → analytics-BeTyviO8.js} +0 -0
- /package/client/dist/assets/{analytics-CrPCZRJ-.js → analytics-C4eEO260.js} +0 -0
- /package/client/dist/assets/{analytics-CYj0tfj7.js → analytics-C67cIA1b.js} +0 -0
- /package/client/dist/assets/{analytics-C6EzgtdE.js → analytics-CAguvW28.js} +0 -0
- /package/client/dist/assets/{analytics-CVx3YOc0.js → analytics-DBtt8Mgk.js} +0 -0
- /package/client/dist/assets/{analytics-CnY4kNG3.js → analytics-DUPtODxX.js} +0 -0
- /package/client/dist/assets/{analytics-BIdr0YfL.js → analytics-YIpQvPAc.js} +0 -0
- /package/client/dist/assets/{apex-Cw8_REBo.js → apex-BLUBIldB.js} +0 -0
- /package/client/dist/assets/{attachments-DYHGA2Dj.js → attachments-CCWasu-P.js} +0 -0
- /package/client/dist/assets/{attachments-Dd92KpUH.js → attachments-CHaDUfjB.js} +0 -0
- /package/client/dist/assets/{attachments-DzdU6DV6.js → attachments-CVSAbGNl.js} +0 -0
- /package/client/dist/assets/{attachments-Bcf6BG6V.js → attachments-Chg5poG1.js} +0 -0
- /package/client/dist/assets/{attachments-BW4L3l2L.js → attachments-DazTVJbH.js} +0 -0
- /package/client/dist/assets/{attachments-COcrGRFz.js → attachments-Dn-JImAK.js} +0 -0
- /package/client/dist/assets/{attachments-Bke8sCU4.js → attachments-LDA9kp2X.js} +0 -0
- /package/client/dist/assets/{azcli-Cz6HAoOw.js → azcli-DuWxh9mO.js} +0 -0
- /package/client/dist/assets/{bat-CcJ-xyqL.js → bat-UKoTejQm.js} +0 -0
- /package/client/dist/assets/{bicep-z1WDCKYz.js → bicep-4sTT4B3D.js} +0 -0
- /package/client/dist/assets/{browser-DGITz3fC.js → browser-BDd1dbFa.js} +0 -0
- /package/client/dist/assets/{browser-JsAIGCEW.js → browser-BWSgbfdX.js} +0 -0
- /package/client/dist/assets/{browser-M5-rbPlw.js → browser-D2Y_UAKA.js} +0 -0
- /package/client/dist/assets/{browser-BlYF4OOq.js → browser-DH9SGVfM.js} +0 -0
- /package/client/dist/assets/{browser-Bc-YdlVg.js → browser-DWOVYMlg.js} +0 -0
- /package/client/dist/assets/{browser-CT-ReZGt.js → browser-Dxc_VIRK.js} +0 -0
- /package/client/dist/assets/{browser-5ErDlJoR.js → browser-lTQwcDCI.js} +0 -0
- /package/client/dist/assets/{cameligo-BRewOpfa.js → cameligo-CAAryRYO.js} +0 -0
- /package/client/dist/assets/{chat-DwUm6W9z.js → chat-BO9MvVID.js} +0 -0
- /package/client/dist/assets/{chat-BEGuC03z.js → chat-CPgmgZOj.js} +0 -0
- /package/client/dist/assets/{chat-CboQguCi.js → chat-CUrG1eVg.js} +0 -0
- /package/client/dist/assets/{chat-DRCa9pOt.js → chat-CvOOKB2s.js} +0 -0
- /package/client/dist/assets/{chat-BEW60P_u.js → chat-DIh3hr6y.js} +0 -0
- /package/client/dist/assets/{chat-yoXwguQu.js → chat-UVVZqA57.js} +0 -0
- /package/client/dist/assets/{chat-BQNMD0PL.js → chat-mPn3UlMl.js} +0 -0
- /package/client/dist/assets/{clojure-DBjRWN6g.js → clojure-BlMERO1w.js} +0 -0
- /package/client/dist/assets/{clsx-DnqN-uhr.js → clsx-CnH-HMk3.js} +0 -0
- /package/client/dist/assets/{code-zCwBt3Uu.js → code-BwIz8agY.js} +0 -0
- /package/client/dist/assets/{code-g0qFMzyg.js → code-CD7yNSK0.js} +0 -0
- /package/client/dist/assets/{code-DDU0CRS0.js → code-CDFlxUFC.js} +0 -0
- /package/client/dist/assets/{code-L35Loak_.js → code-Cp3Fdng-.js} +0 -0
- /package/client/dist/assets/{code-D1z-YDt-.js → code-D24e1Crx.js} +0 -0
- /package/client/dist/assets/{code-BtsmPQLV.js → code-DtZBQTi9.js} +0 -0
- /package/client/dist/assets/{code-Coa8f2Sh.js → code-nKa0fkm_.js} +0 -0
- /package/client/dist/assets/{coffee-Cfk_XHGR.js → coffee-Cj8D-Wl1.js} +0 -0
- /package/client/dist/assets/{commands-sqrqsxyE.js → commands-B-MVT-2F.js} +0 -0
- /package/client/dist/assets/{commands-UD1NzmwX.js → commands-B0yFTp7e.js} +0 -0
- /package/client/dist/assets/{commands-DLrvnPNg.js → commands-BR1kDkHQ.js} +0 -0
- /package/client/dist/assets/{commands-CJxCry-o.js → commands-Cb21pDlG.js} +0 -0
- /package/client/dist/assets/{commands-CfgY-_of.js → commands-DWgp-8W1.js} +0 -0
- /package/client/dist/assets/{commands-B772IyDa.js → commands-ddsl1V91.js} +0 -0
- /package/client/dist/assets/{commands-BDDp6xFG.js → commands-t4frzhB0.js} +0 -0
- /package/client/dist/assets/{common-Dmm1GhdD.js → common-5ilvMOcH.js} +0 -0
- /package/client/dist/assets/{common-DltqHaAe.js → common-B4sqsKp7.js} +0 -0
- /package/client/dist/assets/{common-GbpxfPG8.js → common-BKpVwUIf.js} +0 -0
- /package/client/dist/assets/{common-DeDELLZJ.js → common-BzEC3kJU.js} +0 -0
- /package/client/dist/assets/{common-DnjcgkPH.js → common-CALKUpYm.js} +0 -0
- /package/client/dist/assets/{common-Dard9UNH.js → common-CTEbWVZS.js} +0 -0
- /package/client/dist/assets/{common-DCr6VzJ7.js → common-DQiza2Xp.js} +0 -0
- /package/client/dist/assets/{cpp-BVob6BaP.js → cpp-BPfKnaj_.js} +0 -0
- /package/client/dist/assets/{csharp-C4fbRuOu.js → csharp-gX-x5uD6.js} +0 -0
- /package/client/dist/assets/{csp-DthFP_vT.js → csp-DKGVt8SM.js} +0 -0
- /package/client/dist/assets/{css-CGMH0hcW.js → css-CPMdnAVq.js} +0 -0
- /package/client/dist/assets/{cypher-Pnf68BRV.js → cypher-ClMDrj9S.js} +0 -0
- /package/client/dist/assets/{dart-PMMOtxZX.js → dart-C4zbzpVv.js} +0 -0
- /package/client/dist/assets/{dashboard-BZBADHSj.js → dashboard--Y6yzMlf.js} +0 -0
- /package/client/dist/assets/{dashboard-I19DXBxw.js → dashboard--a4-6oYE.js} +0 -0
- /package/client/dist/assets/{dashboard-CB6Le1yN.js → dashboard-BiJ3CDTG.js} +0 -0
- /package/client/dist/assets/{dashboard-B4ixDVk8.js → dashboard-CiXjk63Z.js} +0 -0
- /package/client/dist/assets/{dashboard-C1MfeUHs.js → dashboard-Cx5VjCea.js} +0 -0
- /package/client/dist/assets/{dashboard-C7SK6xu5.js → dashboard-D7jg25XR.js} +0 -0
- /package/client/dist/assets/{dashboard-CoTpMOBM.js → dashboard-DpGYK2s1.js} +0 -0
- /package/client/dist/assets/{dockerfile-di1nsJCc.js → dockerfile-D9xw73D1.js} +0 -0
- /package/client/dist/assets/{ecl-D_WVcB5M.js → ecl-gqO8tIR9.js} +0 -0
- /package/client/dist/assets/{editor.api2-XLGzZfbc.js → editor.api2-BPnIxMjz.js} +0 -0
- /package/client/dist/assets/{elixir-OAdJEMOn.js → elixir-DSAhVF3_.js} +0 -0
- /package/client/dist/assets/{explore-D2EFgt8J.js → explore-BE5UmlbD.js} +0 -0
- /package/client/dist/assets/{explore-BV5Xxlsn.js → explore-BmTaI8dX.js} +0 -0
- /package/client/dist/assets/{explore-A8Ltoblq.js → explore-CCwkqoWq.js} +0 -0
- /package/client/dist/assets/{explore-4mFpnrKU.js → explore-CMdEoPDx.js} +0 -0
- /package/client/dist/assets/{explore-C3FSE42C.js → explore-CtdCL4QU.js} +0 -0
- /package/client/dist/assets/{explore-B9A3iN2W.js → explore-DHjxSkqQ.js} +0 -0
- /package/client/dist/assets/{explore-BrBJvfjP.js → explore-__BeALjE.js} +0 -0
- /package/client/dist/assets/{flow9-D3QEZjgn.js → flow9-DeQCSPOd.js} +0 -0
- /package/client/dist/assets/{format-command-CwGuwzGA.js → format-command-2VNoNnMv.js} +0 -0
- /package/client/dist/assets/{fsharp-BF0k_8N8.js → fsharp-CEfaXL-S.js} +0 -0
- /package/client/dist/assets/{go-BAQO5Jsz.js → go-Xp1OkZCh.js} +0 -0
- /package/client/dist/assets/{graphql-hdFVFkiV.js → graphql-BwRXrUwe.js} +0 -0
- /package/client/dist/assets/{hcl-DWnl1o-X.js → hcl-u06DtVFk.js} +0 -0
- /package/client/dist/assets/{ini-CB-6OVu3.js → ini-AmeIpFND.js} +0 -0
- /package/client/dist/assets/{java-d1CmfiHX.js → java-CyDbRQjX.js} +0 -0
- /package/client/dist/assets/{jobs-DPPT6bV6.js → jobs-8viuHLDV.js} +0 -0
- /package/client/dist/assets/{jobs-3j3_npyo.js → jobs-AW2eB5D-.js} +0 -0
- /package/client/dist/assets/{jobs-2N3RXDAM.js → jobs-BSm89DL5.js} +0 -0
- /package/client/dist/assets/{jobs-BqEbCCxD.js → jobs-BZ3sQHjZ.js} +0 -0
- /package/client/dist/assets/{jobs-cHYInoau.js → jobs-Bd8AdOTb.js} +0 -0
- /package/client/dist/assets/{jobs-DRzjWI9u.js → jobs-CRtsq_u0.js} +0 -0
- /package/client/dist/assets/{jobs-2f6Hdc72.js → jobs-CSRwFQ6K.js} +0 -0
- /package/client/dist/assets/{jobs-vGfzIDQa.js → jobs-CbEl7WMI.js} +0 -0
- /package/client/dist/assets/{julia-Bgv08lKa.js → julia-BqialFRG.js} +0 -0
- /package/client/dist/assets/{kotlin-u98kaVTf.js → kotlin-Dzz8TWAt.js} +0 -0
- /package/client/dist/assets/{less-CjYwpgg5.js → less-DHRJD3TR.js} +0 -0
- /package/client/dist/assets/{lexon-YTjaAFBB.js → lexon-5Y3QgTmT.js} +0 -0
- /package/client/dist/assets/{lua-BzmkWv27.js → lua-sKvhfPn5.js} +0 -0
- /package/client/dist/assets/{m3-CFwk9fw0.js → m3-DWDVwkFG.js} +0 -0
- /package/client/dist/assets/{markdown-CR5iMpSZ.js → markdown-CD_aSBxW.js} +0 -0
- /package/client/dist/assets/{mips-CcEalc17.js → mips-687T03hg.js} +0 -0
- /package/client/dist/assets/{msdax-BQbkawnr.js → msdax-C1St-dIV.js} +0 -0
- /package/client/dist/assets/{mysql-GTlaaW_P.js → mysql-BG7r8oBS.js} +0 -0
- /package/client/dist/assets/{nav-C2YXcbZS.js → nav-B05EYB0b.js} +0 -0
- /package/client/dist/assets/{nav-D2bOGSEg.js → nav-BNGCq-0y.js} +0 -0
- /package/client/dist/assets/{nav-BEL3MTwK.js → nav-BRInPX8a.js} +0 -0
- /package/client/dist/assets/{nav-CtYwmMgu.js → nav-Bf87DRHD.js} +0 -0
- /package/client/dist/assets/{nav-iH1V5j6o.js → nav-BkVzzFpc.js} +0 -0
- /package/client/dist/assets/{nav-0fwkrgHt.js → nav-BzFLtS1W.js} +0 -0
- /package/client/dist/assets/{nav-ClzOE4mA.js → nav-DBDbQOYn.js} +0 -0
- /package/client/dist/assets/{nav-B_G-TJDW.js → nav-X9sVtUWC.js} +0 -0
- /package/client/dist/assets/{objective-c-Byu1T5if.js → objective-c-Ds1-m05L.js} +0 -0
- /package/client/dist/assets/{pascal-BrfzBfRm.js → pascal-BKK9FpIi.js} +0 -0
- /package/client/dist/assets/{pascaligo-BXXKFUeo.js → pascaligo-SRS3nwtO.js} +0 -0
- /package/client/dist/assets/{perl-B3OikKq-.js → perl-B2hTOlrF.js} +0 -0
- /package/client/dist/assets/{pgsql-CTsa0Acc.js → pgsql-DIQJYNpL.js} +0 -0
- /package/client/dist/assets/{php-DiQh3FUW.js → php-BEaVe8X2.js} +0 -0
- /package/client/dist/assets/{pla-92uH8Fzm.js → pla-oPLHpZ-Q.js} +0 -0
- /package/client/dist/assets/{postiats-BbeWkKUr.js → postiats-D_vzrAzD.js} +0 -0
- /package/client/dist/assets/{powerquery-DgDMzpsm.js → powerquery-BKG6w-FH.js} +0 -0
- /package/client/dist/assets/{powershell-BfdUUzaG.js → powershell-B3dLhDt4.js} +0 -0
- /package/client/dist/assets/{protobuf-BojW2ftW.js → protobuf-DC8SGjcl.js} +0 -0
- /package/client/dist/assets/{pug-BxqTg3IU.js → pug-D5E-4fI0.js} +0 -0
- /package/client/dist/assets/{qsharp-BX_A-MW9.js → qsharp-6vJAWv0x.js} +0 -0
- /package/client/dist/assets/{r-D9BMnxvJ.js → r-CDwsEcbM.js} +0 -0
- /package/client/dist/assets/{redis-5cJqEQJJ.js → redis-CuQbbESS.js} +0 -0
- /package/client/dist/assets/{redshift-d8BBqiwb.js → redshift-B9e1k-qI.js} +0 -0
- /package/client/dist/assets/{restructuredtext-C8a6yIcZ.js → restructuredtext-BiJ5IwaU.js} +0 -0
- /package/client/dist/assets/{ruby-egeh-6KX.js → ruby-B0UAHY9b.js} +0 -0
- /package/client/dist/assets/{rust-a3r9IInB.js → rust-Dg_spmFr.js} +0 -0
- /package/client/dist/assets/{sb-y8iRIDei.js → sb-DjU66I8Q.js} +0 -0
- /package/client/dist/assets/{scala-BPDK2AmK.js → scala-qvStIdfG.js} +0 -0
- /package/client/dist/assets/{scheme-BIWUEoOs.js → scheme-FstEk5Rh.js} +0 -0
- /package/client/dist/assets/{scss-CA-PSzwg.js → scss-w0U3rQLK.js} +0 -0
- /package/client/dist/assets/{settings-CTcwN9RE.js → settings-5tzo0Rn3.js} +0 -0
- /package/client/dist/assets/{settings-D_dujJZI.js → settings-BDAW3trC.js} +0 -0
- /package/client/dist/assets/{settings-Bg0A3zoS.js → settings-BEWv3VEu.js} +0 -0
- /package/client/dist/assets/{settings-BgPqg2nv.js → settings-BORg56um.js} +0 -0
- /package/client/dist/assets/{settings-BSze3_9q.js → settings-D3LurcR5.js} +0 -0
- /package/client/dist/assets/{settings-CSJ0ahZ8.js → settings-DcqWIEM6.js} +0 -0
- /package/client/dist/assets/{settings-DYIV89nV.js → settings-Dfz8QbZS.js} +0 -0
- /package/client/dist/assets/{settings-DDcfx_ca.js → settings-yMubjqYw.js} +0 -0
- /package/client/dist/assets/{shell--LiT1Bja.js → shell-DJ78wREd.js} +0 -0
- /package/client/dist/assets/{solidity-DdqZccZg.js → solidity-1aGIVsdX.js} +0 -0
- /package/client/dist/assets/{sophia-S6-YxNG_.js → sophia-40LqcGjB.js} +0 -0
- /package/client/dist/assets/{sparql-BSf5kMp2.js → sparql-Cz5dqG_g.js} +0 -0
- /package/client/dist/assets/{sql-D7KgjR8G.js → sql-64f62Ni4.js} +0 -0
- /package/client/dist/assets/{st-BnoDa-Ml.js → st-gJe2yG8J.js} +0 -0
- /package/client/dist/assets/{swift-DEUHTkUX.js → swift-C6ME22mv.js} +0 -0
- /package/client/dist/assets/{systemverilog-Tqb_KPnW.js → systemverilog-CEWz259w.js} +0 -0
- /package/client/dist/assets/{tcl-BmBFS2qq.js → tcl-CcLVIi3m.js} +0 -0
- /package/client/dist/assets/{terminal-Bje4ziIa.js → terminal-BYtreaaF.js} +0 -0
- /package/client/dist/assets/{terminal-CSONJOex.js → terminal-C0xx0SjA.js} +0 -0
- /package/client/dist/assets/{terminal-DeWzh6ys.js → terminal-CPpK58RC.js} +0 -0
- /package/client/dist/assets/{terminal-C2WYcFHF.js → terminal-CdxkpafL.js} +0 -0
- /package/client/dist/assets/{terminal-DEqzGtcr.js → terminal-Ciia0wh2.js} +0 -0
- /package/client/dist/assets/{terminal-80yDMgMF.js → terminal-DHIkiWcs.js} +0 -0
- /package/client/dist/assets/{terminal-lkZYR4wJ.js → terminal-DY42QANg.js} +0 -0
- /package/client/dist/assets/{terminal-YOlsJCQj.js → terminal-DoxtVdma.js} +0 -0
- /package/client/dist/assets/{tickets-DYvafSaY.js → tickets-0rM0lIXd.js} +0 -0
- /package/client/dist/assets/{tickets-DNOANUXr.js → tickets-1UIGf_oA.js} +0 -0
- /package/client/dist/assets/{tickets-DlpC_iTg.js → tickets-9kdPXInd.js} +0 -0
- /package/client/dist/assets/{tickets-CF2PYelu.js → tickets-C6pwZwt4.js} +0 -0
- /package/client/dist/assets/{tickets-CB7N30gm.js → tickets-DAjtxAVb.js} +0 -0
- /package/client/dist/assets/{tickets-DU1aqsbr.js → tickets-DNmXcAwu.js} +0 -0
- /package/client/dist/assets/{tickets-clefmXLv.js → tickets-n23kDqJT.js} +0 -0
- /package/client/dist/assets/{tickets-DucYgtdl.js → tickets-tGx5AR5b.js} +0 -0
- /package/client/dist/assets/{twig-BQV8igWC.js → twig-DvsO-WjW.js} +0 -0
- /package/client/dist/assets/{typespec-DlFroUGY.js → typespec-Brkt3IAA.js} +0 -0
- /package/client/dist/assets/{vb-BlrJpIMX.js → vb-r121Uzxt.js} +0 -0
- /package/client/dist/assets/{wgsl-BWgIc6FZ.js → wgsl-BRX8uYh4.js} +0 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Jira REST client. Single internal model rendered to the right dialect per
|
|
3
|
+
// deployment: Cloud (REST v3, Basic auth, ADF bodies) vs Data Center/Server
|
|
4
|
+
// (REST v2, Bearer PAT, plain wiki-string bodies). Every call returns a
|
|
5
|
+
// normalised `JiraResult<T>` whose error `code` drives the outbox's
|
|
6
|
+
// retry/dead-letter decisions. No throwing across the boundary.
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.JiraClient = void 0;
|
|
9
|
+
exports.detectDeployment = detectDeployment;
|
|
10
|
+
const jira_adf_1 = require("./jira-adf");
|
|
11
|
+
function classify(status) {
|
|
12
|
+
if (status === 401)
|
|
13
|
+
return 'auth';
|
|
14
|
+
if (status === 403)
|
|
15
|
+
return 'permission';
|
|
16
|
+
if (status === 404)
|
|
17
|
+
return 'not_found';
|
|
18
|
+
if (status === 429)
|
|
19
|
+
return 'rate_limit';
|
|
20
|
+
if (status >= 400 && status < 500)
|
|
21
|
+
return 'validation';
|
|
22
|
+
return 'server';
|
|
23
|
+
}
|
|
24
|
+
class JiraClient {
|
|
25
|
+
cfg;
|
|
26
|
+
fetchImpl;
|
|
27
|
+
constructor(cfg) {
|
|
28
|
+
this.cfg = cfg;
|
|
29
|
+
// Node 18+ exposes a global fetch (undici); injectable for tests.
|
|
30
|
+
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch;
|
|
31
|
+
}
|
|
32
|
+
get deployment() {
|
|
33
|
+
return this.cfg.deployment;
|
|
34
|
+
}
|
|
35
|
+
authHeader() {
|
|
36
|
+
if (this.cfg.authScheme === 'bearer')
|
|
37
|
+
return `Bearer ${this.cfg.token}`;
|
|
38
|
+
const raw = `${this.cfg.accountEmail ?? ''}:${this.cfg.token}`;
|
|
39
|
+
return `Basic ${Buffer.from(raw, 'utf-8').toString('base64')}`;
|
|
40
|
+
}
|
|
41
|
+
url(path) {
|
|
42
|
+
const base = this.cfg.baseUrl.replace(/\/+$/, '');
|
|
43
|
+
return `${base}/rest/api/${this.cfg.apiVersion}${path}`;
|
|
44
|
+
}
|
|
45
|
+
/** Build a URL for a NON `/rest/api` endpoint (e.g. `/rest/dev-status/1.0/...`). */
|
|
46
|
+
urlRaw(restPath) {
|
|
47
|
+
return `${this.cfg.baseUrl.replace(/\/+$/, '')}${restPath}`;
|
|
48
|
+
}
|
|
49
|
+
/** REST v2/v3 request under `/rest/api/{version}`. */
|
|
50
|
+
request(method, path, body) {
|
|
51
|
+
return this.requestUrl(method, this.url(path), body);
|
|
52
|
+
}
|
|
53
|
+
/** Request to an absolute REST path (for APIs outside `/rest/api`). */
|
|
54
|
+
requestRaw(method, restPath, body) {
|
|
55
|
+
return this.requestUrl(method, this.urlRaw(restPath), body);
|
|
56
|
+
}
|
|
57
|
+
async requestUrl(method, fullUrl, body) {
|
|
58
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
59
|
+
const timeout = controller
|
|
60
|
+
? setTimeout(() => controller.abort(), this.cfg.timeoutMs ?? 20000)
|
|
61
|
+
: null;
|
|
62
|
+
try {
|
|
63
|
+
const res = await this.fetchImpl(fullUrl, {
|
|
64
|
+
method,
|
|
65
|
+
headers: {
|
|
66
|
+
Authorization: this.authHeader(),
|
|
67
|
+
Accept: 'application/json',
|
|
68
|
+
...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
|
|
69
|
+
},
|
|
70
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
71
|
+
...(controller ? { signal: controller.signal } : {}),
|
|
72
|
+
});
|
|
73
|
+
if (res.ok) {
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
const data = text ? JSON.parse(text) : undefined;
|
|
76
|
+
return { ok: true, data, status: res.status };
|
|
77
|
+
}
|
|
78
|
+
const errText = await res.text().catch(() => '');
|
|
79
|
+
const code = classify(res.status);
|
|
80
|
+
const retryAfter = res.headers.get('Retry-After');
|
|
81
|
+
const retryAfterMs = retryAfter ? parseRetryAfter(retryAfter) : undefined;
|
|
82
|
+
return { ok: false, status: res.status, code, error: truncate(errText), ...(retryAfterMs ? { retryAfterMs } : {}) };
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
86
|
+
return { ok: false, status: 0, code: 'network', error: msg };
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
if (timeout)
|
|
90
|
+
clearTimeout(timeout);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ─── Connectivity / metadata ───────────────────────────────────────────────
|
|
94
|
+
/** GET /myself — validates the credential and identifies the account. */
|
|
95
|
+
myself() {
|
|
96
|
+
return this.request('GET', '/myself');
|
|
97
|
+
}
|
|
98
|
+
/** GET /project/{key} — validates the project and returns name/id for confirmation. */
|
|
99
|
+
getProject(keyOrId) {
|
|
100
|
+
return this.request('GET', `/project/${encodeURIComponent(keyOrId)}`);
|
|
101
|
+
}
|
|
102
|
+
/** GET /mypermissions — probe write capability so config-time warns the user. */
|
|
103
|
+
myPermissions(permissions, projectKey) {
|
|
104
|
+
const qp = new URLSearchParams({ permissions: permissions.join(',') });
|
|
105
|
+
if (projectKey)
|
|
106
|
+
qp.set('projectKey', projectKey);
|
|
107
|
+
return this.request('GET', `/mypermissions?${qp.toString()}`);
|
|
108
|
+
}
|
|
109
|
+
/** GET /project/{key}/statuses — the project's real status list per issue type. */
|
|
110
|
+
getProjectStatuses(keyOrId) {
|
|
111
|
+
return this.request('GET', `/project/${encodeURIComponent(keyOrId)}/statuses`);
|
|
112
|
+
}
|
|
113
|
+
/** GET /field — all fields; used to discover the sprint custom field id. */
|
|
114
|
+
getFields() {
|
|
115
|
+
return this.request('GET', '/field');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* List projects the credential can see (for the setup wizard's project picker).
|
|
119
|
+
* Cloud: paginated GET /project/search. DC/Server: GET /project (full list).
|
|
120
|
+
*/
|
|
121
|
+
async searchProjects(query) {
|
|
122
|
+
if (this.cfg.apiVersion === '2') {
|
|
123
|
+
const res = await this.request('GET', '/project');
|
|
124
|
+
if (!res.ok)
|
|
125
|
+
return res;
|
|
126
|
+
const filtered = query
|
|
127
|
+
? res.data.filter((p) => `${p.key} ${p.name}`.toLowerCase().includes(query.toLowerCase()))
|
|
128
|
+
: res.data;
|
|
129
|
+
return { ok: true, data: filtered.slice(0, 50), status: res.status };
|
|
130
|
+
}
|
|
131
|
+
const qp = new URLSearchParams({ maxResults: '50' });
|
|
132
|
+
if (query)
|
|
133
|
+
qp.set('query', query);
|
|
134
|
+
const res = await this.request('GET', `/project/search?${qp.toString()}`);
|
|
135
|
+
if (!res.ok)
|
|
136
|
+
return res;
|
|
137
|
+
return { ok: true, data: res.data.values ?? [], status: res.status };
|
|
138
|
+
}
|
|
139
|
+
// ─── Search (inbound poll) ─────────────────────────────────────────────────
|
|
140
|
+
/**
|
|
141
|
+
* POST /search/jql — the current paginated search (legacy GET /search was
|
|
142
|
+
* removed Oct 2025). Always pass an explicit `fields` array; page via
|
|
143
|
+
* `nextPageToken`. On DC v2 this falls back to the classic /search.
|
|
144
|
+
*/
|
|
145
|
+
searchJql(args) {
|
|
146
|
+
if (this.cfg.apiVersion === '2') {
|
|
147
|
+
// DC/Server: classic search with startAt/maxResults.
|
|
148
|
+
return this.request('POST', '/search', {
|
|
149
|
+
jql: args.jql,
|
|
150
|
+
fields: args.fields,
|
|
151
|
+
maxResults: args.maxResults ?? 100,
|
|
152
|
+
startAt: args.nextPageToken ? parseInt(args.nextPageToken, 10) || 0 : 0,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return this.request('POST', '/search/jql', {
|
|
156
|
+
jql: args.jql,
|
|
157
|
+
fields: args.fields,
|
|
158
|
+
maxResults: args.maxResults ?? 100,
|
|
159
|
+
...(args.nextPageToken ? { nextPageToken: args.nextPageToken } : {}),
|
|
160
|
+
...(args.reconcileIssues ? { reconcileIssues: args.reconcileIssues } : {}),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/** GET /issue/{idOrKey} — re-resolve by immutable id (key may have changed). */
|
|
164
|
+
getIssue(idOrKey, fields) {
|
|
165
|
+
const qp = fields ? `?fields=${encodeURIComponent(fields.join(','))}` : '';
|
|
166
|
+
return this.request('GET', `/issue/${encodeURIComponent(idOrKey)}${qp}`);
|
|
167
|
+
}
|
|
168
|
+
// ─── Lifecycle (outbound) ──────────────────────────────────────────────────
|
|
169
|
+
/** GET /issue/{id}/transitions?expand=transitions.fields — discover edges + screens. */
|
|
170
|
+
getTransitions(issueIdOrKey) {
|
|
171
|
+
return this.request('GET', `/issue/${encodeURIComponent(issueIdOrKey)}/transitions?expand=transitions.fields`);
|
|
172
|
+
}
|
|
173
|
+
/** POST /issue/{id}/transitions — apply a transition, optionally with fields. */
|
|
174
|
+
transitionIssue(issueIdOrKey, transitionId, fields) {
|
|
175
|
+
return this.request('POST', `/issue/${encodeURIComponent(issueIdOrKey)}/transitions`, {
|
|
176
|
+
transition: { id: transitionId },
|
|
177
|
+
...(fields && Object.keys(fields).length > 0 ? { fields } : {}),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/** POST /issue — create an issue. Description rendered per deployment. */
|
|
181
|
+
createIssue(args) {
|
|
182
|
+
const fields = {
|
|
183
|
+
project: { key: args.projectKey },
|
|
184
|
+
issuetype: { name: args.issueType },
|
|
185
|
+
summary: args.summary.slice(0, 250),
|
|
186
|
+
};
|
|
187
|
+
if (args.description)
|
|
188
|
+
fields.description = (0, jira_adf_1.bodyForDeployment)(args.description, this.cfg.deployment);
|
|
189
|
+
if (args.labels && args.labels.length > 0)
|
|
190
|
+
fields.labels = args.labels;
|
|
191
|
+
if (args.priority)
|
|
192
|
+
fields.priority = { name: args.priority };
|
|
193
|
+
return this.request('POST', '/issue', { fields });
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* PUT /issue/{id} — update editable fields (summary/description/labels/
|
|
197
|
+
* priority) when a Jira-backed spec is edited locally. The `fields` object is
|
|
198
|
+
* already rendered for the deployment by the caller. 204 on success.
|
|
199
|
+
*/
|
|
200
|
+
updateIssue(idOrKey, fields) {
|
|
201
|
+
return this.request('PUT', `/issue/${encodeURIComponent(idOrKey)}`, { fields });
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* POST /issue/{id}/comment — add a comment (ADF on Cloud, wiki on DC). The
|
|
205
|
+
* optional idempotency `marker` is stored as an INVISIBLE comment property
|
|
206
|
+
* (never in the body), so users never see it. Cloud + DC both accept the
|
|
207
|
+
* `properties` array on comment creation.
|
|
208
|
+
*/
|
|
209
|
+
addComment(issueIdOrKey, text, marker) {
|
|
210
|
+
const payload = { body: (0, jira_adf_1.bodyForDeployment)(text, this.cfg.deployment) };
|
|
211
|
+
if (marker)
|
|
212
|
+
payload.properties = [{ key: jira_adf_1.SPECRAILS_COMMENT_PROP_KEY, value: { marker } }];
|
|
213
|
+
return this.request('POST', `/issue/${encodeURIComponent(issueIdOrKey)}/comment`, payload);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* GET /issue/{id}/comment?expand=properties — used to dedup comments via the
|
|
217
|
+
* self-marker (invisible comment property, with a legacy body fallback).
|
|
218
|
+
*/
|
|
219
|
+
getComments(issueIdOrKey) {
|
|
220
|
+
return this.request('GET', `/issue/${encodeURIComponent(issueIdOrKey)}/comment?expand=properties`);
|
|
221
|
+
}
|
|
222
|
+
// ─── Read-only details panel (issue fields + Development) ────────────────────
|
|
223
|
+
/** GET /issue/{id}?fields=*all — the full system + custom field map (untyped). */
|
|
224
|
+
getIssueRaw(idOrKey) {
|
|
225
|
+
return this.request('GET', `/issue/${encodeURIComponent(idOrKey)}?fields=*all`);
|
|
226
|
+
}
|
|
227
|
+
/** GET /field — full field metadata (name + schema) for the generic renderer. */
|
|
228
|
+
getFieldsFull() {
|
|
229
|
+
return this.request('GET', '/field');
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* GET /rest/dev-status/1.0/issue/summary?issueId=<numericId> — dev-panel counts
|
|
233
|
+
* + the connected applicationType(s). `issueId` MUST be the immutable numeric
|
|
234
|
+
* id (JiraLink.jiraIssueId), not the PROJ-123 key. No data => 200 zero counts.
|
|
235
|
+
*/
|
|
236
|
+
getDevStatusSummary(issueId) {
|
|
237
|
+
return this.requestRaw('GET', `/rest/dev-status/1.0/issue/summary?issueId=${encodeURIComponent(issueId)}`);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* GET /rest/dev-status/1.0/issue/detail — the actual PR/branch/repository
|
|
241
|
+
* records for one (applicationType, dataType). A wrong applicationType returns
|
|
242
|
+
* 200 with empty detail[]; derive it from getDevStatusSummary byInstanceType.
|
|
243
|
+
*/
|
|
244
|
+
getDevStatusDetail(issueId, applicationType, dataType) {
|
|
245
|
+
const qp = new URLSearchParams({ issueId, applicationType, dataType });
|
|
246
|
+
return this.requestRaw('GET', `/rest/dev-status/1.0/issue/detail?${qp.toString()}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
exports.JiraClient = JiraClient;
|
|
250
|
+
function parseRetryAfter(value) {
|
|
251
|
+
const seconds = Number(value);
|
|
252
|
+
if (!Number.isNaN(seconds))
|
|
253
|
+
return Math.max(0, seconds * 1000);
|
|
254
|
+
const date = Date.parse(value);
|
|
255
|
+
if (!Number.isNaN(date))
|
|
256
|
+
return Math.max(0, date - Date.now());
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
function truncate(s, max = 500) {
|
|
260
|
+
return s.length > max ? `${s.slice(0, max)}…` : s;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Detect Cloud vs Data Center from the base URL host. `*.atlassian.net` ⇒ Cloud
|
|
264
|
+
* (v3, Basic, ADF); otherwise DC/Server (v2, Bearer, wiki). A `probe` caller can
|
|
265
|
+
* still override after hitting /myself, but the host heuristic is the default.
|
|
266
|
+
*/
|
|
267
|
+
function detectDeployment(baseUrl) {
|
|
268
|
+
let host = '';
|
|
269
|
+
try {
|
|
270
|
+
host = new URL(baseUrl).host.toLowerCase();
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
host = baseUrl.toLowerCase();
|
|
274
|
+
}
|
|
275
|
+
const isCloud = host.endsWith('.atlassian.net') || host.endsWith('.jira.com');
|
|
276
|
+
return isCloud
|
|
277
|
+
? { deployment: 'cloud', apiVersion: '3', authScheme: 'basic' }
|
|
278
|
+
: { deployment: 'dc', apiVersion: '2', authScheme: 'bearer' };
|
|
279
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Encrypted-at-rest credential store for Jira tokens.
|
|
3
|
+
//
|
|
4
|
+
// A Jira API token / PAT is a bearer credential with the user's full Jira
|
|
5
|
+
// permissions, so it must not sit in plaintext SQLite (the webhook-HMAC bar).
|
|
6
|
+
// v1: AES-256-GCM (node:crypto, no native plugin) under a per-install 0600
|
|
7
|
+
// keyfile. v2 can swap the backend to a Tauri keychain/stronghold by replacing
|
|
8
|
+
// `SecretStore` — every callsite goes through this single interface.
|
|
9
|
+
//
|
|
10
|
+
// The ciphertext lives in the per-project `jira_connection.encrypted_token`
|
|
11
|
+
// column; the symmetric key lives once at `~/.specrails/jira-secret.key`.
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.KeyfileSecretStore = void 0;
|
|
17
|
+
exports.defaultKeyfilePath = defaultKeyfilePath;
|
|
18
|
+
exports.getOrCreateKey = getOrCreateKey;
|
|
19
|
+
exports.getSecretStore = getSecretStore;
|
|
20
|
+
exports.setSecretStore = setSecretStore;
|
|
21
|
+
const fs_1 = __importDefault(require("fs"));
|
|
22
|
+
const os_1 = __importDefault(require("os"));
|
|
23
|
+
const path_1 = __importDefault(require("path"));
|
|
24
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
25
|
+
const ALGO = 'aes-256-gcm';
|
|
26
|
+
const VERSION = 'v1';
|
|
27
|
+
/** Resolve the keyfile path (override-able for tests). */
|
|
28
|
+
function defaultKeyfilePath(homeDir = os_1.default.homedir()) {
|
|
29
|
+
return path_1.default.join(homeDir, '.specrails', 'jira-secret.key');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Load the 32-byte symmetric key, creating it (0600) on first use. The key is
|
|
33
|
+
* stored base64 in a single keyfile so the v2 keychain swap is one place.
|
|
34
|
+
*/
|
|
35
|
+
function getOrCreateKey(keyfilePath = defaultKeyfilePath()) {
|
|
36
|
+
try {
|
|
37
|
+
const raw = fs_1.default.readFileSync(keyfilePath, 'utf-8').trim();
|
|
38
|
+
const key = Buffer.from(raw, 'base64');
|
|
39
|
+
if (key.length === 32)
|
|
40
|
+
return key;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Missing or corrupt — (re)create below.
|
|
44
|
+
}
|
|
45
|
+
const key = crypto_1.default.randomBytes(32);
|
|
46
|
+
const dir = path_1.default.dirname(keyfilePath);
|
|
47
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
48
|
+
try {
|
|
49
|
+
fs_1.default.chmodSync(dir, 0o700);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
/* best-effort (no-op on Windows) */
|
|
53
|
+
}
|
|
54
|
+
// Write 0600 atomically: write to a temp file then rename.
|
|
55
|
+
const tmp = `${keyfilePath}.tmp`;
|
|
56
|
+
fs_1.default.writeFileSync(tmp, key.toString('base64'), { mode: 0o600 });
|
|
57
|
+
fs_1.default.renameSync(tmp, keyfilePath);
|
|
58
|
+
try {
|
|
59
|
+
fs_1.default.chmodSync(keyfilePath, 0o600);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
/* best-effort */
|
|
63
|
+
}
|
|
64
|
+
return key;
|
|
65
|
+
}
|
|
66
|
+
/** AES-256-GCM secret store backed by the keyfile. */
|
|
67
|
+
class KeyfileSecretStore {
|
|
68
|
+
_key;
|
|
69
|
+
constructor(keyfilePath = defaultKeyfilePath()) {
|
|
70
|
+
this._key = getOrCreateKey(keyfilePath);
|
|
71
|
+
}
|
|
72
|
+
encrypt(plaintext) {
|
|
73
|
+
const iv = crypto_1.default.randomBytes(12);
|
|
74
|
+
const cipher = crypto_1.default.createCipheriv(ALGO, this._key, iv);
|
|
75
|
+
const ct = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);
|
|
76
|
+
const tag = cipher.getAuthTag();
|
|
77
|
+
return [VERSION, iv.toString('base64'), tag.toString('base64'), ct.toString('base64')].join(':');
|
|
78
|
+
}
|
|
79
|
+
decrypt(blob) {
|
|
80
|
+
const parts = blob.split(':');
|
|
81
|
+
if (parts.length !== 4 || parts[0] !== VERSION) {
|
|
82
|
+
throw new Error('jira-credential-store: malformed ciphertext');
|
|
83
|
+
}
|
|
84
|
+
const iv = Buffer.from(parts[1], 'base64');
|
|
85
|
+
const tag = Buffer.from(parts[2], 'base64');
|
|
86
|
+
const ct = Buffer.from(parts[3], 'base64');
|
|
87
|
+
const decipher = crypto_1.default.createDecipheriv(ALGO, this._key, iv);
|
|
88
|
+
decipher.setAuthTag(tag);
|
|
89
|
+
return Buffer.concat([decipher.update(ct), decipher.final()]).toString('utf-8');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.KeyfileSecretStore = KeyfileSecretStore;
|
|
93
|
+
/** Process-wide singleton (the keyfile is shared across all projects). */
|
|
94
|
+
let _store = null;
|
|
95
|
+
function getSecretStore() {
|
|
96
|
+
if (!_store)
|
|
97
|
+
_store = new KeyfileSecretStore();
|
|
98
|
+
return _store;
|
|
99
|
+
}
|
|
100
|
+
/** Test seam: inject a store (e.g. an in-memory one). */
|
|
101
|
+
function setSecretStore(store) {
|
|
102
|
+
_store = store;
|
|
103
|
+
}
|