From a24644ca877690d9982958c1d162ea33ee016604 Mon Sep 17 00:00:00 2001 From: JuLi0n21 Date: Mon, 18 May 2026 23:58:54 +0200 Subject: [PATCH] update fileclap blog --- .direnv/flake-profile | 1 - .direnv/flake-profile-1-link | 1 - .gitignore | 1 + package-lock.json | 590 ++++++++++++++++++++----- package.json | 2 +- src/assets/fileclap/cicd.png | Bin 0 -> 24159 bytes src/content/blog/personal/fileclap.mdx | 111 ++++- 7 files changed, 582 insertions(+), 124 deletions(-) delete mode 120000 .direnv/flake-profile delete mode 120000 .direnv/flake-profile-1-link create mode 100644 src/assets/fileclap/cicd.png diff --git a/.direnv/flake-profile b/.direnv/flake-profile deleted file mode 120000 index 0c05709..0000000 --- a/.direnv/flake-profile +++ /dev/null @@ -1 +0,0 @@ -flake-profile-1-link \ No newline at end of file diff --git a/.direnv/flake-profile-1-link b/.direnv/flake-profile-1-link deleted file mode 120000 index 0474887..0000000 --- a/.direnv/flake-profile-1-link +++ /dev/null @@ -1 +0,0 @@ -/nix/store/p7z5gbs1jx39z6x9mb6rgg3izkkjgw24-nix-shell-env \ No newline at end of file diff --git a/.gitignore b/.gitignore index 16d54bb..e55a182 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ pnpm-debug.log* # jetbrains setting folder .idea/ +.direnv diff --git a/package-lock.json b/package-lock.json index 035b946..d5be06b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "astro", "version": "0.0.1", "dependencies": { - "@astrojs/check": "^0.9.8", + "@astrojs/check": "^0.9.2", "@astrojs/mdx": "^5.0.3", "@astrojs/rss": "^4.0.18", "@astrojs/sitemap": "^3.7.2", @@ -22,36 +22,46 @@ } }, "node_modules/@astrojs/check": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.8.tgz", - "integrity": "sha512-LDng8446QLS5ToKjRHd3bgUdirvemVVExV7nRyJfW2wV36xuv7vDxwy5NWN9zqeSEDgg0Tv84sP+T3yEq+Zlkw==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.2.tgz", + "integrity": "sha512-6rWxtJTbd/ctdAlmla0CAvloGaai5IUTG0K21kctJHHGKJKnGH6Xana7m0zNOtHpVPEJi1SgC/TcsN+ltYt0Cg==", "license": "MIT", "dependencies": { - "@astrojs/language-server": "^2.16.5", - "chokidar": "^4.0.3", + "@astrojs/language-server": "^2.13.2", + "chokidar": "^3.5.3", + "fast-glob": "^3.3.1", "kleur": "^4.1.5", "yargs": "^17.7.2" }, "bin": { - "astro-check": "bin/astro-check.js" + "astro-check": "dist/bin.js" }, "peerDependencies": { "typescript": "^5.0.0" } }, "node_modules/@astrojs/check/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "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": ">= 14.16.0" + "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, "node_modules/@astrojs/check/node_modules/kleur": { @@ -63,17 +73,28 @@ "node": ">=6" } }, - "node_modules/@astrojs/check/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "node_modules/@astrojs/check/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">=8.6" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@astrojs/check/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, "node_modules/@astrojs/compiler": { @@ -92,20 +113,20 @@ } }, "node_modules/@astrojs/language-server": { - "version": "2.16.6", - "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.6.tgz", - "integrity": "sha512-N990lu+HSFiG57owR0XBkr02BYMgiLCshLf+4QG4v6jjSWkBeQGnzqi+E1L08xFPPJ7eEeXnxPXGLaVv5pa4Ug==", + "version": "2.16.9", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.9.tgz", + "integrity": "sha512-L9kddTg+ZSO3X0Pwfx0ZPO+Z+eSSq0/39jXRyIkHzcBICzusdn2T464R4P6K0WcDZ6pMkLlFpuGS73u1pOnMSw==", "license": "MIT", "dependencies": { "@astrojs/compiler": "^2.13.1", - "@astrojs/yaml2ts": "^0.2.3", + "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", - "tinyglobby": "^0.2.15", + "tinyglobby": "^0.2.16", "volar-service-css": "0.0.70", "volar-service-emmet": "0.0.70", "volar-service-html": "0.0.70", @@ -223,17 +244,15 @@ } }, "node_modules/@astrojs/telemetry": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", - "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.2.tgz", + "integrity": "sha512-j8DNruA8ors99Al39RYZPJK4DC1bKkoNm93mAMuBhY9TCNC4R8n1q7ovFnJ5qhGh5Lsh7pa1gpQVpYpsJPeTHQ==", "license": "MIT", "dependencies": { - "ci-info": "^4.2.0", - "debug": "^4.4.0", - "dlv": "^1.1.3", + "ci-info": "^4.4.0", "dset": "^3.1.4", - "is-docker": "^3.0.0", - "is-wsl": "^3.1.0", + "is-docker": "^4.0.0", + "is-wsl": "^3.1.1", "which-pm-runs": "^1.1.0" }, "engines": { @@ -241,12 +260,12 @@ } }, "node_modules/@astrojs/yaml2ts": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.3.tgz", - "integrity": "sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", + "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", "license": "MIT", "dependencies": { - "yaml": "^2.8.2" + "yaml": "^2.8.3" } }, "node_modules/@babel/helper-string-parser": { @@ -1318,6 +1337,53 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@oslojs/encoding": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", @@ -1954,6 +2020,12 @@ "vscode-uri": "^3.0.8" } }, + "node_modules/@vscode/emmet-helper/node_modules/jsonc-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", + "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "license": "MIT" + }, "node_modules/@vscode/l10n": { "version": "0.0.18", "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", @@ -1982,9 +2054,9 @@ } }, "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -2077,15 +2149,15 @@ } }, "node_modules/astro": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/astro/-/astro-6.1.5.tgz", - "integrity": "sha512-AJVw/JlssxUCBFi3Hp4djL8Pt7wUQqStBBawCd8cNGBBM2lBzp/rXGguzt4OcMfW+86fs0hpFwMyopHM2r6d3g==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/astro/-/astro-6.3.5.tgz", + "integrity": "sha512-gU+4KedkbTuVgz7YoVAN+9Ftnq0GaYwejxK2NbqDzB0M9dWd0f3kXZBuaM9hzbchRFoRAJfJjFtdX9LK6Ir7ZA==", "license": "MIT", "dependencies": { - "@astrojs/compiler": "^3.0.1", - "@astrojs/internal-helpers": "0.8.0", - "@astrojs/markdown-remark": "7.1.0", - "@astrojs/telemetry": "3.3.0", + "@astrojs/compiler": "^4.0.0", + "@astrojs/internal-helpers": "0.9.1", + "@astrojs/markdown-remark": "7.1.2", + "@astrojs/telemetry": "3.3.2", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", @@ -2103,10 +2175,12 @@ "esbuild": "^0.27.3", "flattie": "^1.1.1", "fontace": "~0.4.1", + "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", + "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", @@ -2116,7 +2190,7 @@ "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", - "picomatch": "^4.0.3", + "picomatch": "^4.0.4", "rehype": "^13.0.2", "semver": "^7.7.4", "shiki": "^4.0.2", @@ -2125,13 +2199,12 @@ "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", - "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unist-util-visit": "^5.1.0", - "unstorage": "^1.17.4", + "unstorage": "^1.17.5", "vfile": "^6.0.3", - "vite": "^7.3.1", + "vite": "^7.3.2", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", @@ -2154,11 +2227,61 @@ } }, "node_modules/astro/node_modules/@astrojs/compiler": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-3.0.1.tgz", - "integrity": "sha512-z97oYbdebO5aoWzuJ/8q5hLK232+17KcLZ7cJ8BCWk6+qNzVxn/gftC0KzMBUTD8WAaBkPpNSQK6PXLnNrZ0CA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-4.0.0.tgz", + "integrity": "sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA==", "license": "MIT" }, + "node_modules/astro/node_modules/@astrojs/internal-helpers": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.9.1.tgz", + "integrity": "sha512-1pWuARqYom/TzuU3+0ZugsTrKlUydWKuULmDqSMTuonY+9IRDUEGKX/8PXQ1nBxRq3w85uGtd9q9SXfqEldMIQ==", + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.4" + } + }, + "node_modules/astro/node_modules/@astrojs/markdown-remark": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.1.2.tgz", + "integrity": "sha512-caXZ4Dc2St2dW8luEg22GlP0gupLdztCTQE4EzZOxW1pqWXz9mbeJEuHUkgDYcKWW8tjIHkydYDhWLVoxJ327Q==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.9.1", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-to-text": "^4.0.2", + "js-yaml": "^4.1.1", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remark-smartypants": "^3.0.2", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.0", + "smol-toml": "^1.6.0", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.1.0", + "unist-util-visit-parents": "^6.0.2", + "vfile": "^6.0.3" + } + }, + "node_modules/astro/node_modules/@astrojs/prism": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", + "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, "node_modules/astro/node_modules/yargs-parser": { "version": "22.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", @@ -2187,12 +2310,36 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -2588,9 +2735,9 @@ } }, "node_modules/devalue": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.7.1.tgz", - "integrity": "sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", + "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", "license": "MIT" }, "node_modules/devlop": { @@ -2615,12 +2762,6 @@ "node": ">=0.3.1" } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "license": "MIT" - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -2934,6 +3075,22 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-string-truncated-width": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-1.2.1.tgz", @@ -2950,9 +3107,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -2975,9 +3132,9 @@ } }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -2986,13 +3143,14 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { - "version": "5.5.11", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.11.tgz", - "integrity": "sha512-QL0eb0YbSTVWF6tTf1+LEMSgtCEjBYPpnAjoLC8SscESlAjXEIRJ7cHtLG0pLeDFaZLa4VKZLArtA/60ZS7vyA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.8.0.tgz", + "integrity": "sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==", "funding": [ { "type": "github", @@ -3001,14 +3159,25 @@ ], "license": "MIT", "dependencies": { - "fast-xml-builder": "^1.1.4", - "path-expression-matcher": "^1.4.0", - "strnum": "^2.2.3" + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.2.0", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.3.0", + "xml-naming": "^0.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -3026,6 +3195,18 @@ } } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/flattie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", @@ -3079,12 +3260,39 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.4", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.4.tgz", + "integrity": "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "engines": { + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, + "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==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/h3": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", @@ -3395,6 +3603,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "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==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-decimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", @@ -3406,20 +3626,29 @@ } }, "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", + "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -3429,6 +3658,18 @@ "node": ">=8" } }, + "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==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-hexadecimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", @@ -3457,6 +3698,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -3503,9 +3768,9 @@ "license": "MIT" }, "node_modules/jsonc-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", - "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "license": "MIT" }, "node_modules/longest-streak": { @@ -3877,6 +4142,15 @@ "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "license": "CC0-1.0" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -4594,6 +4868,31 @@ ], "license": "MIT" }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -4882,9 +5181,9 @@ } }, "node_modules/postcss": { - "version": "8.5.9", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", - "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "funding": [ { "type": "opencollective", @@ -4958,6 +5257,26 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/radix3": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", @@ -5263,6 +5582,15 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/retext": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", @@ -5324,6 +5652,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.60.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", @@ -5368,6 +5706,29 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/s.color": { "version": "0.0.15", "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", @@ -5555,9 +5916,9 @@ } }, "node_modules/strnum": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", - "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", "funding": [ { "type": "github", @@ -5659,6 +6020,18 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "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==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -5679,26 +6052,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/tsconfck": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", - "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", - "license": "MIT", - "bin": { - "tsconfck": "bin/tsconfck.js" - }, - "engines": { - "node": "^18 || >=20" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6331,12 +6684,6 @@ "npm": ">=7.0.0" } }, - "node_modules/vscode-json-languageservice/node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "license": "MIT" - }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -6411,6 +6758,21 @@ "node": ">=4" } }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", diff --git a/package.json b/package.json index 29ab05b..25edf8f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "format": "prettier --write ." }, "dependencies": { - "@astrojs/check": "^0.9.8", + "@astrojs/check": "^0.9.2", "@astrojs/mdx": "^5.0.3", "@astrojs/rss": "^4.0.18", "@astrojs/sitemap": "^3.7.2", diff --git a/src/assets/fileclap/cicd.png b/src/assets/fileclap/cicd.png new file mode 100644 index 0000000000000000000000000000000000000000..7e3f570ad62e64e9e6561c59d6d9088b224724a6 GIT binary patch literal 24159 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 kKuGAR=BM{` h1, h2, h3, h4, h5, h6, figcaption::before { color: #ffdf20 } @@ -26,19 +27,115 @@ import search from "@assets/fileclap/search.png"; # FileClap: Clear the paperwork off the table -Your digital assistant for students and trainees - No more paper chaos! FileClap helps you easily organize photos, receipts, and important documents. Securely stored and accessible from anywhere—for a stress-free daily life with more clarity! homeview -Advanced Search Capabilites using Vector embeddings for shit +Advanced Search Capabillites using Vector embeddings. + +# Architecture and Technologies +## General +FileClap is built on golang with a-h/templ as a frontend technology, works with any s3 compatible Objectstorage. Keycloak is used for the authentication migrated from a previously self contained login flow. + +Redis is used to allow scalability in a microservice deployment. + +A seperate Thumbnail Generator was created in addition to create thumbnails for all types of files. Because it uses a large libraries like ffmped and pdf parsers, it was extracted into a seperate service. This allows the main service to be a small 32mb docker image, while the thumbnail generator is at 163mb after heavy optimization from an original 1gb+ container, the connection between the fileclap and the thumbnail generator runs over grpc. + +To allow for the vector embeddings that enable the semantic search, a migration from sqlite to postgres has taken place. + +For Observability OpenTelemetry is used on a function level basis, focussing on heavy operations like storage actions, database accessing and using the ocr service: + +```go +func (c *S3client) UploadObject(ctx context.Context, key string, body io.Reader, contentType string, user models.User) error { + //add new span for this function + tracer := otel.Tracer("fileclap_" + Version) + ctx, span := tracer.Start(ctx, "s3.UploadObject") + defer span.End() + + _, err := c.Client.PutObject(ctx, &s3.PutObjectInput{ + Bucket: aws.String(user.ID.String()), + Key: aws.String(key), + Body: body, + ContentType: aws.String(contentType), + }) + if err != nil { + //add error to span in cause something breaks + span.RecordError(err) + return err + } + + return nil +} +``` + +To minimize risks of data collisions and chances of different tenants accessing data of each other, each tenant has been given a s3-bucket that is just his user id. in the same way are all file / web requests handled: + +`https://fileclap.com/{userid}/operation/{fileid}/etc` `{userid}` representing a user and `{fileid}` representing a file inside that user context + +## Frontend + +htmx was used to enhance component based template generation from a-h/temple, the both of them work really well together since it is trivial to make use of rendering conditional components or full sides with just a simple header check, in addition u can save a lot of computing power when not even fetching unneeded data in case u just need sub components: + +```go +func (s *Server) GetLatestFiles(w http.ResponseWriter, r *http.Request) response { + + u := models.GetUser(r.Context()) + limit, offset := pagination(r) + files, err := s.FileRepository.GetRecentFiles(r.Context(), u, limit, offset) + if err != nil { + return response{err: err} + } + + if hxrequest(r) { //if htmx request return file component directly + cmp := components.Wrapper(web.Folders(files, "Latest", limit, offset)) + return response{err: cmp.Render(r.Context(), w)} + } + + //fetch folders to render full page which contains more stuff then just the fragment + folder, err := s.FileRepository.GetAllFolders(r.Context(), u) + if err != nil { + return response{err: err} + } + + cmp := components.Wrapper(views.Index("Latest", folder, "latest")) + return response{err: cmp.Render(r.Context(), w)} +} +``` + +while in conclusion a nice pair to work together, when ur used to force logic into the frontend to minimize server calls it realy becomes a mess and harder to debug. for example the file uploading is delegated to the frontend using presigned links which cant be done with just htmx so u have to create javascript which just isnt nice in temple if u again dont want to make unnecessary server calls + +## Vector embeddings +to allow for semantic search, currently all text files are scanned and turned into embeddings. +The contents of a document is prepared first. in the first phase it has an llm generate: +- keywords: a list of words a user would potentially use to associate with the document +- summary: a two sentence summary of the content +- metadata: Dates, places, contenttype, contacts, bills or what ever could be relevant based on the content +- tags: simple one sentence words that add in user filters: invoice may payment 2025 work +- folder: based on the list of existing folder names which one could fit / or create a new one + +in the second phase embeddings are created for the each of the generated values, and every piece of content is split in to 75 long chunks with a 5 char overlap to the previous chunk. this increases short search term accuracy immensely + +## Ci/cd + +for integration and deployment is a github actions pipeline used thats run on main push + +- it builds the go application +- it builds the docker application +- it runs the go binary, including a postgres db and runs playwright integration tests testing on a majority of browsers the uploading, searching, downloading, deleting of files +- if the docker build and integration tests are complete it pushes the container to the docker-hub repository which is later deployed using gitOps (argocd) manually. in a previous iteration it was set up inside the repository but due to having one repository for all deployments now its no longer allowed due to security risks + +
+ cicd +
Github actions pipeline, funnily enough the pipeline spends the majority of time downloading dependencies, the time could be reduced to 2 mins total, but playwright caching is not properly doable and the 500mb action cache store in total across ur entire account is just 10 times to little to be of any usage using even a basic alpine image as a builder
+
+ +## Performance testing + +Since using heavy caching for almost everything and delegating stuff like object management to the s3 provider, is the application in a simple locust test the service was able to serve 100s of requests every second without the user noticing any latency. + +on the other hand the searching through the documents is comparativley slow, its probaly due to missing db indexes in the vector space and the sheer amount of items considering uploading a single book creats thousands of embeddings, and the extra round trip off embedding the value using openais api. there's also 0 caching in either the embedding request themself or the results
search
Preview of the Search result for value "golang books"
- - -

check it out!

-