@maudecode/kanvil 0.2.1 → 0.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/apps/server/.env.example +19 -0
- package/apps/server/dist/auth-Cuo7ECLh.mjs +7770 -0
- package/apps/server/dist/client.mjs +884 -0
- package/apps/server/dist/{config-CbNqtJEj.mjs → config-DtNfVSnB.mjs} +28 -133
- package/apps/server/dist/index.mjs +2503 -295
- package/apps/server/dist/instance-CCeXRJ6m.mjs +133 -0
- package/apps/server/dist/migrate.mjs +1 -1
- package/apps/server/dist/recover.mjs +5 -4
- package/apps/server/dist/src-tQ82UI8k.mjs +4818 -0
- package/apps/server/drizzle/0014_inbox_dismissal.sql +1 -0
- package/apps/server/drizzle/0015_notification_categories.sql +14 -0
- package/apps/server/drizzle/0016_ticket_resources.sql +19 -0
- package/apps/server/drizzle/0017_project_backgrounds.sql +3 -0
- package/apps/server/drizzle/0018_delivery_outbox.sql +65 -0
- package/apps/server/drizzle/0019_retire_push_deliveries.sql +1 -0
- package/apps/server/drizzle/0020_calendar_feeds.sql +16 -0
- package/apps/server/drizzle/0021_staged_uploads.sql +14 -0
- package/apps/server/drizzle/0022_manual_order.sql +6 -0
- package/apps/server/drizzle/0023_workspace_invitations.sql +22 -0
- package/apps/server/drizzle/0024_workflow_states.sql +39 -0
- package/apps/server/drizzle/0025_workspace_labels.sql +10 -0
- package/apps/server/drizzle/0026_public_read.sql +1 -0
- package/apps/server/drizzle/0027_custom_fields.sql +16 -0
- package/apps/server/drizzle/0028_project_lifecycle.sql +11 -0
- package/apps/server/drizzle/0029_ticket_relocation.sql +16 -0
- package/apps/server/drizzle/0030_repository_connections.sql +39 -0
- package/apps/server/drizzle/0031_repository_providers.sql +3 -0
- package/apps/server/drizzle/0032_workspace_ownership.sql +11 -0
- package/apps/server/drizzle/0033_import_runs.sql +38 -0
- package/apps/server/drizzle/0034_issue_sync.sql +38 -0
- package/apps/server/drizzle/0035_account_deletion.sql +9 -0
- package/apps/server/drizzle/0036_workspace_roles.sql +16 -0
- package/apps/server/drizzle/0037_email_code_owner.sql +14 -0
- package/apps/server/drizzle/0038_time_entries.sql +19 -0
- package/apps/server/drizzle/meta/0014_snapshot.json +4246 -0
- package/apps/server/drizzle/meta/0015_snapshot.json +4297 -0
- package/apps/server/drizzle/meta/0016_snapshot.json +4443 -0
- package/apps/server/drizzle/meta/0017_snapshot.json +4468 -0
- package/apps/server/drizzle/meta/0018_snapshot.json +4948 -0
- package/apps/server/drizzle/meta/0019_snapshot.json +4826 -0
- package/apps/server/drizzle/meta/0020_snapshot.json +4947 -0
- package/apps/server/drizzle/meta/0021_snapshot.json +5059 -0
- package/apps/server/drizzle/meta/0022_snapshot.json +5094 -0
- package/apps/server/drizzle/meta/0023_snapshot.json +5267 -0
- package/apps/server/drizzle/meta/0024_snapshot.json +5405 -0
- package/apps/server/drizzle/meta/0025_snapshot.json +5474 -0
- package/apps/server/drizzle/meta/0026_snapshot.json +5481 -0
- package/apps/server/drizzle/meta/0027_snapshot.json +5605 -0
- package/apps/server/drizzle/meta/0028_snapshot.json +5699 -0
- package/apps/server/drizzle/meta/0029_snapshot.json +5809 -0
- package/apps/server/drizzle/meta/0030_snapshot.json +6066 -0
- package/apps/server/drizzle/meta/0031_snapshot.json +6074 -0
- package/apps/server/drizzle/meta/0032_snapshot.json +6100 -0
- package/apps/server/drizzle/meta/0033_snapshot.json +6406 -0
- package/apps/server/drizzle/meta/0034_snapshot.json +6698 -0
- package/apps/server/drizzle/meta/0035_snapshot.json +6704 -0
- package/apps/server/drizzle/meta/0036_snapshot.json +6825 -0
- package/apps/server/drizzle/meta/0037_snapshot.json +6825 -0
- package/apps/server/drizzle/meta/0038_snapshot.json +6998 -0
- package/apps/server/drizzle/meta/_journal.json +175 -0
- package/apps/web/dist/assets/CompositeItem-DgnfVvrF.js +1 -0
- package/apps/web/dist/assets/Trans-f2VYVS9z.js +1 -0
- package/apps/web/dist/assets/abnfDiagram-WEYOIA3C-DTOx8N4B.js +1 -0
- package/apps/web/dist/assets/admin-settings-DBZL4siY.js +1 -0
- package/apps/web/dist/assets/arc-Y1ARJVZ4.js +1 -0
- package/apps/web/dist/assets/architecture-WOLXFQ4H-DlC3p5z3.js +1 -0
- package/apps/web/dist/assets/architectureDiagram-ZHVYKT53-DooN3Z58.js +36 -0
- package/apps/web/dist/assets/archive-restore-CGuLxoHC.js +1 -0
- package/apps/web/dist/assets/array-BifhSqXX.js +1 -0
- package/apps/web/dist/assets/az-AZ-DesqXNg5.js +1 -0
- package/apps/web/dist/assets/az-BE5iqNIE.js +1 -0
- package/apps/web/dist/assets/az-D-kj4lmf.js +1 -0
- package/apps/web/dist/assets/blockDiagram-RJAE7QA3-CD5AgY4U.js +140 -0
- package/apps/web/dist/assets/c4Diagram-XDPPPE54-CTDOcLuN.js +38 -0
- package/apps/web/dist/assets/channel-BhHvU4I-.js +1 -0
- package/apps/web/dist/assets/chunk-2E7WHVMD-D9qnBqTV.js +88 -0
- package/apps/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/apps/web/dist/assets/chunk-4EMNKR2T-Kz5JiJ85.js +1 -0
- package/apps/web/dist/assets/chunk-55XCU76K-DnKiFpYM.js +1 -0
- package/apps/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/apps/web/dist/assets/chunk-7S6XSTFO-CpdNd6Ke.js +2 -0
- package/apps/web/dist/assets/chunk-AQDTSKZB-CpyuSWt8.js +72 -0
- package/apps/web/dist/assets/chunk-DSNLSHJZ-DTC3y9rb.js +129 -0
- package/apps/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
- package/apps/web/dist/assets/chunk-HAGFOTED-Bv8PrMYK.js +62 -0
- package/apps/web/dist/assets/chunk-HNE4Q36P-CDDJ_yRa.js +1 -0
- package/apps/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
- package/apps/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/apps/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
- package/apps/web/dist/assets/chunk-NQOKRVIF-lNtnsWHS.js +213 -0
- package/apps/web/dist/assets/chunk-UHW7PFBP-D79ptlTN.js +1 -0
- package/apps/web/dist/assets/chunk-VQ5W62QI-B8hWFCiM.js +1 -0
- package/apps/web/dist/assets/chunk-WQQL4CDK-DAGuWzS3.js +10 -0
- package/apps/web/dist/assets/chunk-XXDRQBXY-CnbRkih_.js +1 -0
- package/apps/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/apps/web/dist/assets/chunk-YZO67HFG-C0ptzlKO.js +1 -0
- package/apps/web/dist/assets/chunk-ZAUX2LTX-ah8U5xoJ.js +1 -0
- package/apps/web/dist/assets/chunk-ZCHMQSOR-DYqATOIZ.js +2 -0
- package/apps/web/dist/assets/classDiagram-v2-4MYWR3UA-DYytA-ua.js +217 -0
- package/apps/web/dist/assets/core-jXc03Sty.js +1 -0
- package/apps/web/dist/assets/corner-left-up-BCro--Gl.js +1 -0
- package/apps/web/dist/assets/cose-bilkent-JH36ORCC-lWVj4msc.js +1 -0
- package/apps/web/dist/assets/cynefin-EF2NZ3EQ-Xy6e6m1E.js +1 -0
- package/apps/web/dist/assets/cynefinDiagram-WF24UDRP-BYarZJSm.js +62 -0
- package/apps/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
- package/apps/web/dist/assets/dagre-NK4GIZVX-WLvvUY1o.js +4 -0
- package/apps/web/dist/assets/de-DAv77-wP.js +1 -0
- package/apps/web/dist/assets/de-DE-BIGY9SNm.js +1 -0
- package/apps/web/dist/assets/de-DLGjUGf_.js +1 -0
- package/apps/web/dist/assets/default-BgvtI7HK.js +56 -0
- package/apps/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/apps/web/dist/assets/delivery-settings-CZOtb4X8.js +1 -0
- package/apps/web/dist/assets/diagram-CBK3MWTC-D6PtxkLg.js +24 -0
- package/apps/web/dist/assets/diagram-I5XIIV2D-DTOKQwIY.js +24 -0
- package/apps/web/dist/assets/diagram-ODIL2UCW-BmERt0Xu.js +30 -0
- package/apps/web/dist/assets/diagram-PFBEJUXE-WDUe08eD.js +3 -0
- package/apps/web/dist/assets/diagram-RJA3I4VV-B2K-NLGG.js +41 -0
- package/apps/web/dist/assets/diagram-TYUNFSNR-BLf7PpV7.js +200 -0
- package/apps/web/dist/assets/dist-CumnGVmJ.js +1 -0
- package/apps/web/dist/assets/ebnfDiagram-V4P3TTPT-DwBUQs9p.js +1 -0
- package/apps/web/dist/assets/el-CG6Xy42v.js +1 -0
- package/apps/web/dist/assets/el-D2ypddWn.js +1 -0
- package/apps/web/dist/assets/el-GR-D2TjImt0.js +1 -0
- package/apps/web/dist/assets/elk-QONTBCTQ-AuT8PinL.js +27 -0
- package/apps/web/dist/assets/ellipsis-ZJM26JNS.js +1 -0
- package/apps/web/dist/assets/en-EnSRisMz.js +1 -0
- package/apps/web/dist/assets/en-US-DKYSujv3.js +1 -0
- package/apps/web/dist/assets/erDiagram-KYQIGQAA-h--u4Eo6.js +99 -0
- package/apps/web/dist/assets/es-B_49BMhR.js +1 -0
- package/apps/web/dist/assets/es-Bbj5WuMM.js +1 -0
- package/apps/web/dist/assets/es-ES-C_fRqLGU.js +1 -0
- package/apps/web/dist/assets/eventmodeling-K75KTNOO-CW4hDt1j.js +1 -0
- package/apps/web/dist/assets/flowDiagram-IUGLLWBU-BGUscnNP.js +1 -0
- package/apps/web/dist/assets/forms-C3pNy-qY.js +1 -0
- package/apps/web/dist/assets/fr-B-WmPGZD.js +1 -0
- package/apps/web/dist/assets/fr-CjuIKc1o.js +1 -0
- package/apps/web/dist/assets/fr-FR-_tnQsn4j.js +1 -0
- package/apps/web/dist/assets/ganttDiagram-R7GPNTJY-CB3lsQvj.js +292 -0
- package/apps/web/dist/assets/gitGraph-VSP46ZUC-Hu-kvdCR.js +1 -0
- package/apps/web/dist/assets/gitGraphDiagram-PDYL7XHY-DCuY3C1Q.js +106 -0
- package/apps/web/dist/assets/graphlib-DS17s2tU.js +1 -0
- package/apps/web/dist/assets/hi-BVVrZ-zZ.js +1 -0
- package/apps/web/dist/assets/hi-DvoDcUpL.js +1 -0
- package/apps/web/dist/assets/hi-IN-CcmFsZYy.js +1 -0
- package/apps/web/dist/assets/highlight-CKyEM4jx.js +5 -0
- package/apps/web/dist/assets/id-BhNWOQnp.js +1 -0
- package/apps/web/dist/assets/id-CPASBZ2r.js +1 -0
- package/apps/web/dist/assets/id-ID-C59tC61D.js +1 -0
- package/apps/web/dist/assets/index-BIuqxnJn.js +17 -0
- package/apps/web/dist/assets/index-DyQNFS69.css +2 -0
- package/apps/web/dist/assets/info-OHQRW6UA-Cc8VwTsk.js +1 -0
- package/apps/web/dist/assets/infoDiagram-MVDRKAX5-KIMOx55J.js +2 -0
- package/apps/web/dist/assets/init-C-OQMol4.js +1 -0
- package/apps/web/dist/assets/invitations-D5unaga2.js +1 -0
- package/apps/web/dist/assets/isSameWeek-2ftYGvBT.js +1 -0
- package/apps/web/dist/assets/ishikawaDiagram-HPEHV2GE-CAou726L.js +70 -0
- package/apps/web/dist/assets/it-Cav3_-xd.js +1 -0
- package/apps/web/dist/assets/it-Cd7u97Jd.js +1 -0
- package/apps/web/dist/assets/it-IT-BAP5O3gK.js +1 -0
- package/apps/web/dist/assets/item-Cj8xpMLk.js +1 -0
- package/apps/web/dist/assets/ja-DTmZE0Qe.js +1 -0
- package/apps/web/dist/assets/ja-JP-vQa7mEdh.js +1 -0
- package/apps/web/dist/assets/ja-LkOrjegp.js +1 -0
- package/apps/web/dist/assets/journeyDiagram-BOSHW7O7-YbJuPYDH.js +139 -0
- package/apps/web/dist/assets/kanban-definition-FNSA4HC5-nuRnm9y8.js +89 -0
- package/apps/web/dist/assets/katex-B_JcIwqj.js +257 -0
- package/apps/web/dist/assets/ko-BuYCMOUj.js +1 -0
- package/apps/web/dist/assets/ko-DPpXw683.js +1 -0
- package/apps/web/dist/assets/ko-KR-CXlpmX0-.js +1 -0
- package/apps/web/dist/assets/label-settings-B89Ehf78.js +1 -0
- package/apps/web/dist/assets/line-WsxZYwZr.js +1 -0
- package/apps/web/dist/assets/linear-C9iwaMOi.js +1 -0
- package/apps/web/dist/assets/lucide-DIlszs-T.js +1 -0
- package/apps/web/dist/assets/markdown-blocks-DSEA68s5.js +2 -0
- package/apps/web/dist/assets/member-directory-48yD01yN.js +1 -0
- package/apps/web/dist/assets/mermaid-parser.core-B5c-1CnP.js +7 -0
- package/apps/web/dist/assets/mermaid.core-vGVkgzA3.js +44 -0
- package/apps/web/dist/assets/mindmap-definition-6OY57UG3-uooJyUak.js +98 -0
- package/apps/web/dist/assets/mk-BZ2Rg2sU.js +1 -0
- package/apps/web/dist/assets/mk-CkaQRpqe.js +1 -0
- package/apps/web/dist/assets/mk-MK-BU5BLpXM.js +1 -0
- package/apps/web/dist/assets/nl-BtnPzRih.js +1 -0
- package/apps/web/dist/assets/nl-DiEjqOA8.js +1 -0
- package/apps/web/dist/assets/nl-NL-2aSpdZkg.js +1 -0
- package/apps/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
- package/apps/web/dist/assets/packet-JDAUHWVQ-WJpqlH1d.js +1 -0
- package/apps/web/dist/assets/path-fybaL0A-.js +1 -0
- package/apps/web/dist/assets/pegDiagram-ECIUJNBX-CUvajD93.js +1 -0
- package/apps/web/dist/assets/pie-XZMESJXO-DvandPby.js +1 -0
- package/apps/web/dist/assets/pieDiagram-GNMPY74T-CqxeyIaP.js +39 -0
- package/apps/web/dist/assets/pl-Beg8hEdK.js +1 -0
- package/apps/web/dist/assets/pl-CauoMfkf.js +1 -0
- package/apps/web/dist/assets/pl-PL-C5Wvnv7f.js +1 -0
- package/apps/web/dist/assets/preload-helper-BLdHbfdN.js +1 -0
- package/apps/web/dist/assets/project-lifecycle-CIAMJ-SX.js +1 -0
- package/apps/web/dist/assets/project-settings-C7lolDSl.js +1 -0
- package/apps/web/dist/assets/pt-BR-B4VZ35N_.js +1 -0
- package/apps/web/dist/assets/pt-BR-BpOhwoDW.js +1 -0
- package/apps/web/dist/assets/pt-BR-CVvI-ZB7.js +1 -0
- package/apps/web/dist/assets/public-project-DvvfaUd2.js +1 -0
- package/apps/web/dist/assets/quadrantDiagram-D57K4MC3-DFjNmaZc.js +7 -0
- package/apps/web/dist/assets/radar-ABXABTNO-CJhZF9j2.js +1 -0
- package/apps/web/dist/assets/railroad-I3PHUGI6-DZC10oBD.js +1 -0
- package/apps/web/dist/assets/railroad-abnf-LNEFI6M7-BUJF2n6u.js +1 -0
- package/apps/web/dist/assets/railroad-ebnf-DWYD2UWJ-CG7oB02K.js +1 -0
- package/apps/web/dist/assets/railroad-peg-JR7BVNR7-DBCZuZJY.js +1 -0
- package/apps/web/dist/assets/railroadDiagram-Y72NRBL7-CvN3poBq.js +1 -0
- package/apps/web/dist/assets/requirementDiagram-EQYSW5RA-BEItNirc.js +84 -0
- package/apps/web/dist/assets/rolldown-runtime-COiEfhsA.js +1 -0
- package/apps/web/dist/assets/rotate-ccw-GjVJPDML.js +1 -0
- package/apps/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/apps/web/dist/assets/ru-DOaRp00B.js +1 -0
- package/apps/web/dist/assets/ru-DjVJVHzv.js +1 -0
- package/apps/web/dist/assets/ru-RU-C7UUdGIh.js +1 -0
- package/apps/web/dist/assets/sankeyDiagram-SY24JHO5-DluLIjax.js +40 -0
- package/apps/web/dist/assets/search-ZaQmVnj1.js +85 -0
- package/apps/web/dist/assets/send-Dr9bXHhf.js +1 -0
- package/apps/web/dist/assets/sequenceDiagram-BLEHNHQU-ZcwnsNxK.js +169 -0
- package/apps/web/dist/assets/settings-DXvrVvyS.js +1 -0
- package/apps/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/apps/web/dist/assets/sliders-horizontal-C1t_zA7D.js +1 -0
- package/apps/web/dist/assets/src-BWF7jMDv.js +1 -0
- package/apps/web/dist/assets/stateDiagram-v2-A6IESKWZ-DD6vH3rM.js +291 -0
- package/apps/web/dist/assets/swimlanes-B3ENRKFQ-pX_qyO4X.js +1 -0
- package/apps/web/dist/assets/swimlanesDiagram-AYQRV4AK-CeVsLUsg.js +8 -0
- package/apps/web/dist/assets/switch-D-WTDajm.js +1 -0
- package/apps/web/dist/assets/table-BaRMFP84.js +1 -0
- package/apps/web/dist/assets/ticket-detail-CFJI4qoK.js +2 -0
- package/apps/web/dist/assets/ticket-editor-DL3nHG_q.js +2 -0
- package/apps/web/dist/assets/ticket-list-CDkweYGS.js +5 -0
- package/apps/web/dist/assets/ticket-list-controls-CmTgFQQ-.js +1 -0
- package/apps/web/dist/assets/timeline-definition-JXYKGLGB-DLBjAxKq.js +120 -0
- package/apps/web/dist/assets/toDate-B3HYxwtT.js +1 -0
- package/apps/web/dist/assets/tr-Ckc4TA71.js +1 -0
- package/apps/web/dist/assets/tr-DeYojjLx.js +1 -0
- package/apps/web/dist/assets/tr-TR-VVsL3uMp.js +1 -0
- package/apps/web/dist/assets/treeView-D4JQ5SDB-DsJ44q_q.js +1 -0
- package/apps/web/dist/assets/treemap-SAJKECNS-BmXoBpVL.js +1 -0
- package/apps/web/dist/assets/uk-B4ZvJ8xG.js +1 -0
- package/apps/web/dist/assets/uk-DACrfgCP.js +1 -0
- package/apps/web/dist/assets/uk-UA-DRpCbOps.js +1 -0
- package/apps/web/dist/assets/upload-BwGa8shS.js +1 -0
- package/apps/web/dist/assets/useQueries-sQEHjB0a.js +1 -0
- package/apps/web/dist/assets/usecaseDiagram-WPOLBNNX-eU2tr2si.js +328 -0
- package/apps/web/dist/assets/vennDiagram-Q3Y3IDCW-CoVTWGNg.js +34 -0
- package/apps/web/dist/assets/vi-CkqUo4w_.js +1 -0
- package/apps/web/dist/assets/vi-Dq2krfY8.js +1 -0
- package/apps/web/dist/assets/vi-VN-C0YFqq9j.js +1 -0
- package/apps/web/dist/assets/visual-editor-CBhwqTDu.js +208 -0
- package/apps/web/dist/assets/wardley-7MLQ67FV-C6mVVk98.js +1 -0
- package/apps/web/dist/assets/wardleyDiagram-IVAIDKWA-m3CeJc7a.js +78 -0
- package/apps/web/dist/assets/workspace-settings-DgLyieJN.js +1 -0
- package/apps/web/dist/assets/xychartDiagram-4URNHDU4-Dw6fLaip.js +7 -0
- package/apps/web/dist/assets/zh-CN-B7Rxc3Mp.js +1 -0
- package/apps/web/dist/assets/zh-CN-CC7ghLLr.js +1 -0
- package/apps/web/dist/assets/zh-CN-pcgTdR8c.js +1 -0
- package/apps/web/dist/assets/zh-TW-BlIRMi1C.js +1 -0
- package/apps/web/dist/assets/zh-TW-DymSXkFg.js +1 -0
- package/apps/web/dist/assets/zh-TW-awiwHjeM.js +1 -0
- package/apps/web/dist/index.html +14 -8
- package/bin/kanvil.mjs +3 -1
- package/compose.yml +12 -0
- package/docs/api.md +311 -10
- package/docs/cli.md +74 -0
- package/docs/infrastructure.md +2 -2
- package/docs/localization.md +25 -0
- package/docs/plan.md +34 -11
- package/docs/self-hosting.md +44 -5
- package/docs/themes.md +1 -1
- package/docs/verification.md +1 -1
- package/docs/workspaces.md +18 -2
- package/package.json +12 -8
- package/apps/server/dist/auth-I1XEr0d4.mjs +0 -2931
- package/apps/web/dist/assets/CompositeItem-BWPJ5Mol.js +0 -1
- package/apps/web/dist/assets/admin-settings-DZqkC6ju.js +0 -1
- package/apps/web/dist/assets/date-picker-6H_iwP6t.js +0 -1
- package/apps/web/dist/assets/ellipsis-BT172Uvu.js +0 -1
- package/apps/web/dist/assets/forms-B4Vg3CPz.js +0 -92
- package/apps/web/dist/assets/image-edit-trigger-DGmVtWLC.js +0 -1
- package/apps/web/dist/assets/index-C_a21taR.js +0 -50
- package/apps/web/dist/assets/index-DM-D_3Sv.css +0 -2
- package/apps/web/dist/assets/kbd-tTQGZxaK.js +0 -1
- package/apps/web/dist/assets/link-DoIP9KJ6.js +0 -2
- package/apps/web/dist/assets/list-order-Bzsrihyr.js +0 -1
- package/apps/web/dist/assets/lucide-U995NW8E.js +0 -1
- package/apps/web/dist/assets/member-directory-BiCE8DRq.js +0 -1
- package/apps/web/dist/assets/popover-BhzZ0U1d.js +0 -1
- package/apps/web/dist/assets/project-label-provider-9L7Uts3_.js +0 -1
- package/apps/web/dist/assets/project-settings-Q7Q9Reec.js +0 -1
- package/apps/web/dist/assets/rotate-ccw-sjyLwLLy.js +0 -1
- package/apps/web/dist/assets/settings-B6qD6q1J.js +0 -1
- package/apps/web/dist/assets/settings-layout-B-AwUIMu.js +0 -1
- package/apps/web/dist/assets/switch-D0nFHj6l.js +0 -1
- package/apps/web/dist/assets/table-CYZiwo9g.js +0 -1
- package/apps/web/dist/assets/ticket-detail-B-3vbHSB.js +0 -2
- package/apps/web/dist/assets/ticket-editor-C3d8TZIT.js +0 -1
- package/apps/web/dist/assets/ticket-list-LtGGOnwN.js +0 -5
- package/apps/web/dist/assets/ticket-tags-2rdmkcJV.js +0 -1
- package/apps/web/dist/assets/upload-DXPRzAaa.js +0 -1
- package/apps/web/dist/assets/useNavigate-DFohfUD3.js +0 -1
- package/apps/web/dist/assets/workspace-settings-D3tCm1vH.js +0 -1
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
import { B as notificationIdsInput, G as okSchema, H as notificationPreferencesSchema, U as notificationReadInput, V as notificationPreferencesInput, W as notificationsSchema, X as parsePublicOutput, Y as parseOutput, _t as snapshotSchema, a as checkpointSchema, q as operations, rt as publicOperations, t as ApiError, w as eventSchema, x as errorSchema, xt as streamErrorSchema } from "./src-tQ82UI8k.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { constants } from "node:fs";
|
|
5
|
+
import { mkdir, open, rename, rm } from "node:fs/promises";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
//#region ../../node_modules/.pnpm/eventsource-parser@4.1.2/node_modules/eventsource-parser/dist/errors.js
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when encountering an issue during parsing.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
var ParseError = class extends Error {
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "ParseError";
|
|
18
|
+
this.type = options.type;
|
|
19
|
+
this.field = options.field;
|
|
20
|
+
this.value = options.value;
|
|
21
|
+
this.line = options.line;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region ../../node_modules/.pnpm/eventsource-parser@4.1.2/node_modules/eventsource-parser/dist/parse.js
|
|
26
|
+
/**
|
|
27
|
+
* EventSource/Server-Sent Events parser
|
|
28
|
+
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html
|
|
29
|
+
*/
|
|
30
|
+
const LF = 10;
|
|
31
|
+
const CR = 13;
|
|
32
|
+
const SPACE = 32;
|
|
33
|
+
const MAX_FIELD_PREFIX_LENGTH = 6;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new EventSource parser.
|
|
36
|
+
*
|
|
37
|
+
* @param config - Parser configuration. Accepts callbacks (see {@link ParserCallbacks})
|
|
38
|
+
* and options like `maxBufferSize` (see {@link ParserConfig}).
|
|
39
|
+
*
|
|
40
|
+
* @returns A new EventSource parser, with `feed` and `reset` methods.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
function createParser(config) {
|
|
44
|
+
if (typeof config === "function") throw new TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");
|
|
45
|
+
const { maxBufferSize, onComment, onError, onEvent, onId, onRetry } = config;
|
|
46
|
+
const pendingFragments = [];
|
|
47
|
+
let pendingFragmentsLength = 0;
|
|
48
|
+
let bomPrefix = "";
|
|
49
|
+
let id;
|
|
50
|
+
let data = "";
|
|
51
|
+
let dataLines = 0;
|
|
52
|
+
let eventType;
|
|
53
|
+
let terminated = false;
|
|
54
|
+
let skippingLine = false;
|
|
55
|
+
let skipNextLineFeed = false;
|
|
56
|
+
/**
|
|
57
|
+
* Feeds a chunk of the SSE stream to the parser. Any trailing bytes that do
|
|
58
|
+
* not yet form a complete line are held back and prepended to the next chunk,
|
|
59
|
+
* so callers can pass arbitrary slices of the stream without worrying about
|
|
60
|
+
* line boundaries.
|
|
61
|
+
*
|
|
62
|
+
* Per the SSE spec, one leading UTF-8 BOM is stripped before parsing,
|
|
63
|
+
* even when split across chunks. This handles both the raw 3-byte form (0xEF 0xBB
|
|
64
|
+
* 0xBF) and a single decoded U+FEFF, so a leading BOM is ignored regardless of
|
|
65
|
+
* how the caller decoded the bytes.
|
|
66
|
+
*
|
|
67
|
+
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream
|
|
68
|
+
*/
|
|
69
|
+
function feed(chunk) {
|
|
70
|
+
if (terminated) throw new Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");
|
|
71
|
+
if (bomPrefix !== void 0) {
|
|
72
|
+
chunk = bomPrefix + chunk;
|
|
73
|
+
if (chunk === "" || chunk === "ï" || chunk === "ï»") {
|
|
74
|
+
bomPrefix = chunk;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
bomPrefix = void 0;
|
|
78
|
+
chunk = chunk.replace(/^(?:\uFEFF|\xEF\xBB\xBF)/, "");
|
|
79
|
+
}
|
|
80
|
+
if (skippingLine || skipNextLineFeed) {
|
|
81
|
+
chunk = resumeAfterSkip(chunk);
|
|
82
|
+
if (!chunk) return;
|
|
83
|
+
}
|
|
84
|
+
if (!pendingFragments.length) {
|
|
85
|
+
const trailing = processLines(chunk);
|
|
86
|
+
if (trailing !== "") storeTrailing(trailing);
|
|
87
|
+
checkForBufferOverflow();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (chunk.indexOf("\n") === -1 && chunk.indexOf("\r") === -1) {
|
|
91
|
+
if (pendingFragmentsLength < MAX_FIELD_PREFIX_LENGTH) {
|
|
92
|
+
if (!shouldBufferTrailing(pendingFragments.join("") + chunk.slice(0, MAX_FIELD_PREFIX_LENGTH - pendingFragmentsLength))) {
|
|
93
|
+
pendingFragments.length = 0;
|
|
94
|
+
pendingFragmentsLength = 0;
|
|
95
|
+
skippingLine = true;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
pendingFragments.push(chunk);
|
|
100
|
+
pendingFragmentsLength += chunk.length;
|
|
101
|
+
checkForBufferOverflow();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
pendingFragments.push(chunk);
|
|
105
|
+
const input = pendingFragments.join("");
|
|
106
|
+
pendingFragments.length = 0;
|
|
107
|
+
pendingFragmentsLength = 0;
|
|
108
|
+
storeTrailing(processLines(input));
|
|
109
|
+
checkForBufferOverflow();
|
|
110
|
+
}
|
|
111
|
+
function resumeAfterSkip(chunk) {
|
|
112
|
+
if (chunk.length === 0) return chunk;
|
|
113
|
+
if (skipNextLineFeed) {
|
|
114
|
+
skipNextLineFeed = false;
|
|
115
|
+
return chunk.charCodeAt(0) === LF ? chunk.slice(1) : chunk;
|
|
116
|
+
}
|
|
117
|
+
const crIndex = chunk.indexOf("\r");
|
|
118
|
+
const lfIndex = chunk.indexOf("\n");
|
|
119
|
+
const lineEnd = crIndex === -1 ? lfIndex : lfIndex === -1 ? crIndex : crIndex < lfIndex ? crIndex : lfIndex;
|
|
120
|
+
if (lineEnd === -1) return "";
|
|
121
|
+
if (lineEnd === chunk.length - 1 && chunk.charCodeAt(lineEnd) === CR) {
|
|
122
|
+
skippingLine = false;
|
|
123
|
+
skipNextLineFeed = true;
|
|
124
|
+
return "";
|
|
125
|
+
}
|
|
126
|
+
skippingLine = false;
|
|
127
|
+
return chunk.slice(lineEnd + (chunk.charCodeAt(lineEnd) === CR && chunk.charCodeAt(lineEnd + 1) === LF ? 2 : 1));
|
|
128
|
+
}
|
|
129
|
+
function storeTrailing(trailing) {
|
|
130
|
+
if (!trailing) return;
|
|
131
|
+
if (trailing.charCodeAt(trailing.length - 1) === CR) {
|
|
132
|
+
parseLine(trailing, 0, trailing.length - 1);
|
|
133
|
+
if (checkForBufferOverflow()) return;
|
|
134
|
+
skipNextLineFeed = true;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (shouldBufferTrailing(trailing)) {
|
|
138
|
+
pendingFragments.push(trailing);
|
|
139
|
+
pendingFragmentsLength = trailing.length;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
skippingLine = true;
|
|
143
|
+
}
|
|
144
|
+
function shouldBufferTrailing(trailing) {
|
|
145
|
+
const firstCharCode = trailing.charCodeAt(0);
|
|
146
|
+
return firstCharCode === 58 && !!onComment || firstCharCode === 100 && isPotentialField(trailing, "data") || firstCharCode === 101 && isPotentialField(trailing, "event") || firstCharCode === 105 && isPotentialField(trailing, "id") || firstCharCode === 114 && isPotentialField(trailing, "retry");
|
|
147
|
+
}
|
|
148
|
+
function checkForBufferOverflow() {
|
|
149
|
+
if (terminated) return true;
|
|
150
|
+
if (maxBufferSize === void 0) return false;
|
|
151
|
+
if (pendingFragmentsLength + data.length <= maxBufferSize) return false;
|
|
152
|
+
terminated = true;
|
|
153
|
+
pendingFragments.length = 0;
|
|
154
|
+
pendingFragmentsLength = 0;
|
|
155
|
+
id = void 0;
|
|
156
|
+
data = "";
|
|
157
|
+
dataLines = 0;
|
|
158
|
+
eventType = void 0;
|
|
159
|
+
skippingLine = false;
|
|
160
|
+
skipNextLineFeed = false;
|
|
161
|
+
onError === null || onError === void 0 || onError(new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, { type: "max-buffer-size-exceeded" }));
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Splits `chunk` into SSE lines and dispatches each to the appropriate handler.
|
|
166
|
+
* Returns any trailing bytes that did not terminate with a line break, so the
|
|
167
|
+
* caller can prepend them to the next chunk.
|
|
168
|
+
*
|
|
169
|
+
* The SSE spec permits three line terminators: `\n`, `\r`, and `\r\n`. Real-world
|
|
170
|
+
* streams almost always use plain `\n`, so we take a fast path when no `\r` is
|
|
171
|
+
* present in the chunk. The slow path is spec-correct but does more work per line.
|
|
172
|
+
*/
|
|
173
|
+
function processLines(chunk) {
|
|
174
|
+
let searchIndex = 0;
|
|
175
|
+
if (chunk.indexOf("\r") === -1) {
|
|
176
|
+
let lfIndex = chunk.indexOf("\n", searchIndex);
|
|
177
|
+
while (lfIndex !== -1) {
|
|
178
|
+
if (searchIndex === lfIndex) {
|
|
179
|
+
if (id !== void 0) onId === null || onId === void 0 || onId(id);
|
|
180
|
+
if (dataLines > 0) onEvent === null || onEvent === void 0 || onEvent({
|
|
181
|
+
id,
|
|
182
|
+
event: eventType,
|
|
183
|
+
data
|
|
184
|
+
});
|
|
185
|
+
id = void 0;
|
|
186
|
+
data = "";
|
|
187
|
+
dataLines = 0;
|
|
188
|
+
eventType = void 0;
|
|
189
|
+
searchIndex = lfIndex + 1;
|
|
190
|
+
lfIndex = chunk.indexOf("\n", searchIndex);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
194
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
195
|
+
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5;
|
|
196
|
+
const value = chunk.slice(valueStart, lfIndex);
|
|
197
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
198
|
+
if (id !== void 0) onId === null || onId === void 0 || onId(id);
|
|
199
|
+
onEvent === null || onEvent === void 0 || onEvent({
|
|
200
|
+
id,
|
|
201
|
+
event: eventType,
|
|
202
|
+
data: value
|
|
203
|
+
});
|
|
204
|
+
id = void 0;
|
|
205
|
+
data = "";
|
|
206
|
+
eventType = void 0;
|
|
207
|
+
searchIndex = lfIndex + 2;
|
|
208
|
+
lfIndex = chunk.indexOf("\n", searchIndex);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
data = dataLines === 0 ? value : `${data}\n${value}`;
|
|
212
|
+
dataLines++;
|
|
213
|
+
} else if (isEventPrefix(chunk, searchIndex, firstCharCode)) eventType = chunk.slice(chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6, lfIndex) || void 0;
|
|
214
|
+
else parseLine(chunk, searchIndex, lfIndex);
|
|
215
|
+
if (checkForBufferOverflow()) return "";
|
|
216
|
+
searchIndex = lfIndex + 1;
|
|
217
|
+
lfIndex = chunk.indexOf("\n", searchIndex);
|
|
218
|
+
}
|
|
219
|
+
return chunk.slice(searchIndex);
|
|
220
|
+
}
|
|
221
|
+
while (searchIndex < chunk.length) {
|
|
222
|
+
const crIndex = chunk.indexOf("\r", searchIndex);
|
|
223
|
+
const lfIndex = chunk.indexOf("\n", searchIndex);
|
|
224
|
+
let lineEnd = -1;
|
|
225
|
+
if (crIndex !== -1 && lfIndex !== -1) lineEnd = crIndex < lfIndex ? crIndex : lfIndex;
|
|
226
|
+
else if (crIndex !== -1) {
|
|
227
|
+
if (crIndex === chunk.length - 1) lineEnd = -1;
|
|
228
|
+
else lineEnd = crIndex;
|
|
229
|
+
} else if (lfIndex !== -1) lineEnd = lfIndex;
|
|
230
|
+
if (lineEnd === -1) break;
|
|
231
|
+
parseLine(chunk, searchIndex, lineEnd);
|
|
232
|
+
if (checkForBufferOverflow()) return "";
|
|
233
|
+
searchIndex = lineEnd + 1;
|
|
234
|
+
if (chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF) searchIndex++;
|
|
235
|
+
}
|
|
236
|
+
return chunk.slice(searchIndex);
|
|
237
|
+
}
|
|
238
|
+
function parseLine(chunk, start, end) {
|
|
239
|
+
if (start === end) {
|
|
240
|
+
dispatchEvent();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const firstCharCode = chunk.charCodeAt(start);
|
|
244
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
245
|
+
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5;
|
|
246
|
+
const value = chunk.slice(valueStart, end);
|
|
247
|
+
data = dataLines === 0 ? value : `${data}\n${value}`;
|
|
248
|
+
dataLines++;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
252
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
256
|
+
const value = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
257
|
+
if (!value.includes("\0")) id = value;
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (firstCharCode === 58) {
|
|
261
|
+
if (onComment) {
|
|
262
|
+
const line = chunk.slice(start, end);
|
|
263
|
+
onComment(line.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
264
|
+
}
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const line = chunk.slice(start, end);
|
|
268
|
+
const fieldSeparatorIndex = line.indexOf(":");
|
|
269
|
+
if (fieldSeparatorIndex === -1) {
|
|
270
|
+
processField(line, "", line);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const field = line.slice(0, fieldSeparatorIndex);
|
|
274
|
+
const offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1;
|
|
275
|
+
processField(field, line.slice(fieldSeparatorIndex + offset), line);
|
|
276
|
+
}
|
|
277
|
+
function processField(field, value, line) {
|
|
278
|
+
switch (field) {
|
|
279
|
+
case "event":
|
|
280
|
+
eventType = value || void 0;
|
|
281
|
+
break;
|
|
282
|
+
case "data":
|
|
283
|
+
data = dataLines === 0 ? value : `${data}\n${value}`;
|
|
284
|
+
dataLines++;
|
|
285
|
+
break;
|
|
286
|
+
case "id":
|
|
287
|
+
if (!value.includes("\0")) id = value;
|
|
288
|
+
break;
|
|
289
|
+
case "retry":
|
|
290
|
+
if (/^\d+$/.test(value)) onRetry === null || onRetry === void 0 || onRetry(parseInt(value, 10));
|
|
291
|
+
else onError === null || onError === void 0 || onError(new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
292
|
+
type: "invalid-retry",
|
|
293
|
+
value,
|
|
294
|
+
line
|
|
295
|
+
}));
|
|
296
|
+
break;
|
|
297
|
+
default: onError === null || onError === void 0 || onError(new ParseError(`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}…` : field}"`, {
|
|
298
|
+
type: "unknown-field",
|
|
299
|
+
field,
|
|
300
|
+
value,
|
|
301
|
+
line
|
|
302
|
+
}));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function dispatchEvent() {
|
|
306
|
+
if (id !== void 0) onId === null || onId === void 0 || onId(id);
|
|
307
|
+
if (dataLines > 0) onEvent === null || onEvent === void 0 || onEvent({
|
|
308
|
+
id,
|
|
309
|
+
event: eventType,
|
|
310
|
+
data
|
|
311
|
+
});
|
|
312
|
+
id = void 0;
|
|
313
|
+
data = "";
|
|
314
|
+
dataLines = 0;
|
|
315
|
+
eventType = void 0;
|
|
316
|
+
}
|
|
317
|
+
function reset(options = {}) {
|
|
318
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
319
|
+
const incompleteLine = pendingFragments.join("");
|
|
320
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
321
|
+
}
|
|
322
|
+
bomPrefix = "";
|
|
323
|
+
id = void 0;
|
|
324
|
+
data = "";
|
|
325
|
+
dataLines = 0;
|
|
326
|
+
eventType = void 0;
|
|
327
|
+
pendingFragments.length = 0;
|
|
328
|
+
pendingFragmentsLength = 0;
|
|
329
|
+
terminated = false;
|
|
330
|
+
skippingLine = false;
|
|
331
|
+
skipNextLineFeed = false;
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
feed,
|
|
335
|
+
reset
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Checks if `chunk` starts with the literal `data:` at index `i`.
|
|
340
|
+
*
|
|
341
|
+
* Equivalent to `chunk.startsWith('data:', i)`, but benchmarks show this
|
|
342
|
+
* hand-unrolled char-code comparison is ~20% faster on common event types.
|
|
343
|
+
* The caller passes `firstCharCode` (the code at `i`) so it can be reused
|
|
344
|
+
* across prefix checks.
|
|
345
|
+
*
|
|
346
|
+
* ASCII: 'd' = 100, 'a' = 97, 't' = 116, 'a' = 97, ':' = 58
|
|
347
|
+
*/
|
|
348
|
+
function isDataPrefix(chunk, i, firstCharCode) {
|
|
349
|
+
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Checks if `chunk` starts with the literal `event:` at index `i`.
|
|
353
|
+
*
|
|
354
|
+
* See {@link isDataPrefix} for why this is hand-unrolled rather than using
|
|
355
|
+
* `String.prototype.startsWith`.
|
|
356
|
+
*
|
|
357
|
+
* ASCII: 'e' = 101, 'v' = 118, 'e' = 101, 'n' = 110, 't' = 116, ':' = 58
|
|
358
|
+
*/
|
|
359
|
+
function isEventPrefix(chunk, i, firstCharCode) {
|
|
360
|
+
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
361
|
+
}
|
|
362
|
+
function isPotentialField(line, field) {
|
|
363
|
+
let i = 1;
|
|
364
|
+
while (i < line.length && i < field.length) {
|
|
365
|
+
if (line.charCodeAt(i) !== field.charCodeAt(i)) return false;
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
return line.length <= field.length || line.charCodeAt(field.length) === 58;
|
|
369
|
+
}
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region ../../packages/client/src/index.ts
|
|
372
|
+
function randomRequestId() {
|
|
373
|
+
if (typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
374
|
+
const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
375
|
+
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
376
|
+
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
377
|
+
const hex = Array.from(bytes, (value) => value.toString(16).padStart(2, "0")).join("");
|
|
378
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
379
|
+
}
|
|
380
|
+
async function decode(response) {
|
|
381
|
+
const data = await response.json().catch(() => {
|
|
382
|
+
throw new ApiError(response.status, "invalid_response", "Kanvil returned an invalid response");
|
|
383
|
+
});
|
|
384
|
+
if (!response.ok) {
|
|
385
|
+
const error = errorSchema.safeParse(data);
|
|
386
|
+
throw new ApiError(response.status, error.success ? error.data.error.code : "request_failed", error.success ? error.data.error.message : `Request failed (${response.status})`, error.success ? error.data.error.details : void 0);
|
|
387
|
+
}
|
|
388
|
+
return data;
|
|
389
|
+
}
|
|
390
|
+
function createClient(options) {
|
|
391
|
+
const request = options.fetch ?? fetch;
|
|
392
|
+
const endpoint = (path) => {
|
|
393
|
+
if (!path.startsWith("/") || path.startsWith("//")) throw new ApiError(400, "invalid_path", "Use a relative Kanvil endpoint");
|
|
394
|
+
const url = new URL(`${options.baseUrl.replace(/\/$/, "")}${path}`);
|
|
395
|
+
if (url.origin !== new URL(options.baseUrl).origin) throw new ApiError(400, "invalid_path", "Credentials cannot be sent to another origin");
|
|
396
|
+
return url;
|
|
397
|
+
};
|
|
398
|
+
const retry = async (url, init) => {
|
|
399
|
+
try {
|
|
400
|
+
return await request(url, init);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
if (init.signal?.aborted) throw error;
|
|
403
|
+
return request(url, init);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
const send = async (spec, input, base) => {
|
|
407
|
+
const values = { ...spec.input.parse(input) };
|
|
408
|
+
const path = spec.path.replace(/\{(\w+)\}/g, (_, key) => {
|
|
409
|
+
const value = values[key];
|
|
410
|
+
delete values[key];
|
|
411
|
+
if (typeof value !== "string") throw new ApiError(400, "invalid_path", `Missing path parameter ${key}`);
|
|
412
|
+
return encodeURIComponent(value);
|
|
413
|
+
});
|
|
414
|
+
const url = new URL(`${options.baseUrl.replace(/\/$/, "")}${base}${path}`);
|
|
415
|
+
const headers = new Headers(await options.headers?.());
|
|
416
|
+
const init = {
|
|
417
|
+
method: spec.method,
|
|
418
|
+
credentials: options.credentials ?? "include",
|
|
419
|
+
headers
|
|
420
|
+
};
|
|
421
|
+
if (spec.method === "GET") {
|
|
422
|
+
for (const [key, value] of Object.entries(values)) for (const item of Array.isArray(value) ? value : [value]) if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") url.searchParams.append(key, String(item));
|
|
423
|
+
} else {
|
|
424
|
+
headers.set("Content-Type", "application/json");
|
|
425
|
+
if ("requestId" in spec.input.shape) values.requestId ??= (options.requestId ?? randomRequestId)();
|
|
426
|
+
init.body = JSON.stringify(values);
|
|
427
|
+
}
|
|
428
|
+
return decode(await (spec.method === "GET" || "requestId" in values ? retry(url, init) : request(url, init)));
|
|
429
|
+
};
|
|
430
|
+
const api = {
|
|
431
|
+
async request(path, schema, init = {}) {
|
|
432
|
+
const headers = new Headers(await options.headers?.());
|
|
433
|
+
new Headers(init.headers).forEach((value, key) => headers.set(key, value));
|
|
434
|
+
return schema.parse(await decode(await request(endpoint(path), {
|
|
435
|
+
...init,
|
|
436
|
+
headers,
|
|
437
|
+
credentials: options.credentials ?? "include"
|
|
438
|
+
})));
|
|
439
|
+
},
|
|
440
|
+
async call(name, input) {
|
|
441
|
+
return parseOutput(name, await send(operations[name], input, "/api/v1"));
|
|
442
|
+
},
|
|
443
|
+
async callPublic(name, input) {
|
|
444
|
+
return parsePublicOutput(name, await send(publicOperations[name], input, "/api/public"));
|
|
445
|
+
},
|
|
446
|
+
async subscribe(subscription) {
|
|
447
|
+
let cursor = subscription.cursor, backoff = 1e3;
|
|
448
|
+
try {
|
|
449
|
+
while (!subscription.signal.aborted) {
|
|
450
|
+
subscription.onState?.("connecting");
|
|
451
|
+
const url = endpoint("/api/v1/events");
|
|
452
|
+
if (cursor) url.searchParams.set("cursor", cursor);
|
|
453
|
+
if (subscription.projectId) url.searchParams.set("projectId", subscription.projectId);
|
|
454
|
+
let reader;
|
|
455
|
+
const cancel = () => {
|
|
456
|
+
reader?.cancel().catch(() => {});
|
|
457
|
+
};
|
|
458
|
+
subscription.signal.addEventListener("abort", cancel, { once: true });
|
|
459
|
+
try {
|
|
460
|
+
const response = await request(url, {
|
|
461
|
+
headers: new Headers(await options.headers?.()),
|
|
462
|
+
credentials: options.credentials ?? "include",
|
|
463
|
+
signal: subscription.signal
|
|
464
|
+
});
|
|
465
|
+
if (response.status === 410 && subscription.onReset) {
|
|
466
|
+
cursor = await subscription.onReset();
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (!response.ok) await decode(response);
|
|
470
|
+
if (!response.body) throw new ApiError(502, "invalid_stream", "The event stream has no body");
|
|
471
|
+
reader = response.body.getReader();
|
|
472
|
+
const messages = [];
|
|
473
|
+
const parser = createParser({
|
|
474
|
+
maxBufferSize: 1e6,
|
|
475
|
+
onEvent: (event) => messages.push(event),
|
|
476
|
+
onError: (error) => {
|
|
477
|
+
throw new ApiError(502, "invalid_stream", error.message);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
const decoder = new TextDecoder();
|
|
481
|
+
while (!subscription.signal.aborted) {
|
|
482
|
+
const chunk = await reader.read();
|
|
483
|
+
if (chunk.done) break;
|
|
484
|
+
parser.feed(decoder.decode(chunk.value, { stream: true }));
|
|
485
|
+
for (const message of messages.splice(0)) {
|
|
486
|
+
if (message.event === "error") {
|
|
487
|
+
const error = streamErrorSchema.parse(JSON.parse(message.data));
|
|
488
|
+
throw new ApiError(error.status, error.code, error.message);
|
|
489
|
+
}
|
|
490
|
+
if (message.event === "change") await subscription.onEvent(eventSchema.parse(JSON.parse(message.data)));
|
|
491
|
+
if (message.event === "checkpoint" || message.event === "change") {
|
|
492
|
+
subscription.onState?.("connected");
|
|
493
|
+
backoff = 1e3;
|
|
494
|
+
if (message.id) {
|
|
495
|
+
await subscription.onCursor?.(message.id);
|
|
496
|
+
cursor = message.id;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (subscription.signal.aborted) return;
|
|
503
|
+
if (error instanceof ApiError && error.status === 410 && subscription.onReset) {
|
|
504
|
+
cursor = await subscription.onReset();
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
if (error instanceof ApiError && error.status < 500) throw error;
|
|
508
|
+
} finally {
|
|
509
|
+
subscription.signal.removeEventListener("abort", cancel);
|
|
510
|
+
await reader?.cancel().catch(() => {});
|
|
511
|
+
}
|
|
512
|
+
if (subscription.signal.aborted) return;
|
|
513
|
+
subscription.onState?.("offline");
|
|
514
|
+
await new Promise((resolve) => {
|
|
515
|
+
const finish = () => {
|
|
516
|
+
clearTimeout(timer);
|
|
517
|
+
subscription.signal.removeEventListener("abort", finish);
|
|
518
|
+
resolve();
|
|
519
|
+
};
|
|
520
|
+
const timer = setTimeout(finish, backoff);
|
|
521
|
+
subscription.signal.addEventListener("abort", finish, { once: true });
|
|
522
|
+
if (subscription.signal.aborted) finish();
|
|
523
|
+
});
|
|
524
|
+
backoff = Math.min(backoff * 2, 3e4);
|
|
525
|
+
}
|
|
526
|
+
} finally {
|
|
527
|
+
subscription.onState?.("closed");
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
return {
|
|
532
|
+
...api,
|
|
533
|
+
notifications() {
|
|
534
|
+
return {
|
|
535
|
+
queryKey: [
|
|
536
|
+
"kanvil",
|
|
537
|
+
options.baseUrl,
|
|
538
|
+
"notifications"
|
|
539
|
+
],
|
|
540
|
+
queryFn: () => api.request("/api/v1/notifications", notificationsSchema)
|
|
541
|
+
};
|
|
542
|
+
},
|
|
543
|
+
markNotifications(input) {
|
|
544
|
+
return api.request("/api/v1/notifications/read", okSchema, {
|
|
545
|
+
method: "POST",
|
|
546
|
+
headers: { "Content-Type": "application/json" },
|
|
547
|
+
body: JSON.stringify(notificationReadInput.parse(input))
|
|
548
|
+
});
|
|
549
|
+
},
|
|
550
|
+
dismissNotifications(input) {
|
|
551
|
+
return api.request("/api/v1/notifications/dismiss", okSchema, {
|
|
552
|
+
method: "POST",
|
|
553
|
+
headers: { "Content-Type": "application/json" },
|
|
554
|
+
body: JSON.stringify(notificationIdsInput.parse(input))
|
|
555
|
+
});
|
|
556
|
+
},
|
|
557
|
+
notificationPreferences() {
|
|
558
|
+
return {
|
|
559
|
+
queryKey: [
|
|
560
|
+
"kanvil",
|
|
561
|
+
options.baseUrl,
|
|
562
|
+
"notification-preferences"
|
|
563
|
+
],
|
|
564
|
+
queryFn: () => api.request("/api/v1/notifications/preferences", notificationPreferencesSchema)
|
|
565
|
+
};
|
|
566
|
+
},
|
|
567
|
+
setNotificationPreferences(input) {
|
|
568
|
+
return api.request("/api/v1/notifications/preferences", notificationPreferencesSchema, {
|
|
569
|
+
method: "PUT",
|
|
570
|
+
headers: { "Content-Type": "application/json" },
|
|
571
|
+
body: JSON.stringify(notificationPreferencesInput.parse(input))
|
|
572
|
+
});
|
|
573
|
+
},
|
|
574
|
+
watch(observer) {
|
|
575
|
+
let initial = true;
|
|
576
|
+
return api.subscribe({
|
|
577
|
+
...observer.projectId ? { projectId: observer.projectId } : {},
|
|
578
|
+
signal: observer.signal,
|
|
579
|
+
...observer.onState ? { onState: observer.onState } : {},
|
|
580
|
+
onEvent: (event) => observer.invalidate(event),
|
|
581
|
+
onCursor: async () => {
|
|
582
|
+
if (initial) {
|
|
583
|
+
initial = false;
|
|
584
|
+
await observer.invalidate();
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
onReset: async () => {
|
|
588
|
+
const snapshot = observer.projectId ? await api.request(`/api/v1/snapshot?projectId=${encodeURIComponent(observer.projectId)}`, snapshotSchema) : await api.request("/api/v1/checkpoint", checkpointSchema);
|
|
589
|
+
await observer.invalidate();
|
|
590
|
+
return snapshot.cursor;
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
},
|
|
594
|
+
query(name, input) {
|
|
595
|
+
return {
|
|
596
|
+
queryKey: [
|
|
597
|
+
"kanvil",
|
|
598
|
+
options.baseUrl,
|
|
599
|
+
name,
|
|
600
|
+
input
|
|
601
|
+
],
|
|
602
|
+
queryFn: () => api.call(name, input)
|
|
603
|
+
};
|
|
604
|
+
},
|
|
605
|
+
publicQuery(name, input) {
|
|
606
|
+
return {
|
|
607
|
+
queryKey: [
|
|
608
|
+
"kanvil-public",
|
|
609
|
+
options.baseUrl,
|
|
610
|
+
name,
|
|
611
|
+
input
|
|
612
|
+
],
|
|
613
|
+
queryFn: () => api.callPublic(name, input)
|
|
614
|
+
};
|
|
615
|
+
},
|
|
616
|
+
action(name) {
|
|
617
|
+
return {
|
|
618
|
+
mutationFn: (input) => api.call(name, input),
|
|
619
|
+
networkMode: "always",
|
|
620
|
+
retry: false
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
//#endregion
|
|
626
|
+
//#region src/cli/client.ts
|
|
627
|
+
const commands = {
|
|
628
|
+
"workspace list": "list_workspaces",
|
|
629
|
+
"project list": "list_projects",
|
|
630
|
+
"project get": "get_project",
|
|
631
|
+
"project create": "create_project",
|
|
632
|
+
"task list": "list_tickets",
|
|
633
|
+
"task get": "get_ticket",
|
|
634
|
+
"task create": "create_ticket",
|
|
635
|
+
"task update": "update_ticket",
|
|
636
|
+
"task delete": "delete_ticket",
|
|
637
|
+
"task ready": "list_eligible_tickets",
|
|
638
|
+
"comment list": "list_comments",
|
|
639
|
+
"comment add": "add_comment",
|
|
640
|
+
"claim acquire": "claim_ticket",
|
|
641
|
+
"claim renew": "renew_claim",
|
|
642
|
+
"claim release": "release_claim"
|
|
643
|
+
};
|
|
644
|
+
const clientHelp = `Usage: kanvil <namespace> <action> [ticket-key] [options]
|
|
645
|
+
${Object.keys(commands).join("\n")}
|
|
646
|
+
profile set <name> --server <url> [--project <id>] --token-stdin
|
|
647
|
+
profile list | profile remove <name> --yes
|
|
648
|
+
|
|
649
|
+
--profile <name> Named server/project credential (default: default)
|
|
650
|
+
--config <path> Private configuration (default: ~/.config/kanvil/client.json)
|
|
651
|
+
--input <json|-> Operation input as a JSON object; - reads stdin
|
|
652
|
+
--title <text> Ticket title
|
|
653
|
+
--body <markdown> Comment body
|
|
654
|
+
--expected-version <n> Required version for update, delete and acquire
|
|
655
|
+
--changes <json> Ticket update changes as a JSON object
|
|
656
|
+
--request-id <uuid> Reuse for a deliberate retry across invocations
|
|
657
|
+
--json Compact JSON output (default: indented JSON)
|
|
658
|
+
--yes Confirm task deletion or profile removal
|
|
659
|
+
--help Show commands and input conventions
|
|
660
|
+
|
|
661
|
+
All operation fields also accept --input. A profile's project cannot be overridden.
|
|
662
|
+
Writes never refresh versions or retry conflicts. Credentials are never command arguments.
|
|
663
|
+
`;
|
|
664
|
+
const profileSchema = z.object({
|
|
665
|
+
server: z.string().transform((value, context) => {
|
|
666
|
+
try {
|
|
667
|
+
const url = new URL(value);
|
|
668
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== "/" || url.protocol !== "https:" && !(url.protocol === "http:" && [
|
|
669
|
+
"localhost",
|
|
670
|
+
"127.0.0.1",
|
|
671
|
+
"[::1]"
|
|
672
|
+
].includes(url.hostname))) throw new Error();
|
|
673
|
+
return url.origin;
|
|
674
|
+
} catch {
|
|
675
|
+
context.addIssue({
|
|
676
|
+
code: "custom",
|
|
677
|
+
message: "Use an HTTPS server origin (HTTP only on loopback)."
|
|
678
|
+
});
|
|
679
|
+
return z.NEVER;
|
|
680
|
+
}
|
|
681
|
+
}),
|
|
682
|
+
projectId: z.string().min(1).optional(),
|
|
683
|
+
token: z.string().trim().min(1).max(8192).regex(/^[^\s]+$/)
|
|
684
|
+
});
|
|
685
|
+
const configSchema = z.object({
|
|
686
|
+
version: z.literal(1),
|
|
687
|
+
profiles: z.record(z.string(), profileSchema)
|
|
688
|
+
}).strict();
|
|
689
|
+
const objectSchema = z.record(z.string(), z.unknown());
|
|
690
|
+
var UsageError = class extends ApiError {
|
|
691
|
+
constructor(message) {
|
|
692
|
+
super(400, "invalid_arguments", message);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
function usage(message) {
|
|
696
|
+
throw new UsageError(message);
|
|
697
|
+
}
|
|
698
|
+
function jsonObject(value) {
|
|
699
|
+
try {
|
|
700
|
+
return objectSchema.parse(JSON.parse(value));
|
|
701
|
+
} catch {
|
|
702
|
+
return usage("Input must be a JSON object.");
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
async function readConfig(path) {
|
|
706
|
+
let file;
|
|
707
|
+
try {
|
|
708
|
+
file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
709
|
+
} catch (error) {
|
|
710
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return {
|
|
711
|
+
version: 1,
|
|
712
|
+
profiles: {}
|
|
713
|
+
};
|
|
714
|
+
throw new ApiError(400, "invalid_config", "Cannot open private CLI configuration.");
|
|
715
|
+
}
|
|
716
|
+
try {
|
|
717
|
+
const info = await file.stat();
|
|
718
|
+
if (!info.isFile() || (info.mode & 63) !== 0) usage("CLI configuration must be a private file (chmod 600).");
|
|
719
|
+
return configSchema.parse(JSON.parse(await file.readFile("utf8")));
|
|
720
|
+
} catch {
|
|
721
|
+
throw new ApiError(400, "invalid_config", "Invalid CLI configuration; require a private file (chmod 600).");
|
|
722
|
+
} finally {
|
|
723
|
+
await file.close();
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
async function saveConfig(path, config) {
|
|
727
|
+
await mkdir(dirname(path), {
|
|
728
|
+
recursive: true,
|
|
729
|
+
mode: 448
|
|
730
|
+
});
|
|
731
|
+
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
732
|
+
try {
|
|
733
|
+
const file = await open(temporary, "wx", 384);
|
|
734
|
+
try {
|
|
735
|
+
await file.writeFile(JSON.stringify(config) + "\n");
|
|
736
|
+
} finally {
|
|
737
|
+
await file.close();
|
|
738
|
+
}
|
|
739
|
+
await rename(temporary, path);
|
|
740
|
+
} finally {
|
|
741
|
+
await rm(temporary, { force: true });
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
async function runClient(args, io) {
|
|
745
|
+
let secret = "";
|
|
746
|
+
let compact = args.includes("--json");
|
|
747
|
+
const serialize = (value, pretty = false) => JSON.stringify(value, (_key, item) => typeof item === "string" && secret ? item.replaceAll(secret, "[redacted]") : item, pretty ? 2 : void 0);
|
|
748
|
+
const output = (value) => io.stdout(serialize(value, !compact) + "\n");
|
|
749
|
+
try {
|
|
750
|
+
const { values, positionals } = parseArgs({
|
|
751
|
+
args,
|
|
752
|
+
allowPositionals: true,
|
|
753
|
+
options: {
|
|
754
|
+
help: { type: "boolean" },
|
|
755
|
+
json: { type: "boolean" },
|
|
756
|
+
yes: { type: "boolean" },
|
|
757
|
+
profile: {
|
|
758
|
+
type: "string",
|
|
759
|
+
default: "default"
|
|
760
|
+
},
|
|
761
|
+
config: { type: "string" },
|
|
762
|
+
input: { type: "string" },
|
|
763
|
+
server: { type: "string" },
|
|
764
|
+
project: { type: "string" },
|
|
765
|
+
"token-stdin": { type: "boolean" },
|
|
766
|
+
title: { type: "string" },
|
|
767
|
+
body: { type: "string" },
|
|
768
|
+
"expected-version": { type: "string" },
|
|
769
|
+
changes: { type: "string" },
|
|
770
|
+
"request-id": { type: "string" }
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
compact = values.json ?? false;
|
|
774
|
+
if (values.help) {
|
|
775
|
+
io.stdout(clientHelp);
|
|
776
|
+
return 0;
|
|
777
|
+
}
|
|
778
|
+
const [namespace, action, identifier, ...extra] = positionals;
|
|
779
|
+
if (extra.length) usage("Too many command arguments.");
|
|
780
|
+
const path = values.config ?? io.configPath ?? join(homedir(), ".config", "kanvil", "client.json");
|
|
781
|
+
const config = await readConfig(path);
|
|
782
|
+
if (namespace === "profile") {
|
|
783
|
+
if (action === "list" && !identifier) output(Object.entries(config.profiles).map(([name, { server, projectId }]) => ({
|
|
784
|
+
name,
|
|
785
|
+
server,
|
|
786
|
+
projectId
|
|
787
|
+
})));
|
|
788
|
+
else if (action === "set" && identifier) {
|
|
789
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,79}$/.test(identifier)) usage("Use a profile name containing letters, digits, hyphens or underscores.");
|
|
790
|
+
if (!values["token-stdin"] || values.input) usage("Pass the credential privately with --token-stdin; do not use --input.");
|
|
791
|
+
secret = (await io.stdin()).trim();
|
|
792
|
+
const profile = profileSchema.parse({
|
|
793
|
+
server: values.server,
|
|
794
|
+
projectId: values.project,
|
|
795
|
+
token: secret
|
|
796
|
+
});
|
|
797
|
+
if (Object.hasOwn(config.profiles, identifier) && !values.yes) usage("Replacing a profile requires --yes.");
|
|
798
|
+
Object.defineProperty(config.profiles, identifier, {
|
|
799
|
+
value: profile,
|
|
800
|
+
enumerable: true,
|
|
801
|
+
configurable: true,
|
|
802
|
+
writable: true
|
|
803
|
+
});
|
|
804
|
+
await saveConfig(path, config);
|
|
805
|
+
output({
|
|
806
|
+
name: identifier,
|
|
807
|
+
server: profile.server,
|
|
808
|
+
projectId: profile.projectId
|
|
809
|
+
});
|
|
810
|
+
} else if (action === "remove" && identifier) {
|
|
811
|
+
if (!values.yes) usage("Removing a profile requires --yes.");
|
|
812
|
+
if (!Object.hasOwn(config.profiles, identifier)) usage("Unknown profile.");
|
|
813
|
+
delete config.profiles[identifier];
|
|
814
|
+
await saveConfig(path, config);
|
|
815
|
+
output({ ok: true });
|
|
816
|
+
} else usage("Unknown profile command. Use --help.");
|
|
817
|
+
return 0;
|
|
818
|
+
}
|
|
819
|
+
if (values.server || values.project || values["token-stdin"]) usage("Server, project and token options belong to profile set.");
|
|
820
|
+
const command = Object.entries(commands).find(([name]) => name === `${namespace} ${action}`)?.[1];
|
|
821
|
+
if (!command) usage("Unknown client command. Use --help.");
|
|
822
|
+
const profile = Object.hasOwn(config.profiles, values.profile) ? config.profiles[values.profile] : void 0;
|
|
823
|
+
if (!profile) usage("Unknown profile. Use profile set first.");
|
|
824
|
+
secret = profile.token;
|
|
825
|
+
const input = values.input ? jsonObject(values.input === "-" ? await io.stdin() : values.input) : {};
|
|
826
|
+
if (profile.projectId) {
|
|
827
|
+
if (input.projectId !== void 0 && input.projectId !== profile.projectId) usage("Input project differs from the selected profile.");
|
|
828
|
+
if ("projectId" in operations[command].input.shape) input.projectId = profile.projectId;
|
|
829
|
+
}
|
|
830
|
+
if (identifier) {
|
|
831
|
+
if (!("ticketId" in operations[command].input.shape)) usage("This command takes no ticket argument.");
|
|
832
|
+
if (input.ticketId !== void 0 && input.ticketId !== identifier) usage("Conflicting ticket identifiers.");
|
|
833
|
+
input.ticketId = identifier;
|
|
834
|
+
}
|
|
835
|
+
for (const key of ["title", "body"]) if (values[key] !== void 0) input[key] = values[key];
|
|
836
|
+
if (values["expected-version"] !== void 0) input.expectedVersion = Number(values["expected-version"]);
|
|
837
|
+
if (values["request-id"] !== void 0) input.requestId = values["request-id"];
|
|
838
|
+
if (values.changes !== void 0) input.changes = jsonObject(values.changes);
|
|
839
|
+
if (command === "delete_ticket" && !values.yes) usage("Deleting a task requires --yes and --expected-version.");
|
|
840
|
+
const spec = operations[command];
|
|
841
|
+
if (Object.keys(input).some((key) => !Object.hasOwn(spec.input.shape, key))) usage("Unknown operation input field. See the API operation schema.");
|
|
842
|
+
const parsed = spec.input.parse(input);
|
|
843
|
+
output(await createClient({
|
|
844
|
+
baseUrl: profile.server,
|
|
845
|
+
headers: () => ({ Authorization: `Bearer ${profile.token}` }),
|
|
846
|
+
credentials: "omit",
|
|
847
|
+
fetch: (url, init) => (io.fetch ?? fetch)(url, {
|
|
848
|
+
...init,
|
|
849
|
+
redirect: "error",
|
|
850
|
+
signal: AbortSignal.timeout(3e4)
|
|
851
|
+
})
|
|
852
|
+
}).call(command, parsed).catch((error) => {
|
|
853
|
+
if (error instanceof z.ZodError) throw new ApiError(502, "invalid_response", "Invalid server response.");
|
|
854
|
+
throw error;
|
|
855
|
+
}));
|
|
856
|
+
return 0;
|
|
857
|
+
} catch (error) {
|
|
858
|
+
const status = error instanceof ApiError ? error.status : 0;
|
|
859
|
+
const code = error instanceof ApiError ? error.code : error instanceof z.ZodError ? "invalid_arguments" : "client_error";
|
|
860
|
+
const message = error instanceof UsageError ? error.message : error instanceof z.ZodError ? "Invalid input. Check the operation schema and required fields." : "Command failed. Check the error code, profile, permissions and server connection.";
|
|
861
|
+
io.stderr(serialize({ error: {
|
|
862
|
+
code,
|
|
863
|
+
message
|
|
864
|
+
} }) + "\n");
|
|
865
|
+
return status === 401 || status === 403 ? 3 : status === 404 ? 4 : status === 409 ? 5 : status === 400 || error instanceof z.ZodError || error instanceof SyntaxError || error instanceof TypeError && "code" in error ? 2 : error instanceof TypeError || error instanceof Error && error.name === "TimeoutError" ? 6 : 1;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
//#endregion
|
|
869
|
+
//#region src/cli/client-main.ts
|
|
870
|
+
process.exitCode = await runClient(process.argv.slice(2), {
|
|
871
|
+
stdin: async () => {
|
|
872
|
+
process.stdin.setEncoding("utf8");
|
|
873
|
+
let text = "";
|
|
874
|
+
for await (const chunk of process.stdin) {
|
|
875
|
+
text += String(chunk);
|
|
876
|
+
if (Buffer.byteLength(text) > 1e6) throw new Error("Input exceeds the CLI limit.");
|
|
877
|
+
}
|
|
878
|
+
return text;
|
|
879
|
+
},
|
|
880
|
+
stdout: (text) => process.stdout.write(text),
|
|
881
|
+
stderr: (text) => process.stderr.write(text)
|
|
882
|
+
});
|
|
883
|
+
//#endregion
|
|
884
|
+
export {};
|