From 70111a9dae5e3cae97b176a6f664d1ed1adf9f32 Mon Sep 17 00:00:00 2001 From: Alexander Streltsov Date: Thu, 28 Dec 2023 09:59:19 +0300 Subject: [PATCH] ci: init --- .env.example | 3 + .github/workflows/main.yaml | 36 +++ .gitignore | 3 + .nvmrc | 1 + nodemon.json | 16 +- package-lock.json | 389 ++++++++++++++++++++++++++- package.json | 13 +- routes/ui/chat/aidbox-resources.yaml | 0 routes/ui/chat/test/chat.test.js | 0 sync.js | 181 ------------- sync.mjs | 204 ++++++++++++++ tests/setup.js | 18 -- tests/setup.mjs | 30 +++ vite.config.ts => vite.config.mts | 4 +- 14 files changed, 681 insertions(+), 217 deletions(-) create mode 100644 .env.example create mode 100644 .github/workflows/main.yaml create mode 100644 .nvmrc delete mode 100644 routes/ui/chat/aidbox-resources.yaml delete mode 100644 routes/ui/chat/test/chat.test.js delete mode 100644 sync.js create mode 100644 sync.mjs delete mode 100644 tests/setup.js create mode 100644 tests/setup.mjs rename vite.config.ts => vite.config.mts (56%) diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c427794 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +AIDBOX_USER=root +AIDBOX_PASSWORD=secret +AIDBOX_URL=https://localhost:8080 diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000..d2cc090 --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,36 @@ +name: Build & Deploy + +on: + push: + branches: + - "main" + - "feat/ci-cd" + workflow_dispatch: + +jobs: + publish-gpr: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + - run: npm ci + - run: node sync.mjs + env: + AIDBOX_URL: ${{ vars.AIDBOX_STAGE_URL }} + AIDBOX_USER: ${{ vars.AIDBOX_STAGE_USERNAME }} + AIDBOX_PASSWORD: ${{ vars.AIDBOX_STAGE_PASSWORD }} + + - run: npm run test + env: + AIDBOX_URL: ${{ vars.AIDBOX_STAGE_URL }} + AIDBOX_USER: ${{ vars.AIDBOX_STAGE_USERNAME }} + AIDBOX_PASSWORD: ${{ vars.AIDBOX_STAGE_PASSWORD }} + - run: node sync.mjs + env: + AIDBOX_URL: ${{ vars.AIDBOX_PROD_URL }} + AIDBOX_USER: ${{ vars.AIDBOX_PROD_USERNAME }} + AIDBOX_PASSWORD: ${{ vars.AIDBOX_PROD_PASSWORD }} diff --git a/.gitignore b/.gitignore index fd4f2b0..3603315 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ node_modules .DS_Store +.env +.lsp +.clj-kondo diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..016efd8 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20.10.0 \ No newline at end of file diff --git a/nodemon.json b/nodemon.json index ea8f937..87e5849 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,5 +1,13 @@ { - "events": { - "start": "clear" - } -} + "watch": [ + "routes", + "sync.mjs", + "aidbox-resources.yaml" + ], + "legacyWatch": "true", + "ext": "yaml,clj,html,css,js", + "exec": "node sync.mjs", + "events": { + "start": "clear" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2aa3dc4..3e4f416 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,12 @@ "name": "aidbox-ui", "version": "1.0.0", "license": "ISC", - "dependencies": { - "axios": "^1.6.2", - "js-yaml": "^4.1.0" - }, "devDependencies": { + "axios": "^1.6.2", + "dotenv": "^16.3.1", + "js-yaml": "^4.1.0", + "nodemon": "^3.0.2", + "vite": "^5.0.10", "vitest": "^1.1.0" } }, @@ -645,6 +646,12 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "node_modules/acorn": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", @@ -678,10 +685,24 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/assertion-error": { "version": "1.1.0", @@ -695,18 +716,57 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/axios": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dev": true, "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -746,10 +806,38 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -757,6 +845,12 @@ "node": ">= 0.8" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -804,6 +898,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -817,6 +912,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/esbuild": { "version": "0.19.10", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.10.tgz", @@ -878,10 +985,23 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/follow-redirects": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, "funding": [ { "type": "individual", @@ -901,6 +1021,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -945,6 +1066,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -954,6 +1096,54 @@ "node": ">=16.17.0" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", @@ -976,6 +1166,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -1014,6 +1205,18 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -1036,6 +1239,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -1044,6 +1248,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -1063,6 +1268,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/mlly": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", @@ -1099,6 +1316,58 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nodemon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", @@ -1186,6 +1455,18 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -1242,7 +1523,14 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true }, "node_modules/react-is": { "version": "18.2.0", @@ -1250,6 +1538,18 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/rollup": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", @@ -1279,6 +1579,21 @@ "fsevents": "~2.3.2" } }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1318,6 +1633,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -1363,6 +1690,18 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/tinybench": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", @@ -1387,6 +1726,30 @@ "node": ">=14.0.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -1402,6 +1765,12 @@ "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", "dev": true }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/vite": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.10.tgz", @@ -1576,6 +1945,12 @@ "node": ">=8" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", diff --git a/package.json b/package.json index 076cec4..8e43dd3 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,19 @@ "version": "1.0.0", "description": "", "main": "main.js", + "type": "module", "scripts": { "test": "vitest", - "dev": "nodemon --watch routes --watch sync.js -e clj,html,css,js sync.js" + "dev": "nodemon" }, "author": "", "license": "ISC", - "dependencies": {}, "devDependencies": { - "vitest": "^1.1.0", "axios": "^1.6.2", - "js-yaml": "^4.1.0" + "dotenv": "^16.3.1", + "js-yaml": "^4.1.0", + "nodemon": "^3.0.2", + "vite": "^5.0.10", + "vitest": "^1.1.0" } -} +} \ No newline at end of file diff --git a/routes/ui/chat/aidbox-resources.yaml b/routes/ui/chat/aidbox-resources.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/routes/ui/chat/test/chat.test.js b/routes/ui/chat/test/chat.test.js deleted file mode 100644 index e69de29..0000000 diff --git a/sync.js b/sync.js deleted file mode 100644 index 6e9db49..0000000 --- a/sync.js +++ /dev/null @@ -1,181 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const axios = require('axios'); -const yaml = require('js-yaml') - -function listFilesRecursively(dir, filelist = []) { - const files = fs.readdirSync(dir); - - files.forEach(file => { - const filepath = path.join(dir, file); - if (fs.statSync(filepath).isDirectory()) { - filelist = listFilesRecursively(filepath, filelist); - } else { - filelist.push(filepath); - } - }); - - return filelist; -} - -const directoryPath = 'routes'; - -function getContentTypeByExt(ext) { - if (ext === 'js') - return 'text/javascript'; - else if (ext === 'js') - return 'text/css'; - return 'text/html' -} - -function buildOperationResource(filepath) { - const [_, ...splited] = filepath.split(/[\/\._]/); - const method = splited.slice(-2)[0]; - - const route = splited.slice(0, -2).map(route_path => { - if (route_path[0] === ':') - return {name: route_path.slice(1)} - else - return route_path}); - - const ext = splited.slice(-1)[0]; - - return {id: 'aidbox-' + filepath.replaceAll(/[_\.\/]/g, '-'), - resourceType: "Operation", - request: [method].concat(route), - action: ext === 'clj' ? "ui/clojure" : "ui/static", - data: {content: fs.readFileSync(filepath, {encoding: 'utf8'}), - headers: {'content-type': getContentTypeByExt(ext)}}}} - -const AIDBOX_URL = 'http://localhost:8765'; - -async function deployOperation(operation) { - await axios.put( - `${AIDBOX_URL}/Operation/${operation.id}`, - operation, - { - headers: { - "content-type": "application/json", - "Authorization": "Basic cm9vdDpzZWNyZXQ=" - } - } - ); - - console.log(operation.id + " deployed"); -} - -const operations = listFilesRecursively(directoryPath) - .filter(filename => !filename.endsWith('.DS_Store')) - .map(buildOperationResource); - -const operationIdsToDeploy = new Set(operations.map(op => op.id)); - -async function removeRedundantOperationIdsFromAidbox() { - const resp = await axios.post( - `${AIDBOX_URL}/$sql`, - "select id from operation where id like 'aidbox-ui-%'", - { - headers: { - "content-type": "application/json", - "Authorization": "Basic cm9vdDpzZWNyZXQ=" - } - } - ); - - const deployedOperationIds = resp.data.map(op => op.id); - - const operationsToDelete = deployedOperationIds.filter(id => !operationIdsToDeploy.has(id)); - - operationsToDelete.map(async operationId => { - - await axios.delete( - `${AIDBOX_URL}/Operation/${operationId}`, - {headers: {"Authorization": "Basic cm9vdDpzZWNyZXQ="}} - ) - - console.log(operationId + " deleted") - - }); - -} - - -// console.log(files[0]); - - - -async function getSeedImport() { - try { - const resp = await axios.get( - `${AIDBOX_URL}/SeedImport/aidbox-ui`, - { - headers: { - "content-type": "application/json", - "Authorization": "Basic cm9vdDpzZWNyZXQ=" - } - } - ); - return resp.data.resources; - } catch (e) { - if (e.response.status === 404) - return [] - else - throw e - } -} - -function getResourcesToUpload() { - return fs.readFileSync('aidbox-resources.yaml', 'utf8') - .split(/\n---\n/) - .map(yaml.load) - .filter(res => res !== undefined); -} - -const resToRefString = res => `${res.resourceType}/${res.id}`; - - -async function syncAidboxResources() { - const seedImportRefs = await getSeedImport(); - const resourcesToUpload = getResourcesToUpload(); - - const resourceIdsToUpload = new Set(resourcesToUpload.map(resToRefString)) - - const toDelete = seedImportRefs.filter(ref => !resourceIdsToUpload.has(resToRefString(ref))); - - toDelete.map(async ref => { - - await axios.delete( - `${AIDBOX_URL}/${resToRefString(ref)}`, - {headers: {"Authorization": "Basic cm9vdDpzZWNyZXQ="}} - ) - - console.log(resToRefString(ref) + " deleted") - }); - - - await axios.put( - `${AIDBOX_URL}/SeedImport/aidbox-ui`, - {resources: resourcesToUpload.map(res => ({id: res.id, resourceType: res.resourceType}))}, - {headers: { - "content-type": "application/json", - "Authorization": "Basic cm9vdDpzZWNyZXQ=" - }} - ) - - resourcesToUpload.map(async res => { - - await axios.put( - `${AIDBOX_URL}/${resToRefString(res)}`, - res, - {headers: {"Authorization": "Basic cm9vdDpzZWNyZXQ="}} - ) - - console.log(`Aidbox resource saved. ${resToRefString(res)}`) - - }) - -} - -syncAidboxResources() -removeRedundantOperationIdsFromAidbox(); -operations.map(deployOperation); diff --git a/sync.mjs b/sync.mjs new file mode 100644 index 0000000..4e03bac --- /dev/null +++ b/sync.mjs @@ -0,0 +1,204 @@ +import { readdirSync, statSync, readFileSync } from 'fs'; +import { join } from 'path'; +import axios from 'axios'; +import { load } from 'js-yaml'; +import dotenv from 'dotenv'; + + +const resToRefString = res => `${res.resourceType}/${res.id}`; + +function listFilesRecursively(dir, fileList = []) { + const files = readdirSync(dir); + + files.forEach(file => { + const filepath = join(dir, file); + if (statSync(filepath).isDirectory()) { + fileList = listFilesRecursively(filepath, fileList); + } else { + fileList.push(filepath); + } + }); + + return fileList; +} + +const directoryPath = 'routes'; + + + +const operations = listFilesRecursively(directoryPath) + .filter(filename => !filename.endsWith('.DS_Store') + && !filename.endsWith('.test.js') + && !filename.endsWith('.test.mjs') + && !filename.endsWith(".md")) + .map(buildOperationResource); + +const operationIdsToDeploy = new Set(operations.map(op => op.id)); + +function getContentTypeByExt(ext) { + switch (ext) { + case "js": + return 'text/javascript'; + case "css": + return 'text/css'; + default: + return 'text/html'; + } +} + +function buildOperationResource(filepath) { + const [_, ...splited] = filepath.split(/[\/\._]/); + const method = splited.slice(-2)[0]; + console.log(filepath); + const route = splited.slice(0, -2).map(route_path => { + if (route_path[0] === ':') + return { name: route_path.slice(1) } + else + return route_path + }); + + const ext = splited.slice(-1)[0]; + return { + id: 'aidbox-' + filepath.replaceAll(/[_\.\/]/g, '-'), + resourceType: "Operation", + request: [method].concat(route), + action: ext === 'clj' ? "ui/clojure" : "ui/static", + data: { + content: readFileSync(filepath, { encoding: 'utf8' }), + headers: { 'content-type': getContentTypeByExt(ext) } + } + } +} + +/** + * + * @param {import('axios').AxiosInstance} client + */ +async function removeRedundantOperationIdsFromAidbox(client) { + const resp = await client.post( + '/$sql', + "select id from operation where id like 'aidbox-ui-%'", + ); + + + const operationsToDelete = resp.data + .map(op => op.id) + .filter(id => !operationIdsToDeploy.has(id)); + + await Promise.all(operationsToDelete.map(async operationId => { + + return client.delete( + `/Operation/${operationId}`, + ).then(() => { + console.log("[Deleted] ", operationId) + }) + })) + +} + +/** + * + * @param {import('axios').AxiosInstance} client + */ +async function getSeedImport(client) { + try { + const resp = await client.get( + '/SeedImport/aidbox-ui'); + return resp.data.resources; + } catch (e) { + console.log(e); + if (e.response.status === 404) + return [] + else + throw e + } +} + +function getResourcesToUpload() { + return readFileSync('aidbox-resources.yaml', 'utf8') + .split(/\n---\n/) + .map(load) + .filter(res => res !== undefined); +} + + +/** + * + * @param {import('axios').AxiosInstance} client + */ +async function syncAidboxResources(client) { + const seedImportRefs = await getSeedImport(client); + const resourcesToUpload = getResourcesToUpload(); + + const resourceIdsToUpload = new Set(resourcesToUpload.map(resToRefString)) + + const toDelete = seedImportRefs.filter(ref => !resourceIdsToUpload.has(resToRefString(ref))); + + + await Promise.all(toDelete.map(async ref => { + return client.delete(`/${resToRefString(ref)}`).then(() => { + console.log("[Deleted]: ", resToRefString(ref)) + }) + })); + + + await client.put( + `/SeedImport/aidbox-ui`, + { resources: resourcesToUpload.map(res => ({ id: res.id, resourceType: res.resourceType })) }, + ) + + await Promise.all(resourcesToUpload.map(res => { + + return client.put( + `/${resToRefString(res)}`, + res, + ).then(() => { + console.log('[Aidbox resource saved]: ', resToRefString(res)) + }) + })) +} + +/** + * + * @param {import('axios').AxiosInstance} client + */ +async function deployOperations(client) { + await Promise.all(operations.map(operation => { + return client.put( + `/Operation/${operation.id}`, + operation, + ).then(() => { + console.log("[Deployed]: ", operation.id); + }) + })) +} + + +const main = async () => { + dotenv.config(); + + const baseURL = process.env.AIDBOX_URL; + const username = process.env.AIDBOX_USER; + const password = process.env.AIDBOX_PASSWORD; + + if (!baseURL || !username || !password) { + console.error("Please that your provide environments variables: AIDBOX_URL,AIDBOX_USER,AIDBOX_PASSWORD ") + process.exit(1) + } + const aidboxClient = axios.create({ + baseURL, + headers: { + "Content-Type": "application/json", + }, + auth: { + username, + password + } + }) + + await syncAidboxResources(aidboxClient); + await removeRedundantOperationIdsFromAidbox(aidboxClient); + await deployOperations(aidboxClient); +} + +main(); \ No newline at end of file diff --git a/tests/setup.js b/tests/setup.js deleted file mode 100644 index fb2ecd8..0000000 --- a/tests/setup.js +++ /dev/null @@ -1,18 +0,0 @@ -import axios from 'axios' - -const AIDBOX_URL = 'http://localhost:8765'; - -const client = axios.create({baseURL: AIDBOX_URL, - headers: {"content-type": "application/json", - "Authorization": "Basic cm9vdDpzZWNyZXQ="}}) - -async function http(opts) { - return await client.request( - {url: opts.url, - method: opts.method ?? 'get', - data: opts.body} - ).then(resp => resp.data); -} - - -globalThis.http = http diff --git a/tests/setup.mjs b/tests/setup.mjs new file mode 100644 index 0000000..88c537a --- /dev/null +++ b/tests/setup.mjs @@ -0,0 +1,30 @@ +import axios from 'axios' +import dotenv from 'dotenv'; + +dotenv.config(); + +const baseURL = process.env.AIDBOX_URL; +const username = process.env.AIDBOX_USER; +const password = process.env.AIDBOX_PASSWORD; + + +const client = axios.create({ + baseURL, + auth: { username, password }, + headers: { + "content-type": "application/json", + } +}) + +async function http(opts) { + return await client.request( + { + url: opts.url, + method: opts.method ?? 'get', + data: opts.body + } + ).then(resp => resp.data); +} + + +globalThis.http = http diff --git a/vite.config.ts b/vite.config.mts similarity index 56% rename from vite.config.ts rename to vite.config.mts index 7a5a023..232285c 100644 --- a/vite.config.ts +++ b/vite.config.mts @@ -2,7 +2,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { - exclude: [], - setupFiles: ["tests/setup.js"] + exclude: ["**/node_modules/**"], + setupFiles: ["tests/setup.mjs"] }, })