export & import in opencollection format (#6329)

This commit is contained in:
naman-bruno
2025-12-24 22:28:38 +05:30
committed by GitHub
parent 1b8eece173
commit 67903f26bc
33 changed files with 3180 additions and 222 deletions

267
package-lock.json generated
View File

@@ -1604,7 +1604,7 @@
"version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz",
"integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9",
@@ -1622,7 +1622,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz",
"integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-compilation-targets": "^7.22.6",
@@ -1639,7 +1639,7 @@
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -1657,7 +1657,7 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/@babel/helper-globals": {
@@ -1737,7 +1737,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz",
"integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9",
@@ -1812,7 +1812,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz",
"integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.25.9",
@@ -1855,7 +1855,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz",
"integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -1872,7 +1872,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz",
"integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -1888,7 +1888,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz",
"integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -1904,7 +1904,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz",
"integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -1922,7 +1922,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz",
"integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -1957,7 +1957,7 @@
"version": "7.21.0-placeholder-for-preset-env.2",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
"integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -2056,7 +2056,7 @@
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz",
"integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2072,7 +2072,7 @@
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz",
"integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2254,7 +2254,7 @@
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
"integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
@@ -2271,7 +2271,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz",
"integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2287,7 +2287,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz",
"integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -2305,7 +2305,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz",
"integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.25.9",
@@ -2323,7 +2323,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz",
"integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2339,7 +2339,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz",
"integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2371,7 +2371,7 @@
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz",
"integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.25.9",
@@ -2388,7 +2388,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz",
"integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9",
@@ -2409,7 +2409,7 @@
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -2419,7 +2419,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz",
"integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -2436,7 +2436,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz",
"integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2452,7 +2452,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz",
"integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -2469,7 +2469,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz",
"integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2485,7 +2485,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz",
"integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -2502,7 +2502,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz",
"integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2518,7 +2518,7 @@
"version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz",
"integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2534,7 +2534,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz",
"integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2566,7 +2566,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz",
"integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -2583,7 +2583,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz",
"integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-compilation-targets": "^7.25.9",
@@ -2601,7 +2601,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz",
"integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2617,7 +2617,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz",
"integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2633,7 +2633,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz",
"integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2649,7 +2649,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz",
"integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2665,7 +2665,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz",
"integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-transforms": "^7.25.9",
@@ -2698,7 +2698,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz",
"integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-transforms": "^7.25.9",
@@ -2717,7 +2717,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz",
"integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-transforms": "^7.25.9",
@@ -2734,7 +2734,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz",
"integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -2751,7 +2751,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz",
"integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2782,7 +2782,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz",
"integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2798,7 +2798,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz",
"integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-compilation-targets": "^7.25.9",
@@ -2816,7 +2816,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz",
"integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -2833,7 +2833,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz",
"integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2865,7 +2865,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz",
"integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -2897,7 +2897,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz",
"integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9",
@@ -2915,7 +2915,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz",
"integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3000,7 +3000,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz",
"integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -3017,7 +3017,7 @@
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz",
"integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -3034,7 +3034,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz",
"integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3050,7 +3050,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz",
"integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3066,7 +3066,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz",
"integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
@@ -3083,7 +3083,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz",
"integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3099,7 +3099,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz",
"integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3115,7 +3115,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz",
"integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3150,7 +3150,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz",
"integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
@@ -3166,7 +3166,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz",
"integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -3183,7 +3183,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz",
"integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -3200,7 +3200,7 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz",
"integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.25.9",
@@ -3217,7 +3217,7 @@
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz",
"integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.26.0",
@@ -3318,7 +3318,7 @@
"version": "0.1.6-no-external-plugins",
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
"integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
@@ -5949,22 +5949,6 @@
"node": ">=18"
}
},
"node_modules/@modelcontextprotocol/sdk/node_modules/raw-body": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.6.3",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/@module-federation/runtime": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.5.1.tgz",
@@ -9563,7 +9547,6 @@
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.10.4",
@@ -9583,7 +9566,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -9596,7 +9578,6 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1",
@@ -9611,7 +9592,6 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
"license": "MIT"
},
"node_modules/@testing-library/jest-dom": {
@@ -9722,7 +9702,6 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/babel__core": {
@@ -10015,7 +9994,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/lodash": {
@@ -10038,7 +10016,6 @@
"version": "12.2.3",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
"integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/linkify-it": "*",
@@ -10049,7 +10026,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/ms": {
@@ -11424,7 +11400,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"dequal": "^2.0.3"
@@ -11869,7 +11844,7 @@
"version": "0.4.12",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz",
"integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.22.6",
@@ -11884,7 +11859,7 @@
"version": "0.10.6",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz",
"integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.6.2",
@@ -11898,7 +11873,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz",
"integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.6.3"
@@ -13788,7 +13763,7 @@
"version": "3.39.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz",
"integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.24.2"
@@ -14937,7 +14912,6 @@
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
"license": "MIT"
},
"node_modules/dom-converter": {
@@ -16010,7 +15984,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
"devOptional": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
@@ -16251,27 +16225,6 @@
"node": ">= 0.6"
}
},
"node_modules/express/node_modules/body-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
"dev": true,
"license": "MIT",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"debug": "^4.4.0",
"http-errors": "^2.0.0",
"iconv-lite": "^0.6.3",
"on-finished": "^2.4.1",
"qs": "^6.14.0",
"raw-body": "^3.0.0",
"type-is": "^2.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/express/node_modules/content-disposition": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
@@ -16404,22 +16357,6 @@
"node": ">= 0.6"
}
},
"node_modules/express/node_modules/raw-body": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.6.3",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/express/node_modules/send": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
@@ -18923,7 +18860,7 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@@ -21380,7 +21317,6 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
"bin": {
"lz-string": "bin/bin.js"
@@ -22995,7 +22931,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/path-scurry": {
@@ -25522,14 +25458,14 @@
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
"integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/regenerate-unicode-properties": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
"integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"regenerate": "^1.4.2"
@@ -25548,7 +25484,7 @@
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
"integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.8.4"
@@ -25558,7 +25494,7 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
"integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"regenerate": "^1.4.2",
@@ -25576,14 +25512,14 @@
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
"integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/regjsparser": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
"integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
"dev": true,
"devOptional": true,
"license": "BSD-2-Clause",
"dependencies": {
"jsesc": "~3.0.2"
@@ -25596,7 +25532,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -25792,7 +25728,7 @@
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.0",
@@ -28110,7 +28046,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -29297,7 +29233,7 @@
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -29358,7 +29294,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
"integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -29368,7 +29304,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
"integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"unicode-canonical-property-names-ecmascript": "^2.0.0",
@@ -29382,7 +29318,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
"integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -29392,7 +29328,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
"integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -33196,16 +33132,6 @@
"@babel/core": "^7.0.0"
}
},
"packages/bruno-common/node_modules/@babel/helper-plugin-utils": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
"integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"packages/bruno-common/node_modules/@babel/helper-replace-supers": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz",
@@ -33677,10 +33603,12 @@
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.4",
"@opencollection/types": "0.3.0",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^9.0.2",
"@usebruno/schema-types": "0.0.1",
"@web/rollup-plugin-copy": "^0.5.1",
"babel-jest": "^29.7.0",
"rimraf": "^5.0.7",
@@ -35547,17 +35475,6 @@
"rollup-plugin-terser": "^7.0.2"
}
},
"packages/bruno-js/node_modules/axios": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"packages/bruno-js/node_modules/jsonwebtoken": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
@@ -35619,18 +35536,6 @@
"node": ">=10"
}
},
"packages/bruno-js/node_modules/xml-formatter": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/xml-formatter/-/xml-formatter-3.5.0.tgz",
"integrity": "sha512-9ij/f2PLIPv+YDywtdztq7U82kYMDa5yPYwpn0TnXnqJRH6Su8RC/oaw91erHe3aSEbfgBaA1hDzReDFb1SVXw==",
"license": "MIT",
"dependencies": {
"xml-parser-xo": "^4.1.0"
},
"engines": {
"node": ">= 14"
}
},
"packages/bruno-lang": {
"name": "@usebruno/lang",
"version": "0.12.0",

View File

@@ -26,6 +26,21 @@ const StyledWrapper = styled.div`
}
}
}
.share-button {
display: flex;
border-radius: ${(props) => props.theme.border.radius.base};
padding: 10px;
border: 1px solid ${(props) => props.theme.sidebar.collection.item.indentBorder};
background-color: ${(props) => props.theme.sidebar.bg};
color: ${(props) => props.theme.text};
cursor: pointer;
transition: all 0.1s ease;
&:hover {
background-color: ${(props) => props.theme.listItem.hoverBg};
}
}
`;
export default StyledWrapper;

View File

@@ -1,10 +1,11 @@
import React, { useMemo } from 'react';
import Modal from 'components/Modal';
import { IconUpload, IconLoader2, IconAlertTriangle } from '@tabler/icons';
import { IconUpload, IconLoader2, IconAlertTriangle, IconFileExport } from '@tabler/icons';
import StyledWrapper from './StyledWrapper';
import Bruno from 'components/Bruno';
import exportBrunoCollection from 'utils/collections/export';
import exportPostmanCollection from 'utils/exporters/postman-collection';
import exportOpenCollection from 'utils/exporters/opencollection';
import { cloneDeep } from 'lodash';
import { transformCollectionToSaveToExportAsFile } from 'utils/collections/index';
import { useSelector } from 'react-redux';
@@ -48,6 +49,12 @@ const ShareCollection = ({ onClose, collectionUid }) => {
onClose();
};
const handleExportOpenCollection = () => {
const collectionCopy = cloneDeep(collection);
exportOpenCollection(transformCollectionToSaveToExportAsFile(collectionCopy));
onClose();
};
return (
<Modal
size="md"
@@ -60,10 +67,10 @@ const ShareCollection = ({ onClose, collectionUid }) => {
<StyledWrapper className="flex flex-col h-full w-[500px]">
<div className="space-y-2">
<div
className={`flex border border-gray-200 dark:border-gray-600 items-center p-3 rounded-lg transition-colors ${
className={`share-button ${
isCollectionLoading
? 'opacity-50 cursor-not-allowed'
: 'hover:bg-gray-100 dark:hover:bg-gray-500/10 cursor-pointer'
: 'cursor-pointer'
}`}
onClick={isCollectionLoading ? undefined : handleExportBrunoCollection}
>
@@ -77,10 +84,31 @@ const ShareCollection = ({ onClose, collectionUid }) => {
</div>
<div
className={`flex flex-col border border-gray-200 dark:border-gray-600 items-center rounded-lg transition-colors ${
className={`share-button ${
isCollectionLoading
? 'opacity-50 cursor-not-allowed'
: 'hover:bg-gray-100 dark:hover:bg-gray-500/10 cursor-pointer'
: 'cursor-pointer'
}`}
onClick={isCollectionLoading ? undefined : handleExportOpenCollection}
>
<div className="mr-3 p-1 rounded-full">
{isCollectionLoading ? (
<IconLoader2 size={28} className="animate-spin" />
) : (
<IconFileExport size={28} strokeWidth={1} />
)}
</div>
<div className="flex-1">
<div className="font-medium">OpenCollection</div>
<div className="text-xs">{isCollectionLoading ? 'Loading collection...' : 'Export in OpenCollection format'}</div>
</div>
</div>
<div
className={`flex !flex-col share-button ${
isCollectionLoading
? 'opacity-50 cursor-not-allowed'
: 'cursor-pointer'
}`}
onClick={isCollectionLoading ? undefined : handleExportPostmanCollection}
>

View File

@@ -8,6 +8,7 @@ import { isInsomniaCollection } from 'utils/importers/insomnia-collection';
import { isOpenApiSpec } from 'utils/importers/openapi-collection';
import { isWSDLCollection } from 'utils/importers/wsdl-collection';
import { isBrunoCollection } from 'utils/importers/bruno-collection';
import { isOpenCollection } from 'utils/importers/opencollection';
import FullscreenLoader from './FullscreenLoader/index';
const convertFileToObject = async (file) => {
@@ -72,6 +73,8 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
type = 'postman';
} else if (isInsomniaCollection(data)) {
type = 'insomnia';
} else if (isOpenCollection(data)) {
type = 'opencollection';
} else if (isBrunoCollection(data)) {
type = 'bruno';
} else {
@@ -159,7 +162,7 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
</button>
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
Supports Bruno, Postman, Insomnia, OpenAPI v3, and WSDL formats
Supports Bruno, OpenCollection, Postman, Insomnia, OpenAPI v3, and WSDL formats
</p>
</div>
</div>

View File

@@ -9,6 +9,7 @@ import { postmanToBruno } from 'utils/importers/postman-collection';
import { convertInsomniaToBruno } from 'utils/importers/insomnia-collection';
import { convertOpenapiToBruno } from 'utils/importers/openapi-collection';
import { processBrunoCollection } from 'utils/importers/bruno-collection';
import { processOpenCollection } from 'utils/importers/opencollection';
import { wsdlToBruno } from '@usebruno/converters';
import { toastError } from 'utils/common/error';
import Modal from 'components/Modal';
@@ -37,6 +38,8 @@ const getCollectionName = (format, rawData) => {
return rawData.name || 'Insomnia Collection';
case 'bruno':
return rawData.name || 'Bruno Collection';
case 'opencollection':
return rawData.info?.name || 'OpenCollection';
case 'wsdl':
return 'WSDL Collection';
default:
@@ -65,6 +68,9 @@ const convertCollection = async (format, rawData, groupingType) => {
case 'bruno':
collection = await processBrunoCollection(rawData);
break;
case 'opencollection':
collection = await processOpenCollection(rawData);
break;
default:
throw new Error('Unknown collection format');
}

View File

@@ -36,6 +36,10 @@ const transformCollection = async (collection, type) => {
const { convertOpenapiToBruno } = await import('utils/importers/openapi-collection');
return convertOpenapiToBruno(collection);
}
case 'opencollection': {
const { processOpenCollection } = await import('utils/importers/opencollection');
return processOpenCollection(collection);
}
case 'wsdl': {
const { wsdlToBruno } = await import('@usebruno/converters');
return wsdlToBruno(collection);

View File

@@ -0,0 +1,23 @@
import * as FileSaver from 'file-saver';
import jsyaml from 'js-yaml';
import { brunoToOpenCollection } from '@usebruno/converters';
import { sanitizeName } from 'utils/common/regex';
export const exportCollection = (collection) => {
const openCollection = brunoToOpenCollection(collection);
const yamlContent = jsyaml.dump(openCollection, {
indent: 2,
lineWidth: -1,
noRefs: true,
sortKeys: false
});
const sanitizedName = sanitizeName(collection.name);
const fileName = `${sanitizedName}.yml`;
const fileBlob = new Blob([yamlContent], { type: 'application/x-yaml' });
FileSaver.saveAs(fileBlob, fileName);
};
export default exportCollection;

View File

@@ -0,0 +1,81 @@
import each from 'lodash/each';
import { uuid } from 'utils/common';
import { BrunoError } from 'utils/common/error';
import { validateSchema, updateUidsInCollection, hydrateSeqInCollection } from './common';
import { openCollectionToBruno } from '@usebruno/converters';
const addUidsToRoot = (collection) => {
if (collection.root?.request?.headers) {
each(collection.root.request.headers, (header) => {
header.uid = uuid();
});
}
if (collection.root?.request?.vars?.req) {
each(collection.root.request.vars.req, (v) => {
v.uid = uuid();
});
}
if (collection.root?.request?.vars?.res) {
each(collection.root.request.vars.res, (v) => {
v.uid = uuid();
});
}
const addUidsToFolderRoot = (items) => {
each(items, (item) => {
if (item.type === 'folder') {
if (item.root?.request?.headers) {
each(item.root.request.headers, (header) => {
header.uid = uuid();
});
}
if (item.root?.request?.vars?.req) {
each(item.root.request.vars.req, (v) => {
v.uid = uuid();
});
}
if (item.root?.request?.vars?.res) {
each(item.root.request.vars.res, (v) => {
v.uid = uuid();
});
}
if (item.items?.length) {
addUidsToFolderRoot(item.items);
}
}
});
};
addUidsToFolderRoot(collection.items);
return collection;
};
export const processOpenCollection = async (jsonData) => {
try {
let collection = openCollectionToBruno(jsonData);
collection = hydrateSeqInCollection(collection);
collection = updateUidsInCollection(collection);
collection = addUidsToRoot(collection);
await validateSchema(collection);
return collection;
} catch (err) {
console.error('Error processing OpenCollection:', err);
throw new BrunoError('Import OpenCollection failed');
}
};
export const isOpenCollection = (data) => {
if (typeof data !== 'object' || data === null) {
return false;
}
if (typeof data.opencollection !== 'string' || !data.opencollection.trim()) {
return false;
}
if (typeof data.info !== 'object' || data.info === null) {
return false;
}
return true;
};

View File

@@ -4,7 +4,6 @@
"license": "MIT",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"src",
@@ -29,6 +28,8 @@
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.4",
"@opencollection/types": "0.3.0",
"@usebruno/schema-types": "0.0.1",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-node-resolve": "^15.0.1",

View File

@@ -1,43 +1,89 @@
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const typescript = require('@rollup/plugin-typescript');
const { terser } = require('rollup-plugin-terser');
const peerDepsExternal = require('rollup-plugin-peer-deps-external');
const { copy } = require('@web/rollup-plugin-copy');
const path = require('path');
const packageJson = require('./package.json');
const alias = require('@rollup/plugin-alias');
const path = require('path');
const externalDeps = [
'@usebruno/schema',
'@usebruno/schema-types',
/@usebruno\/schema-types\/.*/,
'@opencollection/types',
/@opencollection\/types\/.*/,
// Runtime dependencies
'lodash',
'lodash/each',
'lodash/get',
'lodash/cloneDeep',
'lodash/map',
'js-yaml',
'jscodeshift',
'nanoid',
'xml2js',
// Node built-ins
'path',
'fs'
];
module.exports = [
{
input: 'src/index.js',
output: [
{
dir: path.dirname(packageJson.main),
format: 'cjs',
sourcemap: true
},
{
dir: path.dirname(packageJson.module),
format: 'esm',
sourcemap: true
}
],
output: {
dir: path.dirname(packageJson.main),
format: 'cjs',
sourcemap: true,
exports: 'named',
entryFileNames: 'index.js'
},
plugins: [
peerDepsExternal(),
nodeResolve({
preferBuiltins: true,
extensions: ['.js', '.css'] // Resolve .js files
extensions: ['.js', '.ts', '.tsx', '.json']
}),
commonjs(),
terser(),
alias({
entries: [{ find: 'src', replacement: path.resolve(__dirname, 'src') }]
typescript({
tsconfig: './tsconfig.json',
sourceMap: true,
outDir: path.dirname(packageJson.main)
}),
terser(),
copy({
patterns: 'src/workers/scripts/**/*',
rootDir: '.'
})
]
],
external: externalDeps
},
{
input: 'src/index.js',
output: {
dir: path.dirname(packageJson.module),
format: 'esm',
sourcemap: true,
exports: 'named',
entryFileNames: 'index.js'
},
plugins: [
peerDepsExternal(),
nodeResolve({
extensions: ['.js', '.ts', '.tsx', '.json']
}),
commonjs(),
typescript({
tsconfig: './tsconfig.json',
sourceMap: true,
outDir: path.dirname(packageJson.module)
}),
terser(),
copy({
patterns: 'src/workers/scripts/**/*',
rootDir: '.'
})
],
external: externalDeps
}
];

View File

@@ -5,3 +5,5 @@ export { default as openApiToBruno } from './openapi/openapi-to-bruno.js';
export { default as insomniaToBruno } from './insomnia/insomnia-to-bruno.js';
export { default as wsdlToBruno } from './wsdl/wsdl-to-bruno.js';
export { default as postmanTranslation } from './postman/postman-translations.js';
export { openCollectionToBruno } from './opencollection/opencollection-to-bruno.js';
export { brunoToOpenCollection } from './opencollection/bruno-to-opencollection.js';

View File

@@ -0,0 +1,172 @@
import { toOpenCollectionAuth, toOpenCollectionHeaders, toOpenCollectionScripts, toOpenCollectionVariables } from "./common";
import { toOpenCollectionEnvironments } from "./environment";
import { toOpenCollectionFolder } from "./folder";
import { toOpenCollectionItems } from "./items";
import { BrunoCollection, BrunoCollectionRoot, BrunoConfig, ClientCertificate, CollectionConfig, OpenCollection, PemCertificate, Pkcs12Certificate, Protobuf } from "./types";
const toOpenCollectionConfig = (brunoConfig: BrunoConfig | undefined): CollectionConfig | undefined => {
if (!brunoConfig) {
return undefined;
}
const config: CollectionConfig = {};
if (brunoConfig.protobuf?.protoFiles?.length || brunoConfig.protobuf?.importPaths?.length) {
config.protobuf = {} as Protobuf;
if (brunoConfig.protobuf.protoFiles?.length) {
config.protobuf.protoFiles = brunoConfig.protobuf.protoFiles.map((f) => ({
type: 'file' as const,
path: f.path
}));
}
if (brunoConfig.protobuf.importPaths?.length) {
config.protobuf.importPaths = brunoConfig.protobuf.importPaths.map((p) => {
const importPath: { path: string; disabled?: boolean } = { path: p.path };
if (p.disabled) {
importPath.disabled = true;
}
return importPath;
});
}
}
if (brunoConfig.proxy?.enabled) {
if (brunoConfig.proxy.enabled === 'global') {
config.proxy = 'inherit';
} else {
config.proxy = {
protocol: brunoConfig.proxy.protocol || 'http',
hostname: brunoConfig.proxy.hostname || '',
port: brunoConfig.proxy.port || 0
};
if (brunoConfig.proxy.auth?.enabled) {
config.proxy.auth = {
username: brunoConfig.proxy.auth.username || '',
password: brunoConfig.proxy.auth.password || ''
};
}
if (brunoConfig.proxy.bypassProxy) {
config.proxy.bypassProxy = brunoConfig.proxy.bypassProxy;
}
}
}
if (brunoConfig.clientCertificates?.certs?.length) {
config.clientCertificates = brunoConfig.clientCertificates.certs
.map((cert): ClientCertificate | null => {
if (cert.type === 'pem') {
const pemCert: PemCertificate = {
domain: cert.domain || '',
type: 'pem',
certificateFilePath: cert.certFilePath || '',
privateKeyFilePath: cert.keyFilePath || ''
};
if (cert.passphrase) {
pemCert.passphrase = cert.passphrase;
}
return pemCert;
} else if (cert.type === 'pkcs12') {
const pkcs12Cert: Pkcs12Certificate = {
domain: cert.domain || '',
type: 'pkcs12',
pkcs12FilePath: cert.pfxFilePath || ''
};
if (cert.passphrase) {
pkcs12Cert.passphrase = cert.passphrase;
}
return pkcs12Cert;
}
return null;
})
.filter((cert): cert is ClientCertificate => cert !== null);
}
return Object.keys(config).length > 0 ? config : undefined;
};
const hasRequestDefaults = (root: BrunoCollectionRoot | undefined): boolean => {
const request = root?.request;
return Boolean(
request?.headers?.length ||
request?.vars?.req?.length ||
request?.script?.req ||
request?.script?.res ||
request?.tests ||
(request?.auth && request.auth.mode !== 'none')
);
};
export const brunoToOpenCollection = (collection: BrunoCollection): OpenCollection => {
const openCollection: OpenCollection = {
opencollection: '1.0.0',
info: {
name: collection.name || 'Untitled Collection'
}
};
const config = toOpenCollectionConfig(collection.brunoConfig as BrunoConfig);
if (config) {
openCollection.config = config;
}
const environments = toOpenCollectionEnvironments(collection.environments ?? undefined);
if (environments?.length) {
if (!openCollection.config) {
openCollection.config = {};
}
openCollection.config.environments = environments;
}
const items = toOpenCollectionItems(collection.items, toOpenCollectionFolder);
if (items.length) {
openCollection.items = items as OpenCollection['items'];
}
if (hasRequestDefaults(collection.root as BrunoCollectionRoot)) {
const request = (collection.root as BrunoCollectionRoot)?.request;
openCollection.request = {};
const headers = toOpenCollectionHeaders(request?.headers);
if (headers) {
openCollection.request.headers = headers;
}
const auth = toOpenCollectionAuth(request?.auth);
if (auth) {
openCollection.request.auth = auth;
}
const variables = toOpenCollectionVariables(request?.vars);
if (variables) {
openCollection.request.variables = variables;
}
const scripts = toOpenCollectionScripts(request as any);
if (scripts) {
openCollection.request.scripts = scripts;
}
}
if ((collection.root as BrunoCollectionRoot)?.docs) {
openCollection.docs = {
content: (collection.root as BrunoCollectionRoot).docs!,
type: 'text/markdown'
};
}
openCollection.bundled = true;
const extensions: { ignore?: string[] } = {};
if ((collection.brunoConfig as BrunoConfig)?.ignore?.length) {
extensions.ignore = (collection.brunoConfig as BrunoConfig).ignore;
}
if (Object.keys(extensions).length > 0) {
openCollection.extensions = extensions;
}
return openCollection;
};

View File

@@ -0,0 +1,83 @@
import { uuid } from '../../common/index.js';
import type {
Action,
ActionSetVariable,
ActionVariableScope,
BrunoVariable,
BrunoVariables
} from '../types';
/**
* Convert Bruno post-response variables to OpenCollection actions.
* Post-response variables in Bruno are converted to 'set-variable' actions
* with phase 'after-response'.
*/
export const toOpenCollectionActions = (resVariables: BrunoVariables | null | undefined): Action[] | undefined => {
if (!resVariables?.length) {
return undefined;
}
const actions: Action[] = resVariables.map((v: BrunoVariable): ActionSetVariable => {
const action: ActionSetVariable = {
type: 'set-variable',
phase: 'after-response',
selector: {
expression: v.value || '',
method: 'jsonq'
},
variable: {
name: v.name || '',
scope: v.local ? 'request' : 'runtime' as ActionVariableScope
}
};
if (v.description && typeof v.description === 'string' && v.description.trim().length) {
action.description = v.description;
}
if (v.enabled === false) {
action.disabled = true;
}
return action;
});
return actions.length > 0 ? actions : undefined;
};
/**
* Convert OpenCollection actions to Bruno post-response variables.
* Only 'set-variable' actions with phase 'after-response' are converted.
*/
export const fromOpenCollectionActions = (actions: Action[] | null | undefined): BrunoVariables => {
if (!actions?.length) {
return [];
}
const resVars: BrunoVariables = [];
actions.forEach((action: Action) => {
// Only process 'set-variable' actions with 'after-response' phase
if (action.type === 'set-variable' && action.phase === 'after-response') {
const setVarAction = action as ActionSetVariable;
const variable: BrunoVariable = {
uid: uuid(),
name: setVarAction.variable?.name || '',
value: setVarAction.selector?.expression || '',
enabled: setVarAction.disabled !== true,
local: setVarAction.variable?.scope === 'request'
};
if (setVarAction.description) {
variable.description = typeof setVarAction.description === 'string'
? setVarAction.description
: (setVarAction.description as { content?: string })?.content || '';
}
resVars.push(variable);
}
});
return resVars;
};

View File

@@ -0,0 +1,48 @@
import { uuid } from '../../common/index.js';
import type {
Assertion,
BrunoKeyValue
} from '../types';
export const fromOpenCollectionAssertions = (assertions: Assertion[] | undefined): BrunoKeyValue[] => {
if (!assertions?.length) {
return [];
}
return assertions.map((a): BrunoKeyValue => ({
uid: uuid(),
name: a.expression || '',
value: `${a.operator || 'eq'} ${a.value || ''}`.trim(),
description: typeof a.description === 'string' ? a.description : a.description?.content || null,
enabled: a.disabled !== true
}));
};
export const toOpenCollectionAssertions = (assertions: BrunoKeyValue[] | null | undefined): Assertion[] | undefined => {
if (!assertions?.length) {
return undefined;
}
return assertions.map((a): Assertion => {
const valueStr = a.value || '';
const parts = valueStr.split(' ');
const operator = parts[0] || 'eq';
const value = parts.slice(1).join(' ');
const ocAssertion: Assertion = {
expression: a.name || '',
operator,
value
};
if (a.enabled === false) {
ocAssertion.disabled = true;
}
if (a.description && typeof a.description === 'string' && a.description.trim().length) {
ocAssertion.description = a.description;
}
return ocAssertion;
});
};

View File

@@ -0,0 +1,470 @@
import type {
Auth,
AuthBasic,
AuthBearer,
AuthDigest,
AuthNTLM,
AuthAwsV4,
AuthApiKey,
AuthWsse,
AuthOAuth2,
BrunoAuth,
BrunoOAuth2
} from '../types';
const fromOpenCollectionOAuth2 = (auth: AuthOAuth2): BrunoAuth => {
const getTokenPlacement = (tokenConfig: AuthOAuth2['tokenConfig']): string => {
if (tokenConfig?.placement && 'query' in tokenConfig.placement) {
return 'query';
}
return 'header';
};
const getTokenHeaderPrefix = (tokenConfig: AuthOAuth2['tokenConfig']): string => {
if (tokenConfig?.placement && 'header' in tokenConfig.placement) {
return tokenConfig.placement.header;
}
return 'Bearer';
};
const getTokenQueryKey = (tokenConfig: AuthOAuth2['tokenConfig']): string => {
if (tokenConfig?.placement && 'query' in tokenConfig.placement) {
return tokenConfig.placement.query;
}
return 'access_token';
};
const getCredentialsPlacement = (credentials: AuthOAuth2['credentials']): 'body' | 'basic_auth_header' => {
if (credentials && 'placement' in credentials && credentials.placement === 'basic_auth_header') {
return 'basic_auth_header';
}
return 'body';
};
const buildOAuth2Config = (base: Partial<BrunoOAuth2>): BrunoAuth => {
const brunoAuth: BrunoAuth = {
mode: 'oauth2',
awsv4: null,
basic: null,
bearer: null,
digest: null,
ntlm: null,
oauth2: {
grantType: base.grantType || 'client_credentials',
username: base.username || null,
password: base.password || null,
callbackUrl: base.callbackUrl || null,
authorizationUrl: base.authorizationUrl || null,
accessTokenUrl: base.accessTokenUrl || null,
clientId: base.clientId || null,
clientSecret: base.clientSecret || null,
scope: base.scope || null,
state: base.state || null,
pkce: base.pkce || null,
credentialsPlacement: base.credentialsPlacement || null,
credentialsId: base.credentialsId || null,
tokenPlacement: base.tokenPlacement || null,
tokenHeaderPrefix: base.tokenHeaderPrefix || null,
tokenQueryKey: base.tokenQueryKey || null,
refreshTokenUrl: base.refreshTokenUrl || null,
autoRefreshToken: base.autoRefreshToken || null,
autoFetchToken: base.autoFetchToken || null,
additionalParameters: null
},
wsse: null,
apikey: null
};
return brunoAuth;
};
switch (auth.flow) {
case 'client_credentials':
return buildOAuth2Config({
grantType: 'client_credentials',
accessTokenUrl: auth.accessTokenUrl || null,
refreshTokenUrl: auth.refreshTokenUrl || null,
clientId: auth.credentials?.clientId || null,
clientSecret: auth.credentials?.clientSecret || null,
scope: auth.scope || null,
credentialsPlacement: getCredentialsPlacement(auth.credentials),
credentialsId: auth.tokenConfig?.id || 'credentials',
tokenPlacement: getTokenPlacement(auth.tokenConfig),
tokenHeaderPrefix: getTokenHeaderPrefix(auth.tokenConfig),
tokenQueryKey: getTokenQueryKey(auth.tokenConfig),
autoFetchToken: auth.settings?.autoFetchToken !== false,
autoRefreshToken: auth.settings?.autoRefreshToken !== false
});
case 'resource_owner_password_credentials':
return buildOAuth2Config({
grantType: 'password',
accessTokenUrl: auth.accessTokenUrl || null,
refreshTokenUrl: auth.refreshTokenUrl || null,
clientId: auth.credentials?.clientId || null,
clientSecret: auth.credentials?.clientSecret || null,
username: auth.resourceOwner?.username || null,
password: auth.resourceOwner?.password || null,
scope: auth.scope || null,
credentialsPlacement: getCredentialsPlacement(auth.credentials),
credentialsId: auth.tokenConfig?.id || 'credentials',
tokenPlacement: getTokenPlacement(auth.tokenConfig),
tokenHeaderPrefix: getTokenHeaderPrefix(auth.tokenConfig),
tokenQueryKey: getTokenQueryKey(auth.tokenConfig),
autoFetchToken: auth.settings?.autoFetchToken !== false,
autoRefreshToken: auth.settings?.autoRefreshToken !== false
});
case 'authorization_code':
return buildOAuth2Config({
grantType: 'authorization_code',
authorizationUrl: auth.authorizationUrl || null,
accessTokenUrl: auth.accessTokenUrl || null,
refreshTokenUrl: auth.refreshTokenUrl || null,
callbackUrl: auth.callbackUrl || null,
clientId: auth.credentials?.clientId || null,
clientSecret: auth.credentials?.clientSecret || null,
scope: auth.scope || null,
pkce: auth.pkce?.enabled || null,
credentialsPlacement: getCredentialsPlacement(auth.credentials),
credentialsId: auth.tokenConfig?.id || 'credentials',
tokenPlacement: getTokenPlacement(auth.tokenConfig),
tokenHeaderPrefix: getTokenHeaderPrefix(auth.tokenConfig),
tokenQueryKey: getTokenQueryKey(auth.tokenConfig),
autoFetchToken: auth.settings?.autoFetchToken !== false,
autoRefreshToken: auth.settings?.autoRefreshToken !== false
});
case 'implicit':
return buildOAuth2Config({
grantType: 'implicit',
authorizationUrl: auth.authorizationUrl || null,
callbackUrl: auth.callbackUrl || null,
clientId: auth.credentials?.clientId || null,
scope: auth.scope || null,
state: auth.state || null,
credentialsId: auth.tokenConfig?.id || 'credentials',
tokenPlacement: getTokenPlacement(auth.tokenConfig),
tokenHeaderPrefix: getTokenHeaderPrefix(auth.tokenConfig),
tokenQueryKey: getTokenQueryKey(auth.tokenConfig),
autoFetchToken: auth.settings?.autoFetchToken !== false
});
default:
return {
mode: 'none',
awsv4: null,
basic: null,
bearer: null,
digest: null,
ntlm: null,
oauth2: null,
wsse: null,
apikey: null
};
}
};
export const fromOpenCollectionAuth = (auth: Auth | undefined): BrunoAuth => {
const defaultAuth: BrunoAuth = {
mode: 'none',
awsv4: null,
basic: null,
bearer: null,
digest: null,
ntlm: null,
oauth2: null,
wsse: null,
apikey: null
};
if (!auth) {
return defaultAuth;
}
if (auth === 'inherit') {
return { ...defaultAuth, mode: 'inherit' };
}
switch (auth.type) {
case 'basic': {
const basicAuth = auth as AuthBasic;
return {
...defaultAuth,
mode: 'basic',
basic: {
username: basicAuth.username || null,
password: basicAuth.password || null
}
};
}
case 'bearer': {
const bearerAuth = auth as AuthBearer;
return {
...defaultAuth,
mode: 'bearer',
bearer: {
token: bearerAuth.token || null
}
};
}
case 'digest': {
const digestAuth = auth as AuthDigest;
return {
...defaultAuth,
mode: 'digest',
digest: {
username: digestAuth.username || null,
password: digestAuth.password || null
}
};
}
case 'ntlm': {
const ntlmAuth = auth as AuthNTLM;
return {
...defaultAuth,
mode: 'ntlm',
ntlm: {
username: ntlmAuth.username || null,
password: ntlmAuth.password || null,
domain: ntlmAuth.domain || null
}
};
}
case 'awsv4': {
const awsAuth = auth as AuthAwsV4;
return {
...defaultAuth,
mode: 'awsv4',
awsv4: {
accessKeyId: awsAuth.accessKeyId || null,
secretAccessKey: awsAuth.secretAccessKey || null,
sessionToken: awsAuth.sessionToken || null,
service: awsAuth.service || null,
region: awsAuth.region || null,
profileName: awsAuth.profileName || null
}
};
}
case 'apikey': {
const apiKeyAuth = auth as AuthApiKey;
return {
...defaultAuth,
mode: 'apikey',
apikey: {
key: apiKeyAuth.key || null,
value: apiKeyAuth.value || null,
placement: apiKeyAuth.placement === 'query' ? 'queryparams' : (apiKeyAuth.placement === 'header' ? 'header' : null)
}
};
}
case 'wsse': {
const wsseAuth = auth as AuthWsse;
return {
...defaultAuth,
mode: 'wsse',
wsse: {
username: wsseAuth.username || null,
password: wsseAuth.password || null
}
};
}
case 'oauth2':
return fromOpenCollectionOAuth2(auth as AuthOAuth2);
default:
return defaultAuth;
}
};
const toOpenCollectionOAuth2 = (oauth2: BrunoOAuth2 | null | undefined): AuthOAuth2 | undefined => {
if (!oauth2) {
return undefined;
}
const base = { type: 'oauth2' as const };
switch (oauth2.grantType) {
case 'client_credentials':
return {
...base,
flow: 'client_credentials',
accessTokenUrl: oauth2.accessTokenUrl || '',
refreshTokenUrl: oauth2.refreshTokenUrl || '',
credentials: {
clientId: oauth2.clientId || '',
clientSecret: oauth2.clientSecret || '',
placement: oauth2.credentialsPlacement === 'basic_auth_header' ? 'basic_auth_header' : 'body'
},
scope: oauth2.scope || '',
tokenConfig: {
id: oauth2.credentialsId || 'credentials',
placement: oauth2.tokenPlacement === 'query'
? { query: oauth2.tokenQueryKey || 'access_token' }
: { header: oauth2.tokenHeaderPrefix || 'Bearer' }
},
settings: {
autoFetchToken: oauth2.autoFetchToken !== false,
autoRefreshToken: oauth2.autoRefreshToken !== false
}
};
case 'password':
return {
...base,
flow: 'resource_owner_password_credentials',
accessTokenUrl: oauth2.accessTokenUrl || '',
refreshTokenUrl: oauth2.refreshTokenUrl || '',
credentials: {
clientId: oauth2.clientId || '',
clientSecret: oauth2.clientSecret || '',
placement: oauth2.credentialsPlacement === 'basic_auth_header' ? 'basic_auth_header' : 'body'
},
resourceOwner: {
username: oauth2.username || '',
password: oauth2.password || ''
},
scope: oauth2.scope || '',
tokenConfig: {
id: oauth2.credentialsId || 'credentials',
placement: oauth2.tokenPlacement === 'query'
? { query: oauth2.tokenQueryKey || 'access_token' }
: { header: oauth2.tokenHeaderPrefix || 'Bearer' }
},
settings: {
autoFetchToken: oauth2.autoFetchToken !== false,
autoRefreshToken: oauth2.autoRefreshToken !== false
}
};
case 'authorization_code':
return {
...base,
flow: 'authorization_code',
authorizationUrl: oauth2.authorizationUrl || '',
accessTokenUrl: oauth2.accessTokenUrl || '',
refreshTokenUrl: oauth2.refreshTokenUrl || '',
callbackUrl: oauth2.callbackUrl || '',
credentials: {
clientId: oauth2.clientId || '',
clientSecret: oauth2.clientSecret || '',
placement: oauth2.credentialsPlacement === 'basic_auth_header' ? 'basic_auth_header' : 'body'
},
scope: oauth2.scope || '',
pkce: oauth2.pkce ? { enabled: true, method: 'S256' } : undefined,
tokenConfig: {
id: oauth2.credentialsId || 'credentials',
placement: oauth2.tokenPlacement === 'query'
? { query: oauth2.tokenQueryKey || 'access_token' }
: { header: oauth2.tokenHeaderPrefix || 'Bearer' }
},
settings: {
autoFetchToken: oauth2.autoFetchToken !== false,
autoRefreshToken: oauth2.autoRefreshToken !== false
}
};
case 'implicit':
return {
...base,
flow: 'implicit',
authorizationUrl: oauth2.authorizationUrl || '',
callbackUrl: oauth2.callbackUrl || '',
credentials: {
clientId: oauth2.clientId || ''
},
scope: oauth2.scope || '',
state: oauth2.state || '',
tokenConfig: {
id: oauth2.credentialsId || 'credentials',
placement: oauth2.tokenPlacement === 'query'
? { query: oauth2.tokenQueryKey || 'access_token' }
: { header: oauth2.tokenHeaderPrefix || 'Bearer' }
},
settings: {
autoFetchToken: oauth2.autoFetchToken !== false
}
};
default:
return undefined;
}
};
export const toOpenCollectionAuth = (auth: BrunoAuth | null | undefined): Auth | undefined => {
if (!auth || auth.mode === 'none') {
return undefined;
}
if (auth.mode === 'inherit') {
return 'inherit';
}
switch (auth.mode) {
case 'basic':
return {
type: 'basic',
username: auth.basic?.username || '',
password: auth.basic?.password || ''
};
case 'bearer':
return {
type: 'bearer',
token: auth.bearer?.token || ''
};
case 'digest':
return {
type: 'digest',
username: auth.digest?.username || '',
password: auth.digest?.password || ''
};
case 'ntlm':
return {
type: 'ntlm',
username: auth.ntlm?.username || '',
password: auth.ntlm?.password || '',
domain: auth.ntlm?.domain || ''
};
case 'awsv4':
return {
type: 'awsv4',
accessKeyId: auth.awsv4?.accessKeyId || '',
secretAccessKey: auth.awsv4?.secretAccessKey || '',
sessionToken: auth.awsv4?.sessionToken || '',
service: auth.awsv4?.service || '',
region: auth.awsv4?.region || '',
profileName: auth.awsv4?.profileName || ''
};
case 'apikey':
return {
type: 'apikey',
key: auth.apikey?.key || '',
value: auth.apikey?.value || '',
placement: auth.apikey?.placement === 'queryparams' ? 'query' : 'header'
};
case 'wsse':
return {
type: 'wsse',
username: auth.wsse?.username || '',
password: auth.wsse?.password || ''
};
case 'oauth2':
return toOpenCollectionOAuth2(auth.oauth2);
default:
return undefined;
}
};

View File

@@ -0,0 +1,227 @@
import { uuid } from '../../common/index.js';
import type {
HttpRequestBody,
RawBody,
FormUrlEncodedBody,
FormUrlEncodedEntry,
MultipartFormBody,
MultipartFormEntry,
FileBody,
FileBodyVariant,
GraphQLBody,
BrunoHttpRequestBody,
BrunoKeyValue,
BrunoMultipartFormEntry,
BrunoFileEntry,
BrunoGraphqlBody
} from '../types';
export const fromOpenCollectionBody = (body: HttpRequestBody | GraphQLBody | undefined, requestType: string = 'http'): BrunoHttpRequestBody => {
const defaultBody: BrunoHttpRequestBody = {
mode: 'none',
json: null,
text: null,
xml: null,
sparql: null,
formUrlEncoded: [],
multipartForm: [],
graphql: null,
file: []
};
if (!body) {
return defaultBody;
}
if (requestType === 'graphql') {
const gqlBody = body as GraphQLBody;
return {
...defaultBody,
mode: 'graphql',
graphql: {
query: gqlBody.query || '',
variables: gqlBody.variables || ''
}
};
}
const httpBody = body as HttpRequestBody;
if ('type' in httpBody) {
switch (httpBody.type) {
case 'json': {
const rawBody = httpBody as RawBody;
return {
...defaultBody,
mode: 'json',
json: rawBody.data || ''
};
}
case 'text': {
const rawBody = httpBody as RawBody;
return {
...defaultBody,
mode: 'text',
text: rawBody.data || ''
};
}
case 'xml': {
const rawBody = httpBody as RawBody;
return {
...defaultBody,
mode: 'xml',
xml: rawBody.data || ''
};
}
case 'sparql': {
const rawBody = httpBody as RawBody;
return {
...defaultBody,
mode: 'sparql',
sparql: rawBody.data || ''
};
}
case 'form-urlencoded': {
const formBody = httpBody as FormUrlEncodedBody;
return {
...defaultBody,
mode: 'formUrlEncoded',
formUrlEncoded: (formBody.data || []).map((field): BrunoKeyValue => ({
uid: uuid(),
name: field.name || '',
value: field.value || '',
description: typeof field.description === 'string' ? field.description : field.description?.content || null,
enabled: field.disabled !== true
}))
};
}
case 'multipart-form': {
const multipartBody = httpBody as MultipartFormBody;
return {
...defaultBody,
mode: 'multipartForm',
multipartForm: (multipartBody.data || []).map((field): BrunoMultipartFormEntry => ({
uid: uuid(),
type: field.type || 'text',
name: field.name || '',
value: Array.isArray(field.value) ? field.value : (field.value || ''),
description: typeof field.description === 'string' ? field.description : field.description?.content || null,
contentType: null,
enabled: field.disabled !== true
}))
};
}
case 'file': {
const fileBody = httpBody as FileBody;
return {
...defaultBody,
mode: 'file',
file: (fileBody.data || []).map((file): BrunoFileEntry => ({
uid: uuid(),
filePath: file.filePath || '',
contentType: file.contentType || '',
selected: file.selected !== false
}))
};
}
}
}
return defaultBody;
};
export const toOpenCollectionBody = (body: BrunoHttpRequestBody | null | undefined): HttpRequestBody | undefined => {
if (!body || body.mode === 'none') {
return undefined;
}
switch (body.mode) {
case 'json':
return { type: 'json', data: body.json || '' };
case 'text':
return { type: 'text', data: body.text || '' };
case 'xml':
return { type: 'xml', data: body.xml || '' };
case 'sparql':
return { type: 'sparql', data: body.sparql || '' };
case 'formUrlEncoded': {
const formData: FormUrlEncodedEntry[] = (body.formUrlEncoded || []).map((field): FormUrlEncodedEntry => {
const entry: FormUrlEncodedEntry = {
name: field.name || '',
value: field.value || ''
};
if (field.description && typeof field.description === 'string' && field.description.trim().length) {
entry.description = field.description;
}
if (field.enabled === false) {
entry.disabled = true;
}
return entry;
});
return { type: 'form-urlencoded', data: formData };
}
case 'multipartForm': {
const multipartData: MultipartFormEntry[] = (body.multipartForm || []).map((field): MultipartFormEntry => {
const entry: MultipartFormEntry = {
name: field.name || '',
type: field.type || 'text',
value: field.value || ''
};
if (field.description && typeof field.description === 'string' && field.description.trim().length) {
entry.description = field.description;
}
if (field.enabled === false) {
entry.disabled = true;
}
return entry;
});
return { type: 'multipart-form', data: multipartData };
}
case 'file': {
const fileData: FileBodyVariant[] = (body.file || []).map((file): FileBodyVariant => ({
filePath: file.filePath || '',
contentType: file.contentType || '',
selected: file.selected !== false
}));
return { type: 'file', data: fileData };
}
case 'graphql':
return undefined;
default:
return undefined;
}
};
export const toOpenCollectionGraphqlBody = (body: BrunoHttpRequestBody | null | undefined): GraphQLBody | undefined => {
if (!body || body.mode !== 'graphql' || !body.graphql) {
return undefined;
}
return {
query: body.graphql.query || '',
variables: body.graphql.variables || ''
};
};

View File

@@ -0,0 +1,44 @@
import { uuid } from '../../common/index.js';
import type {
HttpRequestHeader,
BrunoKeyValue
} from '../types';
export const fromOpenCollectionHeaders = (headers: HttpRequestHeader[] | undefined): BrunoKeyValue[] => {
if (!headers?.length) {
return [];
}
return headers.map((header): BrunoKeyValue => ({
uid: uuid(),
name: header.name || '',
value: header.value || '',
description: typeof header.description === 'string' ? header.description : header.description?.content || null,
enabled: header.disabled !== true
}));
};
export const toOpenCollectionHeaders = (headers: BrunoKeyValue[] | null | undefined): HttpRequestHeader[] | undefined => {
if (!headers?.length) {
return undefined;
}
const ocHeaders = headers.map((header): HttpRequestHeader => {
const httpHeader: HttpRequestHeader = {
name: header.name || '',
value: header.value || ''
};
if (header.description && typeof header.description === 'string' && header.description.trim().length) {
httpHeader.description = header.description;
}
if (header.enabled === false) {
httpHeader.disabled = true;
}
return httpHeader;
});
return ocHeaders.length ? ocHeaders : undefined;
};

View File

@@ -0,0 +1,8 @@
export { fromOpenCollectionAuth, toOpenCollectionAuth } from './auth';
export { fromOpenCollectionHeaders, toOpenCollectionHeaders } from './headers';
export { fromOpenCollectionParams, toOpenCollectionParams } from './params';
export { fromOpenCollectionBody, toOpenCollectionBody, toOpenCollectionGraphqlBody } from './body';
export { fromOpenCollectionVariables, toOpenCollectionVariables } from './variables';
export { fromOpenCollectionActions, toOpenCollectionActions } from './actions';
export { fromOpenCollectionScripts, toOpenCollectionScripts } from './scripts';
export { fromOpenCollectionAssertions, toOpenCollectionAssertions } from './assertions';

View File

@@ -0,0 +1,47 @@
import { uuid } from '../../common/index.js';
import type {
HttpRequestParam,
BrunoHttpRequestParam,
BrunoHttpRequestParamType
} from '../types';
export const fromOpenCollectionParams = (params: HttpRequestParam[] | undefined): BrunoHttpRequestParam[] => {
if (!params?.length) {
return [];
}
return params.map((param): BrunoHttpRequestParam => ({
uid: uuid(),
name: param.name || '',
value: param.value || '',
description: typeof param.description === 'string' ? param.description : param.description?.content || null,
type: (param.type || 'query') as BrunoHttpRequestParamType,
enabled: param.disabled !== true
}));
};
export const toOpenCollectionParams = (params: BrunoHttpRequestParam[] | null | undefined): HttpRequestParam[] | undefined => {
if (!params?.length) {
return undefined;
}
const ocParams = params.map((param): HttpRequestParam => {
const httpParam: HttpRequestParam = {
name: param.name || '',
value: param.value || '',
type: param.type || 'query'
};
if (param.description && typeof param.description === 'string' && param.description.trim().length) {
httpParam.description = param.description;
}
if (param.enabled === false) {
httpParam.disabled = true;
}
return httpParam;
});
return ocParams.length ? ocParams : undefined;
};

View File

@@ -0,0 +1,64 @@
import type { Scripts, Script } from '@opencollection/types/common/scripts';
import type { FolderRequest as BrunoFolderRequest } from '@usebruno/schema-types/collection/folder';
import type { HttpRequest as BrunoHttpRequest } from '@usebruno/schema-types/requests/http';
import type { WebSocketRequest as BrunoWebSocketRequest } from '@usebruno/schema-types/requests/websocket';
import type { GrpcRequest as BrunoGrpcRequest } from '@usebruno/schema-types/requests/grpc';
export const toOpenCollectionScripts = (request: BrunoFolderRequest | BrunoHttpRequest | BrunoWebSocketRequest | BrunoGrpcRequest | null | undefined): Scripts | undefined => {
const ocScripts: Scripts = [];
if (request?.script?.req?.trim().length) {
ocScripts.push({
type: 'before-request',
code: request.script.req.trim()
});
}
if (request?.script?.res?.trim().length) {
ocScripts.push({
type: 'after-response',
code: request.script.res.trim()
});
}
if (request?.tests?.trim().length) {
ocScripts.push({
type: 'tests',
code: request.tests.trim()
});
}
return ocScripts.length > 0 ? ocScripts : undefined;
};
export const fromOpenCollectionScripts = (scripts: Scripts | null | undefined): {
script?: { req?: string | null; res?: string | null };
tests?: string | null;
} | undefined => {
if (!scripts || !Array.isArray(scripts) || scripts.length === 0) {
return undefined;
}
const brunoScripts: {
script?: { req?: string | null; res?: string | null };
tests?: string | null;
} = {};
for (const script of scripts) {
if (script.type === 'before-request' && script.code) {
if (!brunoScripts.script) {
brunoScripts.script = {};
}
brunoScripts.script.req = script.code;
}
if (script.type === 'after-response' && script.code) {
if (!brunoScripts.script) {
brunoScripts.script = {};
}
brunoScripts.script.res = script.code;
}
if (script.type === 'tests' && script.code) {
brunoScripts.tests = script.code;
}
}
return Object.keys(brunoScripts).length > 0 ? brunoScripts : undefined;
};

View File

@@ -0,0 +1,75 @@
import { uuid } from '../../common/index.js';
import type {
Variable,
BrunoVariable,
BrunoVariables
} from '../types';
interface BrunoVars {
req: BrunoVariables;
res: BrunoVariables;
}
export const fromOpenCollectionVariables = (variables: Variable[] | undefined): BrunoVars => {
if (!variables?.length) {
return { req: [], res: [] };
}
const reqVars: BrunoVariable[] = [];
variables.forEach((v: Variable) => {
let value = '';
if (typeof v.value === 'string') {
value = v.value;
} else if (v.value && typeof v.value === 'object' && 'data' in v.value) {
value = (v.value as { data: string }).data || '';
}
const variable: BrunoVariable = {
uid: uuid(),
name: v.name || '',
value,
enabled: v.disabled !== true,
local: false
};
if (v.description) {
variable.description = typeof v.description === 'string' ? v.description : (v.description as { content?: string })?.content || '';
}
reqVars.push(variable);
});
return { req: reqVars, res: [] };
};
export const toOpenCollectionVariables = (vars: BrunoVars | { req?: BrunoVariables; res?: BrunoVariables } | null | undefined): Variable[] | undefined => {
// Handle folder variables (has req/res structure) - only use req vars
const hasReqRes = vars && 'req' in vars;
const reqVars = hasReqRes ? vars.req : vars as BrunoVariables;
const reqVarsArray = Array.isArray(reqVars) ? reqVars : [];
if (!reqVarsArray.length) {
return undefined;
}
const ocVariables: Variable[] = reqVarsArray.map((v: BrunoVariable): Variable => {
const variable: Variable = {
name: v.name || '',
value: v.value || ''
};
if (v.description && typeof v.description === 'string' && v.description.trim().length) {
variable.description = v.description;
}
if (v.enabled === false) {
variable.disabled = true;
}
return variable;
});
return ocVariables.length > 0 ? ocVariables : undefined;
};

View File

@@ -0,0 +1,79 @@
import { uuid } from '../common/index.js';
import type {
Environment,
Variable,
BrunoEnvironment,
BrunoEnvironmentVariable
} from './types';
interface OCVariable extends Omit<Variable, 'value'> {
name: string;
value?: string | { data: string };
secret?: boolean;
disabled?: boolean;
}
export const fromOpenCollectionEnvironments = (environments: Environment[] | undefined): BrunoEnvironment[] => {
if (!environments?.length) {
return [];
}
return environments.map((env): BrunoEnvironment => ({
uid: uuid(),
name: env.name || 'Untitled Environment',
variables: (env.variables || []).map((v): BrunoEnvironmentVariable => {
const variable = v as OCVariable;
const isSecret = variable.secret === true;
let value = '';
if (!isSecret && variable.value !== undefined) {
if (typeof variable.value === 'string') {
value = variable.value;
} else if (variable.value && typeof variable.value === 'object' && 'data' in variable.value) {
value = variable.value.data;
}
}
return {
uid: uuid(),
name: variable.name || '',
value,
type: 'text',
enabled: variable.disabled !== true,
secret: isSecret
};
})
}));
};
export const toOpenCollectionEnvironments = (environments: BrunoEnvironment[] | undefined): Environment[] | undefined => {
if (!environments?.length) {
return undefined;
}
return environments.map((env): Environment => {
const ocEnv: Environment = {
name: env.name || 'Untitled Environment',
variables: (env.variables || []).map((v): OCVariable => {
const ocVar: OCVariable = {
name: v.name || '',
value: typeof v.value === 'string' ? v.value : String(v.value ?? '')
};
if (v.secret) {
ocVar.secret = true;
// Secret variables don't include the value in export
delete ocVar.value;
}
if (v.enabled === false) {
ocVar.disabled = true;
}
return ocVar;
}) as Variable[]
};
return ocEnv;
});
};

View File

@@ -0,0 +1,135 @@
import { uuid } from '../common/index.js';
import {
fromOpenCollectionHeaders,
toOpenCollectionHeaders,
fromOpenCollectionAuth,
toOpenCollectionAuth,
fromOpenCollectionScripts,
toOpenCollectionScripts,
fromOpenCollectionVariables,
toOpenCollectionVariables
} from './common';
import { fromOpenCollectionItems, toOpenCollectionItems } from './items';
import type {
Folder,
FolderInfo,
RequestDefaults,
Auth,
BrunoItem,
BrunoFolderRoot,
BrunoKeyValue
} from './types';
export const fromOpenCollectionFolder = (folder: Folder): BrunoItem => {
const info = folder.info || {};
const brunoFolder: BrunoItem = {
uid: uuid(),
type: 'folder',
name: info.name || 'Untitled Folder',
seq: info.seq || 1
};
if (folder.request || folder.docs) {
const root: BrunoFolderRoot = {};
if (folder.request) {
const scripts = fromOpenCollectionScripts(folder.request.scripts);
root.request = {
headers: fromOpenCollectionHeaders(folder.request.headers),
auth: fromOpenCollectionAuth(folder.request.auth as Auth),
script: scripts?.script,
vars: fromOpenCollectionVariables(folder.request.variables),
tests: scripts?.tests
};
}
if (folder.docs) {
if (typeof folder.docs === 'string') {
root.docs = folder.docs;
} else if (folder.docs && typeof folder.docs === 'object' && 'content' in folder.docs) {
root.docs = folder.docs.content || '';
}
}
root.meta = {
name: info.name || 'Untitled Folder',
seq: info.seq || 1
};
brunoFolder.root = root;
}
if (info.tags?.length) {
brunoFolder.tags = info.tags;
}
if (folder.items?.length) {
brunoFolder.items = fromOpenCollectionItems(folder.items, fromOpenCollectionFolder as (f: unknown) => BrunoItem);
}
return brunoFolder;
};
export const toOpenCollectionFolder = (folder: BrunoItem): Folder => {
const info: FolderInfo = {
name: folder.name || 'Untitled Folder',
type: 'folder'
};
if (folder.seq) {
info.seq = folder.seq;
}
if (folder.tags?.length) {
info.tags = folder.tags;
}
const ocFolder: Folder = {
info
};
if (folder.root) {
const folderRequest = folder.root.request || {};
const headers = toOpenCollectionHeaders(folderRequest.headers as BrunoKeyValue[]);
const auth = toOpenCollectionAuth(folderRequest.auth);
const scripts = toOpenCollectionScripts(folderRequest as { script?: { req: string | null; res: string | null } | null; tests?: string | null });
const variables = toOpenCollectionVariables(folderRequest.vars);
if (headers || auth || scripts || variables) {
const request: RequestDefaults = {};
if (headers) {
request.headers = headers;
}
if (auth) {
request.auth = auth;
}
if (scripts) {
request.scripts = scripts;
}
if (variables) {
request.variables = variables;
}
ocFolder.request = request;
}
if (folder.root.docs) {
ocFolder.docs = {
content: folder.root.docs,
type: 'text/markdown'
};
}
}
if (folder.items?.length) {
ocFolder.items = toOpenCollectionItems(folder.items, toOpenCollectionFolder as (f: BrunoItem) => unknown) as Folder['items'];
}
return ocFolder;
};

View File

@@ -0,0 +1,37 @@
export { openCollectionToBruno } from './opencollection-to-bruno';
export { brunoToOpenCollection } from './bruno-to-opencollection';
export { fromOpenCollectionFolder, toOpenCollectionFolder } from './folder';
export { fromOpenCollectionEnvironments, toOpenCollectionEnvironments } from './environment';
export {
fromOpenCollectionItem,
toOpenCollectionItem,
fromOpenCollectionItems,
toOpenCollectionItems,
fromOpenCollectionHttpItem,
toOpenCollectionHttpItem,
fromOpenCollectionGraphqlItem,
toOpenCollectionGraphqlItem,
fromOpenCollectionGrpcItem,
toOpenCollectionGrpcItem,
fromOpenCollectionWebsocketItem,
toOpenCollectionWebsocketItem
} from './items';
export {
fromOpenCollectionAuth,
toOpenCollectionAuth,
fromOpenCollectionHeaders,
toOpenCollectionHeaders,
fromOpenCollectionParams,
toOpenCollectionParams,
fromOpenCollectionBody,
toOpenCollectionBody,
toOpenCollectionGraphqlBody,
fromOpenCollectionVariables,
toOpenCollectionVariables,
fromOpenCollectionScripts,
toOpenCollectionScripts,
fromOpenCollectionAssertions,
toOpenCollectionAssertions
} from './common';

View File

@@ -0,0 +1,192 @@
import { uuid } from '../../common/index.js';
import {
fromOpenCollectionHeaders,
toOpenCollectionHeaders,
fromOpenCollectionParams,
toOpenCollectionParams,
fromOpenCollectionBody,
toOpenCollectionGraphqlBody,
fromOpenCollectionAuth,
toOpenCollectionAuth,
fromOpenCollectionScripts,
toOpenCollectionScripts,
fromOpenCollectionVariables,
toOpenCollectionVariables,
fromOpenCollectionActions,
toOpenCollectionActions,
fromOpenCollectionAssertions,
toOpenCollectionAssertions
} from '../common';
import type {
GraphQLRequest,
GraphQLRequestInfo,
GraphQLRequestDetails,
GraphQLRequestRuntime,
GraphQLRequestSettings,
GraphQLBody,
GraphQLBodyVariant,
Auth,
BrunoItem,
BrunoKeyValue,
BrunoHttpRequestParam
} from '../types';
const getGraphqlBody = (body: GraphQLBody | GraphQLBodyVariant[] | undefined): GraphQLBody | undefined => {
if (!body) return undefined;
if (Array.isArray(body)) {
const selected = body.find((v) => v.selected);
return selected?.body || body[0]?.body;
}
return body;
};
export const fromOpenCollectionGraphqlItem = (item: GraphQLRequest): BrunoItem => {
const info = item.info || {};
const graphql = item.graphql || {};
const runtime = item.runtime || {};
const scripts = fromOpenCollectionScripts(runtime.scripts);
const graphqlBody = getGraphqlBody(graphql.body);
// variables (pre-request from variables, post-response from actions)
const variables = fromOpenCollectionVariables(runtime.variables);
const postResponseVars = fromOpenCollectionActions(runtime.actions);
const brunoItem: BrunoItem = {
uid: uuid(),
type: 'graphql-request',
name: info.name || 'Untitled Request',
seq: info.seq || 1,
request: {
url: graphql.url || '',
method: graphql.method || 'POST',
headers: fromOpenCollectionHeaders(graphql.headers),
params: fromOpenCollectionParams(graphql.params),
body: fromOpenCollectionBody(graphqlBody, 'graphql'),
auth: fromOpenCollectionAuth(runtime.auth as Auth),
script: scripts?.script,
vars: {
req: variables.req,
res: postResponseVars
},
assertions: fromOpenCollectionAssertions(runtime.assertions),
tests: scripts?.tests,
docs: item.docs || ''
}
};
const settings = item.settings;
if (settings) {
brunoItem.settings = {};
if (settings.encodeUrl !== undefined) {
(brunoItem.settings as Record<string, unknown>).encodeUrl = settings.encodeUrl;
}
if (settings.timeout !== undefined) {
(brunoItem.settings as Record<string, unknown>).timeout = settings.timeout;
}
if (settings.followRedirects !== undefined) {
(brunoItem.settings as Record<string, unknown>).followRedirects = settings.followRedirects;
}
if (settings.maxRedirects !== undefined) {
(brunoItem.settings as Record<string, unknown>).maxRedirects = settings.maxRedirects;
}
}
if (info.tags?.length) {
brunoItem.tags = info.tags;
}
return brunoItem;
};
export const toOpenCollectionGraphqlItem = (item: BrunoItem): GraphQLRequest => {
const request = (item.request || {}) as Record<string, unknown>;
const brunoSettings = (item.settings || {}) as Record<string, unknown>;
const info: GraphQLRequestInfo = {
name: item.name || 'Untitled Request',
type: 'graphql'
};
if (item.seq) {
info.seq = item.seq;
}
if (item.tags?.length) {
info.tags = item.tags;
}
const graphql: GraphQLRequestDetails = {
url: request.url as string || '',
method: request.method as string || 'POST'
};
const headers = toOpenCollectionHeaders(request.headers as BrunoKeyValue[]);
if (headers) {
graphql.headers = headers;
}
const params = toOpenCollectionParams(request.params as BrunoHttpRequestParam[]);
if (params) {
graphql.params = params;
}
const body = toOpenCollectionGraphqlBody(request.body as Parameters<typeof toOpenCollectionGraphqlBody>[0]);
if (body) {
graphql.body = body;
}
const ocRequest: GraphQLRequest = {
info,
graphql
};
const auth = toOpenCollectionAuth(request.auth as Parameters<typeof toOpenCollectionAuth>[0]);
const scripts = toOpenCollectionScripts(request as Parameters<typeof toOpenCollectionScripts>[0]);
const variables = toOpenCollectionVariables(request.vars as Parameters<typeof toOpenCollectionVariables>[0]);
const assertions = toOpenCollectionAssertions(request.assertions as BrunoKeyValue[]);
// actions (from post-response variables)
const vars = request.vars as { req?: unknown[]; res?: unknown[] } | undefined;
const actions = toOpenCollectionActions(vars?.res as Parameters<typeof toOpenCollectionActions>[0]);
if (auth || scripts || variables || assertions || actions) {
const runtime: GraphQLRequestRuntime = {};
if (auth) {
runtime.auth = auth;
}
if (scripts) {
runtime.scripts = scripts;
}
if (variables) {
runtime.variables = variables;
}
if (assertions) {
runtime.assertions = assertions;
}
if (actions) {
runtime.actions = actions;
}
ocRequest.runtime = runtime;
}
const settings: GraphQLRequestSettings = {
encodeUrl: typeof brunoSettings.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true,
timeout: typeof brunoSettings.timeout === 'number' ? brunoSettings.timeout : 0,
followRedirects: typeof brunoSettings.followRedirects === 'boolean' ? brunoSettings.followRedirects : true,
maxRedirects: typeof brunoSettings.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5
};
ocRequest.settings = settings;
if (request.docs) {
ocRequest.docs = request.docs as string;
}
return ocRequest;
};

View File

@@ -0,0 +1,214 @@
import { uuid } from '../../common/index.js';
import {
fromOpenCollectionAuth,
toOpenCollectionAuth,
fromOpenCollectionScripts,
toOpenCollectionScripts,
fromOpenCollectionVariables,
toOpenCollectionVariables,
fromOpenCollectionActions,
toOpenCollectionActions,
fromOpenCollectionAssertions,
toOpenCollectionAssertions
} from '../common';
import type {
GrpcRequest,
GrpcRequestInfo,
GrpcRequestDetails,
GrpcRequestRuntime,
GrpcMetadata,
GrpcMessageVariant,
GrpcMessagePayload,
Auth,
BrunoItem,
BrunoGrpcMessage,
BrunoKeyValue
} from '../types';
const fromGrpcMetadata = (metadata: GrpcMetadata[] | undefined): BrunoKeyValue[] => {
if (!metadata?.length) {
return [];
}
return metadata.map((m): BrunoKeyValue => ({
uid: uuid(),
name: m.name || '',
value: m.value || '',
description: typeof m.description === 'string' ? m.description : (m.description as { content?: string } | undefined)?.content || null,
enabled: m.disabled !== true
}));
};
export const fromOpenCollectionGrpcItem = (item: GrpcRequest): BrunoItem => {
const info = item.info || {};
const grpc = item.grpc || {};
const runtime = item.runtime || {};
const grpcMessages: BrunoGrpcMessage[] = [];
if (grpc.message) {
if (typeof grpc.message === 'string') {
grpcMessages.push({ name: 'message 1', content: grpc.message });
} else if (Array.isArray(grpc.message)) {
grpc.message.forEach((msg, index) => {
grpcMessages.push({
name: msg.title || `message ${index + 1}`,
content: typeof msg.message === 'string' ? msg.message : ''
});
});
}
}
const scripts = fromOpenCollectionScripts(runtime.scripts);
// variables (pre-request from variables, post-response from actions)
const variables = fromOpenCollectionVariables(runtime.variables);
const postResponseVars = fromOpenCollectionActions((runtime as { actions?: Parameters<typeof fromOpenCollectionActions>[0] }).actions);
const brunoItem: BrunoItem = {
uid: uuid(),
type: 'grpc-request',
name: info.name || 'Untitled Request',
seq: info.seq || 1,
request: {
url: grpc.url || '',
method: grpc.method || '',
headers: fromGrpcMetadata(grpc.metadata),
body: {
mode: 'grpc',
grpc: grpcMessages
},
auth: fromOpenCollectionAuth(runtime.auth as Auth),
script: scripts?.script,
vars: {
req: variables.req,
res: postResponseVars
},
assertions: fromOpenCollectionAssertions(runtime.assertions),
tests: scripts?.tests,
docs: ''
}
};
// Add grpc-specific properties
if (grpc.methodType) {
(brunoItem.request as unknown as Record<string, unknown>).methodType = grpc.methodType;
}
if (grpc.protoFilePath) {
(brunoItem.request as unknown as Record<string, unknown>).protoPath = grpc.protoFilePath;
}
if (info.tags?.length) {
brunoItem.tags = info.tags;
}
return brunoItem;
};
export const toOpenCollectionGrpcItem = (item: BrunoItem): GrpcRequest => {
const request = (item.request || {}) as Record<string, unknown>;
const info: GrpcRequestInfo = {
name: item.name || 'Untitled Request',
type: 'grpc'
};
if (item.seq) {
info.seq = item.seq;
}
if (item.tags?.length) {
info.tags = item.tags;
}
const grpc: GrpcRequestDetails = {
url: request.url as string || '',
method: request.method as string || ''
};
if (request.methodType) {
grpc.methodType = request.methodType as GrpcRequestDetails['methodType'];
}
if (request.protoPath) {
grpc.protoFilePath = request.protoPath as string;
}
const headers = request.headers as BrunoKeyValue[] | undefined;
if (headers?.length) {
grpc.metadata = headers.map((h): GrpcMetadata => {
const metadata: GrpcMetadata = {
name: h.name || '',
value: h.value || ''
};
if (h.description && typeof h.description === 'string' && h.description.trim().length) {
metadata.description = h.description;
}
if (h.enabled === false) {
metadata.disabled = true;
}
return metadata;
});
}
const body = request.body as { grpc?: BrunoGrpcMessage[] } | undefined;
if (body?.grpc?.length) {
const messages = body.grpc;
if (messages.length === 1) {
grpc.message = messages[0].content || '';
} else {
grpc.message = messages.map((msg): GrpcMessageVariant => ({
title: msg.name || 'Untitled',
message: msg.content || ''
}));
}
}
const ocRequest: GrpcRequest = {
info,
grpc
};
const auth = toOpenCollectionAuth(request.auth as Parameters<typeof toOpenCollectionAuth>[0]);
const scripts = toOpenCollectionScripts(request as Parameters<typeof toOpenCollectionScripts>[0]);
const variables = toOpenCollectionVariables(request.vars as Parameters<typeof toOpenCollectionVariables>[0]);
const assertions = toOpenCollectionAssertions(request.assertions as BrunoKeyValue[]);
// actions (from post-response variables)
const vars = request.vars as { req?: unknown[]; res?: unknown[] } | undefined;
const actions = toOpenCollectionActions(vars?.res as Parameters<typeof toOpenCollectionActions>[0]);
if (auth || scripts || variables || assertions || actions) {
const runtime: GrpcRequestRuntime = {};
if (auth) {
runtime.auth = auth;
}
if (scripts) {
runtime.scripts = scripts;
}
if (variables) {
runtime.variables = variables;
}
if (assertions) {
runtime.assertions = assertions;
}
if (actions) {
(runtime as { actions?: typeof actions }).actions = actions;
}
ocRequest.runtime = runtime;
}
if (request.docs) {
ocRequest.docs = request.docs as string;
}
return ocRequest;
};

View File

@@ -0,0 +1,295 @@
import { uuid } from '../../common/index.js';
import {
fromOpenCollectionHeaders,
toOpenCollectionHeaders,
fromOpenCollectionParams,
toOpenCollectionParams,
fromOpenCollectionBody,
toOpenCollectionBody,
fromOpenCollectionAuth,
toOpenCollectionAuth,
fromOpenCollectionScripts,
toOpenCollectionScripts,
fromOpenCollectionVariables,
toOpenCollectionVariables,
fromOpenCollectionActions,
toOpenCollectionActions,
fromOpenCollectionAssertions,
toOpenCollectionAssertions
} from '../common';
import type {
HttpRequest,
HttpRequestSettings,
HttpRequestExample,
HttpRequestInfo,
HttpRequestDetails,
HttpRequestRuntime,
HttpRequestHeader,
HttpRequestBody,
Auth,
BrunoItem,
BrunoKeyValue,
BrunoHttpRequestParam,
BrunoExample,
BrunoHttpRequest
} from '../types';
import type { HttpItemSettings as BrunoHttpItemSettings } from '@usebruno/schema-types/collection/item';
const getHttpBody = (body: HttpRequestBody | Array<{ title: string; selected?: boolean; body: HttpRequestBody }> | undefined): HttpRequestBody | undefined => {
if (!body) return undefined;
if (Array.isArray(body)) {
const selected = body.find((v) => v.selected);
return selected?.body || body[0]?.body;
}
return body;
};
export const fromOpenCollectionHttpItem = (ocRequest: HttpRequest): BrunoItem => {
const info = ocRequest.info;
const http = ocRequest.http;
const runtime = ocRequest.runtime;
const scripts = fromOpenCollectionScripts(runtime?.scripts);
const httpBody = getHttpBody(http?.body as HttpRequestBody);
// variables (pre-request from variables, post-response from actions)
const variables = fromOpenCollectionVariables(runtime?.variables);
const postResponseVars = fromOpenCollectionActions(runtime?.actions);
const brunoRequest: BrunoHttpRequest = {
url: http?.url || '',
method: http?.method || 'GET',
headers: fromOpenCollectionHeaders(http?.headers) || [],
params: fromOpenCollectionParams(http?.params) || [],
body: fromOpenCollectionBody(httpBody) || {
mode: 'none',
json: null,
text: null,
xml: null,
sparql: null,
formUrlEncoded: [],
multipartForm: [],
graphql: null,
file: []
},
auth: fromOpenCollectionAuth(runtime?.auth as Auth),
script: {
req: scripts?.script?.req || null,
res: scripts?.script?.res || null
},
vars: {
req: variables.req,
res: postResponseVars
},
assertions: fromOpenCollectionAssertions(runtime?.assertions) || [],
tests: scripts?.tests || null,
docs: ocRequest.docs || null
};
const brunoItem: BrunoItem = {
uid: uuid(),
type: 'http-request',
seq: info?.seq || 1,
name: info?.name || 'Untitled Request',
tags: info?.tags || [],
request: brunoRequest,
settings: null,
fileContent: null,
root: null,
items: [],
examples: [],
filename: null,
pathname: null
};
if (ocRequest.settings) {
const settings: BrunoHttpItemSettings = {
encodeUrl: typeof ocRequest.settings.encodeUrl === 'boolean' ? ocRequest.settings.encodeUrl : true,
timeout: typeof ocRequest.settings.timeout === 'number' ? ocRequest.settings.timeout : 0,
followRedirects: typeof ocRequest.settings.followRedirects === 'boolean' ? ocRequest.settings.followRedirects : true,
maxRedirects: typeof ocRequest.settings.maxRedirects === 'number' ? ocRequest.settings.maxRedirects : 5
};
brunoItem.settings = settings;
}
if (ocRequest.examples?.length) {
brunoItem.examples = ocRequest.examples.map((example): BrunoExample => ({
uid: uuid(),
itemUid: brunoItem.uid,
name: example.name || 'Untitled Example',
description: typeof example.description === 'string' ? example.description : (example.description as { content?: string })?.content || null,
type: 'http-request',
request: {
url: example.request?.url || '',
method: example.request?.method || 'GET',
headers: fromOpenCollectionHeaders(example.request?.headers) || [],
params: fromOpenCollectionParams(example.request?.params) || [],
body: fromOpenCollectionBody(example.request?.body) || null
},
response: example.response ? {
status: String(example.response.status || 200),
statusText: example.response.statusText || 'OK',
headers: fromOpenCollectionHeaders(example.response.headers as HttpRequestHeader[]) || [],
body: example.response.body ? {
type: example.response.body.type || 'text',
content: example.response.body.data || ''
} : null
} : null
}));
}
return brunoItem;
};
export const toOpenCollectionHttpItem = (item: BrunoItem): HttpRequest => {
const ocRequest: HttpRequest = {};
const brunoRequest = item.request as BrunoHttpRequest;
const brunoSettings = item.settings as BrunoHttpItemSettings | undefined;
const info: HttpRequestInfo = {
name: item.name || 'Untitled Request',
type: 'http'
};
if (item.seq) {
info.seq = item.seq;
}
if (item.tags?.length) {
info.tags = item.tags;
}
ocRequest.info = info;
const http: HttpRequestDetails = {
method: brunoRequest?.method || 'GET',
url: brunoRequest?.url || ''
};
const headers = toOpenCollectionHeaders(brunoRequest?.headers as BrunoKeyValue[]);
if (headers) {
http.headers = headers;
}
const params = toOpenCollectionParams(brunoRequest?.params as BrunoHttpRequestParam[]);
if (params) {
http.params = params;
}
const body = toOpenCollectionBody(brunoRequest?.body);
if (body) {
http.body = body;
}
ocRequest.http = http;
const runtime: HttpRequestRuntime = {};
let hasRuntime = false;
const variables = toOpenCollectionVariables(brunoRequest?.vars);
if (variables) {
runtime.variables = variables;
hasRuntime = true;
}
const scripts = toOpenCollectionScripts(brunoRequest);
if (scripts) {
runtime.scripts = scripts;
hasRuntime = true;
}
const assertions = toOpenCollectionAssertions(brunoRequest?.assertions as BrunoKeyValue[]);
if (assertions) {
runtime.assertions = assertions;
hasRuntime = true;
}
// actions (from post-response variables)
const resVars = brunoRequest?.vars?.res;
const actions = toOpenCollectionActions(resVars);
if (actions) {
runtime.actions = actions;
hasRuntime = true;
}
const auth = toOpenCollectionAuth(brunoRequest?.auth);
if (auth) {
runtime.auth = auth;
hasRuntime = true;
}
if (hasRuntime) {
ocRequest.runtime = runtime;
}
const settings: HttpRequestSettings = {
encodeUrl: typeof brunoSettings?.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true,
timeout: typeof brunoSettings?.timeout === 'number' ? brunoSettings.timeout : 0,
followRedirects: typeof brunoSettings?.followRedirects === 'boolean' ? brunoSettings.followRedirects : true,
maxRedirects: typeof brunoSettings?.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5
};
ocRequest.settings = settings;
if (brunoRequest?.docs) {
ocRequest.docs = brunoRequest.docs;
}
if (item.examples?.length) {
ocRequest.examples = item.examples.map((example): HttpRequestExample => {
const ocExample: HttpRequestExample = {
name: example.name || 'Untitled Example'
};
if (example.description) {
ocExample.description = example.description;
}
if (example.request) {
ocExample.request = {
url: example.request.url || '',
method: example.request.method || 'GET'
};
const exampleHeaders = toOpenCollectionHeaders(example.request.headers as BrunoKeyValue[]);
if (exampleHeaders) {
ocExample.request.headers = exampleHeaders;
}
const exampleParams = toOpenCollectionParams(example.request.params as BrunoHttpRequestParam[]);
if (exampleParams) {
ocExample.request.params = exampleParams;
}
const exampleBody = toOpenCollectionBody(example.request.body);
if (exampleBody) {
ocExample.request.body = exampleBody;
}
}
if (example.response) {
ocExample.response = {};
if (example.response.status !== undefined) {
ocExample.response.status = Number(example.response.status);
}
if (example.response.statusText) {
ocExample.response.statusText = example.response.statusText;
}
const responseHeaders = toOpenCollectionHeaders(example.response.headers as BrunoKeyValue[]);
if (responseHeaders) {
ocExample.response.headers = responseHeaders;
}
if (example.response.body) {
ocExample.response.body = {
type: (example.response.body.type as 'json' | 'text' | 'xml' | 'html' | 'binary') || 'text',
data: String(example.response.body.content || '')
};
}
}
return ocExample;
});
}
return ocRequest;
};

View File

@@ -0,0 +1,125 @@
import { uuid } from '../../common/index.js';
import { fromOpenCollectionHttpItem, toOpenCollectionHttpItem } from './http';
import { fromOpenCollectionGraphqlItem, toOpenCollectionGraphqlItem } from './graphql';
import { fromOpenCollectionGrpcItem, toOpenCollectionGrpcItem } from './grpc';
import { fromOpenCollectionWebsocketItem, toOpenCollectionWebsocketItem } from './websocket';
import type {
BrunoItem
} from '../types';
interface OCItem {
info?: {
type?: string;
name?: string;
seq?: number;
};
http?: unknown;
graphql?: unknown;
grpc?: unknown;
websocket?: unknown;
items?: unknown[];
script?: string;
}
const getItemType = (item: OCItem): string => {
if (item.info?.type) {
return item.info.type;
}
if ('items' in item && item.items) {
return 'folder';
}
if ('http' in item && item.http) {
return 'http';
}
if ('graphql' in item && item.graphql) {
return 'graphql';
}
if ('grpc' in item && item.grpc) {
return 'grpc';
}
if ('websocket' in item && item.websocket) {
return 'websocket';
}
if ('script' in item && typeof item.script === 'string') {
return 'script';
}
return 'unknown';
};
export const fromOpenCollectionItem = (item: unknown, parseFolder: (folder: unknown) => BrunoItem): BrunoItem | null => {
const ocItem = item as OCItem;
const itemType = getItemType(ocItem);
switch (itemType) {
case 'http':
return fromOpenCollectionHttpItem(item as Parameters<typeof fromOpenCollectionHttpItem>[0]);
case 'graphql':
return fromOpenCollectionGraphqlItem(item as Parameters<typeof fromOpenCollectionGraphqlItem>[0]);
case 'grpc':
return fromOpenCollectionGrpcItem(item as Parameters<typeof fromOpenCollectionGrpcItem>[0]);
case 'websocket':
return fromOpenCollectionWebsocketItem(item as Parameters<typeof fromOpenCollectionWebsocketItem>[0]);
case 'folder':
return parseFolder(item);
case 'script': {
const scriptItem = item as { script?: string; info?: { name?: string } };
return {
uid: uuid(),
type: 'js',
name: scriptItem.info?.name || 'script.js',
fileContent: scriptItem.script || ''
};
}
default:
return null;
}
};
export const toOpenCollectionItem = (item: BrunoItem, stringifyFolder: (folder: BrunoItem) => unknown): unknown | null => {
switch (item.type) {
case 'http-request':
return toOpenCollectionHttpItem(item);
case 'graphql-request':
return toOpenCollectionGraphqlItem(item);
case 'grpc-request':
return toOpenCollectionGrpcItem(item);
case 'ws-request':
return toOpenCollectionWebsocketItem(item);
case 'folder':
return stringifyFolder(item);
case 'js':
return {
info: {
name: item.name || 'script.js',
type: 'script'
},
script: item.fileContent || ''
};
default:
return null;
}
};
export const fromOpenCollectionItems = (items: unknown[] | undefined, parseFolder: (folder: unknown) => BrunoItem): BrunoItem[] => {
return (items || [])
.map((item) => fromOpenCollectionItem(item, parseFolder))
.filter((item): item is BrunoItem => item !== null);
};
export const toOpenCollectionItems = (items: BrunoItem[] | undefined | null, stringifyFolder: (folder: BrunoItem) => unknown): unknown[] => {
return (items || [])
.map((item) => toOpenCollectionItem(item, stringifyFolder))
.filter((item): item is unknown => item !== null);
};
export { fromOpenCollectionHttpItem, toOpenCollectionHttpItem } from './http';
export { fromOpenCollectionGraphqlItem, toOpenCollectionGraphqlItem } from './graphql';
export { fromOpenCollectionGrpcItem, toOpenCollectionGrpcItem } from './grpc';
export { fromOpenCollectionWebsocketItem, toOpenCollectionWebsocketItem } from './websocket';

View File

@@ -0,0 +1,176 @@
import { uuid } from '../../common/index.js';
import {
fromOpenCollectionHeaders,
toOpenCollectionHeaders,
fromOpenCollectionAuth,
toOpenCollectionAuth,
fromOpenCollectionScripts,
toOpenCollectionScripts,
fromOpenCollectionVariables,
toOpenCollectionVariables,
fromOpenCollectionActions,
toOpenCollectionActions
} from '../common';
import type {
WebSocketRequest,
WebSocketRequestInfo,
WebSocketRequestDetails,
WebSocketRequestRuntime,
WebSocketMessage,
WebSocketMessageVariant,
Auth,
BrunoItem,
BrunoWsMessage,
BrunoKeyValue,
BrunoWebSocketRequestBody
} from '../types';
export const fromOpenCollectionWebsocketItem = (item: WebSocketRequest): BrunoItem => {
const info = item.info || {};
const websocket = item.websocket || {};
const runtime = item.runtime || {};
const wsMessages: BrunoWsMessage[] = [];
if (websocket.message) {
if ('type' in websocket.message && 'data' in websocket.message) {
const msg = websocket.message as WebSocketMessage;
wsMessages.push({
name: 'message 1',
type: msg.type || 'json',
content: msg.data || ''
});
} else if (Array.isArray(websocket.message)) {
websocket.message.forEach((m, index) => {
wsMessages.push({
name: m.title || `message ${index + 1}`,
type: m.message?.type || 'json',
content: m.message?.data || ''
});
});
}
}
const scripts = fromOpenCollectionScripts(runtime.scripts);
// variables (pre-request from variables, post-response from actions)
const variables = fromOpenCollectionVariables(runtime.variables);
const postResponseVars = fromOpenCollectionActions((runtime as { actions?: Parameters<typeof fromOpenCollectionActions>[0] }).actions);
const wsBody: BrunoWebSocketRequestBody = {
mode: 'ws',
ws: wsMessages
};
const brunoItem: BrunoItem = {
uid: uuid(),
type: 'ws-request',
name: info.name || 'Untitled Request',
seq: info.seq || 1,
request: {
url: websocket.url || '',
headers: fromOpenCollectionHeaders(websocket.headers),
body: wsBody,
auth: fromOpenCollectionAuth(runtime.auth as Auth),
script: scripts?.script,
vars: {
req: variables.req,
res: postResponseVars
},
tests: scripts?.tests,
docs: item.docs || ''
}
};
if (info.tags?.length) {
brunoItem.tags = info.tags;
}
return brunoItem;
};
export const toOpenCollectionWebsocketItem = (item: BrunoItem): WebSocketRequest => {
const request = (item.request || {}) as Record<string, unknown>;
const info: WebSocketRequestInfo = {
name: item.name || 'Untitled Request',
type: 'websocket'
};
if (item.seq) {
info.seq = item.seq;
}
if (item.tags?.length) {
info.tags = item.tags;
}
const websocket: WebSocketRequestDetails = {
url: request.url as string || ''
};
const headers = toOpenCollectionHeaders(request.headers as BrunoKeyValue[]);
if (headers) {
websocket.headers = headers;
}
const body = request.body as { ws?: BrunoWsMessage[] } | undefined;
if (body?.ws?.length) {
const messages = body.ws;
if (messages.length === 1) {
websocket.message = {
type: (messages[0].type as WebSocketMessage['type']) || 'json',
data: messages[0].content || ''
};
} else {
websocket.message = messages.map((msg): WebSocketMessageVariant => ({
title: msg.name || 'Untitled',
message: {
type: (msg.type as WebSocketMessage['type']) || 'json',
data: msg.content || ''
}
}));
}
}
const ocRequest: WebSocketRequest = {
info,
websocket
};
const auth = toOpenCollectionAuth(request.auth as Parameters<typeof toOpenCollectionAuth>[0]);
const scripts = toOpenCollectionScripts(request as Parameters<typeof toOpenCollectionScripts>[0]);
const variables = toOpenCollectionVariables(request.vars as Parameters<typeof toOpenCollectionVariables>[0]);
// actions (from post-response variables)
const vars = request.vars as { req?: unknown[]; res?: unknown[] } | undefined;
const actions = toOpenCollectionActions(vars?.res as Parameters<typeof toOpenCollectionActions>[0]);
if (auth || scripts || variables || actions) {
const runtime: WebSocketRequestRuntime = {};
if (auth) {
runtime.auth = auth;
}
if (scripts) {
runtime.scripts = scripts;
}
if (variables) {
runtime.variables = variables;
}
if (actions) {
(runtime as { actions?: typeof actions }).actions = actions;
}
ocRequest.runtime = runtime;
}
if (request.docs) {
ocRequest.docs = request.docs as string;
}
return ocRequest;
};

View File

@@ -0,0 +1,133 @@
import { OpenCollection } from "@opencollection/types";
import { BrunoCollection, BrunoCollectionRoot, BrunoConfig, PemCertificate, Pkcs12Certificate } from "./types";
import { fromOpenCollectionAuth, fromOpenCollectionHeaders, fromOpenCollectionScripts, fromOpenCollectionVariables } from "./common";
import { uuid } from "../common";
import { fromOpenCollectionItems } from "./items";
import { fromOpenCollectionFolder } from "./folder";
import { fromOpenCollectionEnvironments } from "./environment";
const fromOpenCollectionConfig = (oc: OpenCollection): BrunoConfig => {
const extensions = oc.extensions;
const ignoreList = extensions && Array.isArray(extensions.ignore)
? extensions.ignore as string[]
: ['node_modules', '.git'];
const brunoConfig: BrunoConfig = {
version: '1',
name: oc.info?.name || 'Untitled Collection',
type: 'collection',
ignore: ignoreList
};
const config = oc.config;
if (!config) {
return brunoConfig;
}
if (config.protobuf) {
brunoConfig.protobuf = {
protoFiles: config.protobuf.protoFiles?.map((f) => ({
path: f.path
})),
importPaths: config.protobuf.importPaths?.map((p) => ({
path: p.path,
disabled: p.disabled || false
}))
};
}
if (config.proxy && typeof config.proxy !== 'boolean') {
if (config.proxy === 'inherit') {
brunoConfig.proxy = { enabled: 'global' };
} else {
const proxyConfig = config.proxy;
brunoConfig.proxy = {
enabled: true,
protocol: proxyConfig.protocol || 'http',
hostname: proxyConfig.hostname || '',
port: proxyConfig.port || 0
};
if (proxyConfig.auth) {
brunoConfig.proxy.auth = {
enabled: true,
username: proxyConfig.auth.username || '',
password: proxyConfig.auth.password || ''
};
}
if (proxyConfig.bypassProxy) {
brunoConfig.proxy.bypassProxy = proxyConfig.bypassProxy;
}
}
}
if (config.clientCertificates?.length) {
brunoConfig.clientCertificates = {
certs: config.clientCertificates.map((cert) => {
if (cert.type === 'pem') {
const pemCert = cert as PemCertificate;
return {
domain: pemCert.domain || '',
type: 'pem' as const,
certFilePath: pemCert.certificateFilePath || '',
keyFilePath: pemCert.privateKeyFilePath || '',
passphrase: pemCert.passphrase || ''
};
} else if (cert.type === 'pkcs12') {
const pkcs12Cert = cert as Pkcs12Certificate;
return {
domain: pkcs12Cert.domain || '',
type: 'pkcs12' as const,
pfxFilePath: pkcs12Cert.pkcs12FilePath || '',
passphrase: pkcs12Cert.passphrase || ''
};
}
return null;
}).filter((cert): cert is NonNullable<typeof cert> => cert !== null)
};
}
return brunoConfig;
};
const fromOpenCollectionRoot = (oc: OpenCollection): BrunoCollectionRoot => {
const root: BrunoCollectionRoot = {};
if (oc.request) {
const scripts = fromOpenCollectionScripts(oc.request.scripts);
root.request = {
headers: fromOpenCollectionHeaders(oc.request.headers),
auth: fromOpenCollectionAuth(oc.request.auth),
script: scripts?.script,
vars: fromOpenCollectionVariables(oc.request.variables),
tests: scripts?.tests
};
}
if (oc.docs) {
root.docs = typeof oc.docs === 'string'
? oc.docs
: oc.docs.content || '';
}
root.meta = {
name: oc.info?.name || 'Untitled Collection'
};
return root;
};
export const openCollectionToBruno = (openCollection: OpenCollection): BrunoCollection => {
const brunoCollection: BrunoCollection = {
uid: uuid(),
name: openCollection.info?.name || 'Untitled Collection',
version: '1',
items: fromOpenCollectionItems(openCollection.items, (folder: unknown) => fromOpenCollectionFolder(folder as Parameters<typeof fromOpenCollectionFolder>[0])),
environments: fromOpenCollectionEnvironments(openCollection.config?.environments),
brunoConfig: fromOpenCollectionConfig(openCollection) as Record<string, unknown>,
root: fromOpenCollectionRoot(openCollection)
};
return brunoCollection;
};

View File

@@ -0,0 +1,208 @@
// OpenCollection types - main module
export type { OpenCollection, Extensions } from '@opencollection/types';
// OpenCollection collection/item types
export type { Item, Folder, FolderInfo } from '@opencollection/types/collection/item';
// OpenCollection HTTP request types
export type {
HttpRequest,
HttpRequestHeader,
HttpResponseHeader,
HttpRequestParam,
HttpRequestBody,
HttpRequestSettings,
HttpRequestExample,
HttpRequestExampleRequest,
HttpRequestExampleResponse,
HttpRequestExampleResponseBody,
HttpRequestBodyVariant,
HttpRequestInfo,
HttpRequestDetails,
HttpRequestRuntime,
RawBody,
FormUrlEncodedBody,
FormUrlEncodedEntry,
MultipartFormBody,
MultipartFormEntry,
FileBody,
FileBodyVariant
} from '@opencollection/types/requests/http';
// OpenCollection GraphQL request types
export type {
GraphQLRequest,
GraphQLRequestSettings,
GraphQLRequestInfo,
GraphQLRequestDetails,
GraphQLRequestRuntime,
GraphQLBody,
GraphQLBodyVariant
} from '@opencollection/types/requests/graphql';
// OpenCollection gRPC request types
export type {
GrpcRequest,
GrpcRequestInfo,
GrpcRequestDetails,
GrpcRequestRuntime,
GrpcMetadata,
GrpcMessage,
GrpcMessageVariant,
GrpcMessagePayload,
GrpcMethodType
} from '@opencollection/types/requests/grpc';
// OpenCollection WebSocket request types
export type {
WebSocketRequest,
WebSocketRequestInfo,
WebSocketRequestDetails,
WebSocketRequestRuntime,
WebSocketMessage,
WebSocketMessageVariant,
WebSocketPayload,
WebSocketMessageType
} from '@opencollection/types/requests/websocket';
// OpenCollection config types
export type { Environment, CollectionConfig } from '@opencollection/types/config/environments';
export type { Protobuf, ProtoFileItem, ProtoFileImportPath } from '@opencollection/types/config/protobuf';
export type { Proxy, ProxyAuth } from '@opencollection/types/config/proxy';
export type { ClientCertificate, PemCertificate, Pkcs12Certificate } from '@opencollection/types/config/certificates';
// OpenCollection common types
export type { RequestDefaults, RequestSettings } from '@opencollection/types/common/request-defaults';
export type { Documentation } from '@opencollection/types/common/documentation';
export type { Description } from '@opencollection/types/common/description';
export type { Info, Author } from '@opencollection/types/common/info';
export type {
Variable,
VariableValueVariant
} from '@opencollection/types/common/variables';
export type { Scripts } from '@opencollection/types/common/scripts';
export type { Assertion } from '@opencollection/types/common/assertions';
export type { Tag } from '@opencollection/types/common/tags';
export type {
Action,
ActionSetVariable,
ActionPhase,
ActionVariableScope,
SetVariableActionSelector,
SetVariableActionTarget
} from '@opencollection/types/common/actions';
// OpenCollection auth types
export type {
Auth,
AuthBasic,
AuthBearer,
AuthDigest,
AuthNTLM,
AuthAwsV4,
AuthApiKey,
AuthWsse
} from '@opencollection/types/common/auth';
export type { AuthOAuth2 } from '@opencollection/types/common/auth-oauth2';
// Bruno types - collection
export type { Item as BrunoItem } from '@usebruno/schema-types/collection/item';
export type {
FolderRoot as BrunoFolderRoot,
FolderRequest as BrunoFolderRequest,
FolderMeta as BrunoFolderMeta
} from '@usebruno/schema-types/collection/folder';
export type { Collection as BrunoCollection } from '@usebruno/schema-types/collection/collection';
export type {
Environment as BrunoEnvironment,
EnvironmentVariable as BrunoEnvironmentVariable
} from '@usebruno/schema-types/collection/environment';
export type {
Example as BrunoExample,
ExampleRequest as BrunoExampleRequest,
ExampleResponse as BrunoExampleResponse,
ExampleResponseBody as BrunoExampleResponseBody
} from '@usebruno/schema-types/collection/examples';
// Bruno types - common
export type { KeyValue as BrunoKeyValue } from '@usebruno/schema-types/common/key-value';
export type { Variable as BrunoVariable, Variables as BrunoVariables } from '@usebruno/schema-types/common/variables';
export type { Script as BrunoScript } from '@usebruno/schema-types/common/scripts';
export type {
Auth as BrunoAuth,
AuthMode as BrunoAuthMode,
AuthAwsV4 as BrunoAuthAwsV4,
AuthBasic as BrunoAuthBasic,
AuthBearer as BrunoAuthBearer,
AuthDigest as BrunoAuthDigest,
AuthNTLM as BrunoAuthNTLM,
AuthWsse as BrunoAuthWsse,
AuthApiKey as BrunoAuthApiKey,
OAuth2 as BrunoOAuth2
} from '@usebruno/schema-types/common/auth';
export type { MultipartFormEntry as BrunoMultipartFormEntry, MultipartForm as BrunoMultipartForm } from '@usebruno/schema-types/common/multipart-form';
export type { FileEntry as BrunoFileEntry, FileList as BrunoFileList } from '@usebruno/schema-types/common/file';
export type { GraphqlBody as BrunoGraphqlBody } from '@usebruno/schema-types/common/graphql';
// Bruno types - requests
export type {
HttpRequest as BrunoHttpRequest,
HttpRequestBody as BrunoHttpRequestBody,
HttpRequestBodyMode as BrunoHttpRequestBodyMode,
HttpRequestParam as BrunoHttpRequestParam,
HttpRequestParamType as BrunoHttpRequestParamType
} from '@usebruno/schema-types/requests/http';
export type {
GrpcRequest as BrunoGrpcRequest,
GrpcRequestBody as BrunoGrpcRequestBody,
GrpcMessage as BrunoGrpcMessage,
GrpcMethodType as BrunoGrpcMethodType
} from '@usebruno/schema-types/requests/grpc';
export type {
WebSocketRequest as BrunoWebSocketRequest,
WebSocketRequestBody as BrunoWebSocketRequestBody,
WebSocketMessage as BrunoWsMessage
} from '@usebruno/schema-types/requests/websocket';
export interface BrunoConfig {
version?: string;
name?: string;
type?: string;
ignore?: string[];
protobuf?: {
protoFiles?: { path: string }[];
importPaths?: { path: string; disabled?: boolean }[];
};
proxy?: {
enabled?: boolean | 'global';
protocol?: string;
hostname?: string;
port?: number;
auth?: {
enabled?: boolean;
username?: string;
password?: string;
};
bypassProxy?: string;
};
clientCertificates?: {
certs?: Array<{
domain?: string;
type?: 'pem' | 'pkcs12';
certFilePath?: string;
keyFilePath?: string;
pfxFilePath?: string;
passphrase?: string;
}>;
};
}
export interface BrunoCollectionRoot {
request?: any;
docs?: string;
meta?: {
name?: string;
seq?: number;
};
}

View File

@@ -8,7 +8,7 @@ const generateUID = () => {
return result;
};
import { get, each, filter } from 'lodash';
import { get, each } from 'lodash';
import { collectionSchema } from '@usebruno/schema';
// --- Inlined from src/common/index.js ---

View File

@@ -1,19 +1,31 @@
{
"compilerOptions": {
"target": "ES6",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"jsx": "react",
"target": "ES2020",
"module": "ESNext",
"declaration": true,
"declarationDir": "types",
"sourceMap": true,
"outDir": "dist",
"moduleResolution": "node",
"emitDeclarationOnly": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist",
"rootDir": "./src",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true
"moduleResolution": "node",
"declaration": true,
"declarationMap": true,
"allowJs": true,
"checkJs": false,
"types": ["node"],
"lib": ["ES2020"],
"typeRoots": ["../../node_modules/@types", "./node_modules/@types"],
"baseUrl": "../..",
"paths": {
"@usebruno/schema-types": ["packages/bruno-schema-types/dist/index.d.ts"],
"@usebruno/schema-types/*": ["packages/bruno-schema-types/dist/*"],
"@opencollection/types": ["node_modules/@opencollection/types/dist/opencollection.d.ts"],
"@opencollection/types/*": ["node_modules/@opencollection/types/dist/*"]
}
},
"exclude": ["dist", "node_modules", "tests"]
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js"],
"exclude": ["node_modules", "dist"]
}