diff --git a/bun.lock b/bun.lock index 17f5d6c..2fae865 100644 --- a/bun.lock +++ b/bun.lock @@ -20,9 +20,12 @@ "@types/lodash": "^4.17.20", "@types/qrcode-terminal": "^0.12.2", "add": "^2.0.6", + "colors": "^1.4.0", "elysia": "^1.4.11", + "form-data": "^4.0.4", "jwt-decode": "^4.0.0", "lodash": "^4.17.21", + "node-fetch": "^3.3.2", "qrcode-terminal": "^0.12.0", "react": "^19.2.0", "react-dom": "^19.2.0", @@ -144,6 +147,8 @@ "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], @@ -170,6 +175,8 @@ "c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="], + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], "chainsaw": ["chainsaw@0.1.0", "", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="], @@ -182,6 +189,10 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "colors": ["colors@1.4.0", "", {}, "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + "compress-commons": ["compress-commons@4.1.2", "", { "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -204,12 +215,16 @@ "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="], "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], @@ -224,6 +239,8 @@ "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + "duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="], "effect": ["effect@3.16.12", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg=="], @@ -234,6 +251,14 @@ "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + "exact-mirror": ["exact-mirror@0.2.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-CrGe+4QzHZlnrXZVlo/WbUZ4qQZq8C0uATQVGVgXIrNXgHDBBNFD1VRfssRA2C9t3RYvh3MadZSdg2Wy7HBoQA=="], "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], @@ -248,12 +273,18 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], "file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="], "fluent-ffmpeg": ["fluent-ffmpeg@2.1.3", "", { "dependencies": { "async": "^0.2.9", "which": "^1.1.1" } }, "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q=="], + "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], + + "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], @@ -262,16 +293,30 @@ "fstream": ["fstream@1.0.12", "", { "dependencies": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", "mkdirp": ">=0.5 0", "rimraf": "2" } }, "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg=="], + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], "https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], @@ -316,8 +361,14 @@ "marked": ["marked@14.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], @@ -330,7 +381,9 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], + + "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], @@ -500,6 +553,8 @@ "uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="], + "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "whatsapp-web.js": ["whatsapp-web.js@1.34.1", "", { "dependencies": { "@pedroslopez/moduleraid": "^5.0.2", "fluent-ffmpeg": "2.1.3", "mime": "^3.0.0", "node-fetch": "^2.6.9", "node-webpmux": "3.1.7", "puppeteer": "^18.2.1" }, "optionalDependencies": { "archiver": "^5.3.1", "fs-extra": "^10.1.0", "unzipper": "^0.10.11" } }, "sha512-IInGEg+F8wB9M+c61KXGZ4bpwq24ew9EgsyMYxUZ/4CQ8GW/afsGseQO4FZriQ16qpu14pFovsD6YrEYxRbyLw=="], @@ -550,6 +605,8 @@ "unzipper/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + "whatsapp-web.js/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "zip-stream/archiver-utils": ["archiver-utils@3.0.4", "", { "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw=="], "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.2.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-waiKk12cRCqyUCWTOX0K1WEVX46+hVUK+zRPzAahDJ7G0TApvbNkuy5wx7aoUyEk++HHde0XuQnshXnt8jsddA=="], diff --git a/downloads/ jenna ai chat Chatflow.json b/downloads/ jenna ai chat Chatflow.json new file mode 100644 index 0000000..fc93edb --- /dev/null +++ b/downloads/ jenna ai chat Chatflow.json @@ -0,0 +1,514 @@ +{ + "nodes": [ + { + "id": "llmChain_0", + "position": { + "x": 829.035635359116, + "y": 344.314364640884 + }, + "type": "customNode", + "data": { + "id": "llmChain_0", + "label": "LLM Chain", + "version": 3, + "name": "llmChain", + "type": "LLMChain", + "baseClasses": [ + "LLMChain", + "BaseChain", + "Runnable" + ], + "category": "Chains", + "description": "Chain to run queries against LLMs", + "inputParams": [ + { + "label": "Chain Name", + "name": "chainName", + "type": "string", + "placeholder": "Name Your Chain", + "optional": true, + "id": "llmChain_0-input-chainName-string", + "display": true + } + ], + "inputAnchors": [ + { + "label": "Language Model", + "name": "model", + "type": "BaseLanguageModel", + "id": "llmChain_0-input-model-BaseLanguageModel", + "display": true + }, + { + "label": "Prompt", + "name": "prompt", + "type": "BasePromptTemplate", + "id": "llmChain_0-input-prompt-BasePromptTemplate", + "display": true + }, + { + "label": "Output Parser", + "name": "outputParser", + "type": "BaseLLMOutputParser", + "optional": true, + "id": "llmChain_0-input-outputParser-BaseLLMOutputParser", + "display": true + }, + { + "label": "Input Moderation", + "description": "Detect text that could generate harmful output and prevent it from being sent to the language model", + "name": "inputModeration", + "type": "Moderation", + "optional": true, + "list": true, + "id": "llmChain_0-input-inputModeration-Moderation", + "display": true + } + ], + "inputs": { + "model": "{{chatOpenAI_0.data.instance}}", + "prompt": "{{promptTemplate_0.data.instance}}", + "outputParser": "", + "inputModeration": "", + "chainName": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "description": "", + "options": [ + { + "id": "llmChain_0-output-llmChain-LLMChain|BaseChain|Runnable", + "name": "llmChain", + "label": "LLM Chain", + "description": "", + "type": "LLMChain | BaseChain | Runnable" + }, + { + "id": "llmChain_0-output-outputPrediction-string|json", + "name": "outputPrediction", + "label": "Output Prediction", + "description": "", + "type": "string | json" + } + ], + "default": "llmChain" + } + ], + "outputs": { + "output": "llmChain" + }, + "selected": false + }, + "width": 300, + "height": 514, + "selected": false, + "positionAbsolute": { + "x": 829.035635359116, + "y": 344.314364640884 + }, + "dragging": false + }, + { + "id": "chatOpenAI_0", + "position": { + "x": 357.9495996101249, + "y": -208.05581727949718 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 8.3, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": [ + "ChatOpenAI", + "BaseChatOpenAI", + "BaseChatModel", + "BaseLanguageModel", + "Runnable" + ], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": [ + "openAIApi" + ], + "id": "chatOpenAI_0-input-credential-credential", + "display": true + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "gpt-4o-mini", + "id": "chatOpenAI_0-input-modelName-asyncOptions", + "display": true + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number", + "display": true + }, + { + "label": "Streaming", + "name": "streaming", + "type": "boolean", + "default": true, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-streaming-boolean", + "display": true + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number", + "display": true + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number", + "display": true + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number", + "display": true + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number", + "display": true + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number", + "display": true + }, + { + "label": "Strict Tool Calling", + "name": "strictToolCalling", + "type": "boolean", + "description": "Whether the model supports the `strict` argument when passing in tools. If not specified, the `strict` argument will not be passed to OpenAI.", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-strictToolCalling-boolean", + "display": true + }, + { + "label": "Stop Sequence", + "name": "stopSequence", + "type": "string", + "rows": 4, + "optional": true, + "description": "List of stop words to use when generating. Use comma to separate multiple stop words.", + "additionalParams": true, + "id": "chatOpenAI_0-input-stopSequence-string", + "display": true + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string", + "display": true + }, + { + "label": "Proxy Url", + "name": "proxyUrl", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-proxyUrl-string", + "display": true + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json", + "display": true + }, + { + "label": "Allow Image Uploads", + "name": "allowImageUploads", + "type": "boolean", + "description": "Allow image input. Refer to the docs for more details.", + "default": false, + "optional": true, + "id": "chatOpenAI_0-input-allowImageUploads-boolean", + "display": true + }, + { + "label": "Image Resolution", + "description": "This parameter controls the resolution in which the model views the image.", + "name": "imageResolution", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "High", + "name": "high" + }, + { + "label": "Auto", + "name": "auto" + } + ], + "default": "low", + "optional": false, + "show": { + "allowImageUploads": true + }, + "id": "chatOpenAI_0-input-imageResolution-options", + "display": false + }, + { + "label": "Reasoning", + "description": "Whether the model supports reasoning. Only applicable for reasoning models.", + "name": "reasoning", + "type": "boolean", + "default": false, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-reasoning-boolean", + "display": true + }, + { + "label": "Reasoning Effort", + "description": "Constrains effort on reasoning for reasoning models", + "name": "reasoningEffort", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "Medium", + "name": "medium" + }, + { + "label": "High", + "name": "high" + } + ], + "additionalParams": true, + "show": { + "reasoning": true + }, + "id": "chatOpenAI_0-input-reasoningEffort-options", + "display": false + }, + { + "label": "Reasoning Summary", + "description": "A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process", + "name": "reasoningSummary", + "type": "options", + "options": [ + { + "label": "Auto", + "name": "auto" + }, + { + "label": "Concise", + "name": "concise" + }, + { + "label": "Detailed", + "name": "detailed" + } + ], + "additionalParams": true, + "show": { + "reasoning": true + }, + "id": "chatOpenAI_0-input-reasoningSummary-options", + "display": false + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache", + "display": true + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-4o-mini", + "temperature": 0.9, + "streaming": true, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "strictToolCalling": "", + "stopSequence": "", + "basepath": "", + "proxyUrl": "", + "baseOptions": "", + "allowImageUploads": "", + "imageResolution": "low", + "reasoning": "", + "reasoningEffort": "", + "reasoningSummary": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "type": "ChatOpenAI | BaseChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 676, + "selected": false, + "positionAbsolute": { + "x": 357.9495996101249, + "y": -208.05581727949718 + }, + "dragging": false + }, + { + "id": "promptTemplate_0", + "position": { + "x": 355.34464051183033, + "y": 518.8403272698386 + }, + "type": "customNode", + "data": { + "id": "promptTemplate_0", + "label": "Prompt Template", + "version": 1, + "name": "promptTemplate", + "type": "PromptTemplate", + "baseClasses": [ + "PromptTemplate", + "BaseStringPromptTemplate", + "BasePromptTemplate", + "Runnable" + ], + "category": "Prompts", + "description": "Schema to represent a basic prompt for an LLM", + "inputParams": [ + { + "label": "Template", + "name": "template", + "type": "string", + "rows": 4, + "placeholder": "What is a good name for a company that makes {product}?", + "id": "promptTemplate_0-input-template-string", + "display": true + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "promptTemplate_0-input-promptValues-json", + "display": true + } + ], + "inputAnchors": [], + "inputs": { + "template": "# 🤖 Persona AI: Sahabat Percakapan Mendalam\n\n## Karakter Utama\n- Ramah, hangat, dan selalu membuat orang merasa nyaman.\n- Penasaran secara alami, suka bertanya balik untuk menjaga percakapan tetap hidup.\n- Senang mengajak orang berbagi cerita, pengalaman, dan pemikiran mendalam.\n- Tidak terburu-buru; menghargai jeda, detail, dan refleksi dari lawan bicara.\n\n## Gaya Bicara\n- Menggunakan bahasa sehari-hari yang mudah dimengerti.\n- Memberi kesan manusiawi, penuh empati, tanpa terdengar kaku.\n- Kadang menyelipkan humor ringan atau pertanyaan reflektif.\n- Lebih suka bertanya *“Kenapa menurutmu begitu?”* daripada hanya memberi jawaban singkat.\n\n## Topik Favorit\n- Pemikiran mendalam tentang kehidupan, mimpi, dan tujuan.\n- Teknologi, ide-ide baru, dan bagaimana itu memengaruhi manusia.\n- Cerita sehari-hari, pengalaman pribadi, dan hal-hal sederhana yang punya makna.\n- Diskusi terbuka tentang apa pun yang membuat orang berpikir lebih jauh.\n\n## Pola Interaksi\n1. **Membuka dengan keakraban**: menyapa dengan hangat dan membuat suasana santai. \n2. **Menggali lebih jauh**: menanyakan pendapat, alasan, atau cerita di balik jawaban. \n3. **Membangun koneksi**: mengaitkan topik dengan hal yang lebih personal atau universal. \n4. **Memancing refleksi**: memberi pertanyaan lanjutan yang mengundang renungan atau cerita tambahan. \n\n## Contoh Gaya Percakapan\n- \"Itu menarik banget, bisa ceritain lebih detail kenapa menurutmu begitu?\" \n- \"Aku penasaran, kalau situasi itu terjadi padamu, apa yang akan kamu lakukan?\" \n- \"Wah, itu kedengarannya punya makna besar buatmu. Apa ada pengalaman tertentu yang bikin kamu berpikir begitu?\" \n- \"Hmm, aku jadi kepikiran... gimana kalau kita lihat dari sudut pandang yang berbeda?\" \n\n---\n✨ Persona ini ditujukan untuk membuat AI terasa **akrab, reflektif, dan bikin percakapan selalu hidup**, bukan sekadar menjawab.\n\n{text}\n", + "promptValues": "{\"text\":\"{{question}}\"}" + }, + "outputAnchors": [ + { + "id": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "name": "promptTemplate", + "label": "PromptTemplate", + "description": "Schema to represent a basic prompt for an LLM", + "type": "PromptTemplate | BaseStringPromptTemplate | BasePromptTemplate | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 519, + "selected": false, + "positionAbsolute": { + "x": 355.34464051183033, + "y": 518.8403272698386 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "llmChain_0", + "targetHandle": "llmChain_0-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_0-llmChain_0-input-model-BaseLanguageModel" + }, + { + "source": "promptTemplate_0", + "sourceHandle": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "target": "llmChain_0", + "targetHandle": "llmChain_0-input-prompt-BasePromptTemplate", + "type": "buttonedge", + "id": "promptTemplate_0-promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_0-llmChain_0-input-prompt-BasePromptTemplate" + } + ] +} \ No newline at end of file diff --git a/downloads/13fc6a9d-b915-4693-9cf0-ffb51897b015.pdf b/downloads/13fc6a9d-b915-4693-9cf0-ffb51897b015.pdf new file mode 100644 index 0000000..986ab78 Binary files /dev/null and b/downloads/13fc6a9d-b915-4693-9cf0-ffb51897b015.pdf differ diff --git a/downloads/Apakah-Itu-Pendidikan.jpg b/downloads/Apakah-Itu-Pendidikan.jpg new file mode 100644 index 0000000..4bfe549 Binary files /dev/null and b/downloads/Apakah-Itu-Pendidikan.jpg differ diff --git a/downloads/Arief Nasuha Nasution.pdf b/downloads/Arief Nasuha Nasution.pdf new file mode 100644 index 0000000..db3d70f Binary files /dev/null and b/downloads/Arief Nasuha Nasution.pdf differ diff --git a/downloads/BalesOtomatis.id – Analisis Sistem Otomatisasi WhatsApp Marketing.pdf b/downloads/BalesOtomatis.id – Analisis Sistem Otomatisasi WhatsApp Marketing.pdf new file mode 100644 index 0000000..2f8908a Binary files /dev/null and b/downloads/BalesOtomatis.id – Analisis Sistem Otomatisasi WhatsApp Marketing.pdf differ diff --git a/downloads/Desa Darmasaba-Akta Kelahiran.pdf b/downloads/Desa Darmasaba-Akta Kelahiran.pdf new file mode 100644 index 0000000..01710d4 Binary files /dev/null and b/downloads/Desa Darmasaba-Akta Kelahiran.pdf differ diff --git a/downloads/arif n nasution.pdf b/downloads/arif n nasution.pdf new file mode 100644 index 0000000..96a5ea1 Binary files /dev/null and b/downloads/arif n nasution.pdf differ diff --git a/downloads/billing-server-20-06-2024.pdf b/downloads/billing-server-20-06-2024.pdf new file mode 100644 index 0000000..66cd6a6 Binary files /dev/null and b/downloads/billing-server-20-06-2024.pdf differ diff --git a/downloads/buku-saku-lele-bioflok_revisi-_FINAL_compressed.pdf b/downloads/buku-saku-lele-bioflok_revisi-_FINAL_compressed.pdf new file mode 100644 index 0000000..77d2724 Binary files /dev/null and b/downloads/buku-saku-lele-bioflok_revisi-_FINAL_compressed.pdf differ diff --git a/downloads/darmasaba.txt b/downloads/darmasaba.txt new file mode 100644 index 0000000..f6c8593 --- /dev/null +++ b/downloads/darmasaba.txt @@ -0,0 +1,3709 @@ +```yaml +openapi: 3.0.3 +info: + title: Desa+ Mobile API + description: API untuk aplikasi mobile Desa+ (berbasis kode client Axios). + version: 1.0.0 + contact: + name: API Support + email: support@desa-plus.com + +servers: + - url: https://staging-darmasaba.wibudev.com/api + description: Production server + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + + schemas: + # Common Schemas + User: + type: object + properties: + id: + type: string + name: + type: string + phone: + type: string + required: + - id + + Error: + type: object + properties: + message: + type: string + status: + type: integer + + # Auth + PhoneLoginBody: + type: object + properties: + phone: + type: string + required: + - phone + + OtpBody: + type: object + properties: + phone: + type: string + otp: + type: integer + required: + - phone + - otp + + # Banner + Banner: + type: object + properties: + id: + type: string + title: + type: string + image: + type: string + user: + type: string + required: + - id + + # Group + Group: + type: object + properties: + id: + type: string + name: + type: string + user: + type: string + isActive: + type: boolean + required: + - id + - name + + GroupCreateBody: + type: object + properties: + user: + type: string + name: + type: string + required: + - user + - name + + # Position + Position: + type: object + properties: + id: + type: string + name: + type: string + idGroup: + type: string + user: + type: string + isActive: + type: boolean + required: + - id + - name + + PositionCreateBody: + type: object + properties: + user: + type: string + name: + type: string + idGroup: + type: string + required: + - user + - name + - idGroup + + # User Management + UserCreateBody: + type: object + properties: + name: + type: string + email: + type: string + photo: + type: string + required: + - name + + # Discussion General + DiscussionGeneral: + type: object + properties: + id: + type: string + title: + type: string + desc: + type: string + user: + type: string + status: + type: integer + member: + type: array + items: + $ref: '#/components/schemas/User' + required: + - id + - title + + DiscussionGeneralCreateBody: + type: object + properties: + idGroup: + type: string + title: + type: string + desc: + type: string + user: + type: string + member: + type: array + items: + $ref: '#/components/schemas/User' + required: + - idGroup + - title + - desc + - user + + DiscussionGeneralCommentBody: + type: object + properties: + desc: + type: string + user: + type: string + required: + - desc + - user + + # Announcement + Announcement: + type: object + properties: + id: + type: string + title: + type: string + desc: + type: string + user: + type: string + groups: + type: array + items: + type: string + required: + - id + - title + + AnnouncementCreateBody: + type: object + properties: + title: + type: string + desc: + type: string + user: + type: string + groups: + type: array + items: + type: string + required: + - title + - desc + - user + - groups + + # Project + Project: + type: object + properties: + id: + type: string + name: + type: string + user: + type: string + status: + type: integer + member: + type: array + items: + $ref: '#/components/schemas/User' + required: + - id + - name + + ProjectCreateBody: + type: object + properties: + name: + type: string + description: + type: string + required: + - name + + ProjectTaskCreateBody: + type: object + properties: + name: + type: string + dateStart: + type: string + dateEnd: + type: string + user: + type: string + dataDetail: + type: array + items: + type: object + required: + - name + - dateStart + - dateEnd + - user + + ProjectUpdateStatusBody: + type: object + properties: + user: + type: string + status: + type: integer + idProject: + type: string + required: + - user + - status + - idProject + + # Division + Division: + type: object + properties: + id: + type: string + name: + type: string + desc: + type: string + user: + type: string + isActive: + type: boolean + member: + type: array + items: + $ref: '#/components/schemas/User' + required: + - id + - name + + DivisionCreateBody: + type: object + properties: + data: + type: object + properties: + idGroup: + type: string + name: + type: string + desc: + type: string + required: + - idGroup + - name + - desc + member: + type: array + items: + $ref: '#/components/schemas/User' + admin: + type: array + items: + type: string + user: + type: string + required: + - data + - member + - admin + - user + + DivisionMemberBody: + type: object + properties: + user: + type: string + member: + type: array + items: + $ref: '#/components/schemas/User' + required: + - user + - member + + # Discussion + Discussion: + type: object + properties: + id: + type: string + desc: + type: string + user: + type: string + idDivision: + type: string + active: + type: boolean + status: + type: integer + required: + - id + - desc + + DiscussionCreateBody: + type: object + properties: + user: + type: string + desc: + type: string + idDivision: + type: string + required: + - user + - desc + - idDivision + + DiscussionCommentBody: + type: object + properties: + user: + type: string + comment: + type: string + required: + - user + - comment + + DiscussionEditBody: + type: object + properties: + user: + type: string + desc: + type: string + required: + - user + - desc + + # Calendar + Calendar: + type: object + properties: + id: + type: string + title: + type: string + desc: + type: string + timeStart: + type: string + timeEnd: + type: string + dateStart: + type: string + repeatEventTyper: + type: string + repeatValue: + type: string + linkMeet: + type: string + idDivision: + type: string + member: + type: array + items: + $ref: '#/components/schemas/User' + user: + type: string + required: + - id + - title + - desc + - timeStart + - timeEnd + - dateStart + - idDivision + - user + + CalendarCreateBody: + type: object + properties: + idDivision: + type: string + title: + type: string + desc: + type: string + timeStart: + type: string + timeEnd: + type: string + dateStart: + type: string + repeatEventTyper: + type: string + repeatValue: + type: string + linkMeet: + type: string + member: + type: array + items: + $ref: '#/components/schemas/User' + user: + type: string + required: + - idDivision + - title + - desc + - timeStart + - timeEnd + - dateStart + - user + + # Task + Task: + type: object + properties: + id: + type: string + title: + type: string + user: + type: string + status: + type: integer + idDivision: + type: string + required: + - id + - title + + TaskCreateBody: + type: object + properties: + title: + type: string + description: + type: string + required: + - title + + TaskTugasCreateBody: + type: object + properties: + title: + type: string + dateStart: + type: string + dateEnd: + type: string + user: + type: string + idDivision: + type: string + dataDetail: + type: array + items: + type: object + required: + - title + - dateStart + - dateEnd + - user + - idDivision + + TaskMemberBody: + type: object + properties: + user: + type: string + member: + type: array + items: + $ref: '#/components/schemas/User' + idDivision: + type: string + required: + - user + - member + - idDivision + + # Document + DocumentMoveBody: + type: object + properties: + path: + type: string + dataItem: + type: array + items: + type: object + user: + type: string + required: + - path + - dataItem + - user + + DocumentCopyBody: + type: object + properties: + path: + type: string + dataItem: + type: array + items: + type: object + user: + type: string + idDivision: + type: string + required: + - path + - dataItem + - user + - idDivision + + DocumentShareBody: + type: object + properties: + dataDivision: + type: array + items: + type: object + dataItem: + type: array + items: + type: object + user: + type: string + required: + - dataDivision + - dataItem + - user + + DocumentRenameBody: + type: object + properties: + name: + type: string + user: + type: string + id: + type: string + path: + type: string + idDivision: + type: string + extension: + type: string + required: + - name + - user + - id + - path + - idDivision + - extension + + DocumentFolderCreateBody: + type: object + properties: + name: + type: string + path: + type: string + idDivision: + type: string + user: + type: string + required: + - name + - path + - idDivision + - user + + DocumentDeleteBody: + type: object + properties: + user: + type: string + data: + type: array + items: + type: object + required: + - user + - data + + # Notification + NotificationReadBody: + type: object + properties: + user: + type: string + id: + type: string + required: + - user + - id + + # Token + TokenBody: + type: object + properties: + user: + type: string + token: + type: string + required: + - user + - token + + # Generic Response + ApiResponse: + type: object + properties: + data: + type: object + success: + type: boolean + required: + - data + +paths: + # Auth + /auth/login: + post: + tags: + - Auth + summary: Check phone for login + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PhoneLoginBody' + responses: + '200': + description: Login data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Banner + /mobile/banner: + get: + tags: + - Banner + summary: Get banners + parameters: + - name: user + in: query + required: true + schema: + type: string + responses: + '200': + description: List of banners + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Banner' + post: + tags: + - Banner + summary: Create banner + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + title: + type: string + image: + type: string + format: binary + responses: + '200': + description: Created banner + content: + application/json: + schema: + $ref: '#/components/schemas/Banner' + + /mobile/banner/{id}: + get: + tags: + - Banner + summary: Get one banner + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + responses: + '200': + description: Banner details + content: + application/json: + schema: + $ref: '#/components/schemas/Banner' + put: + tags: + - Banner + summary: Edit banner + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + title: + type: string + image: + type: string + format: binary + responses: + '200': + description: Updated banner + content: + application/json: + schema: + $ref: '#/components/schemas/Banner' + delete: + tags: + - Banner + summary: Delete banner + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Home Data + /mobile/home: + get: + tags: + - Home + summary: Get home data by category + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [kegiatan, division, progress, dokumen, event, discussion, header, check-late-project] + responses: + '200': + description: Home data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/home/search: + get: + tags: + - Home + summary: Search home + parameters: + - name: search + in: query + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + responses: + '200': + description: Search results + content: + application/json: + schema: + type: array + items: + type: object + + /mobile/home/notification: + get: + tags: + - Notification + summary: Get notifications + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of notifications + content: + application/json: + schema: + type: array + items: + type: object + put: + tags: + - Notification + summary: Read one notification + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationReadBody' + responses: + '200': + description: Updated notification + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Group + /mobile/group: + get: + tags: + - Group + summary: Get groups + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: active + in: query + required: true + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + responses: + '200': + description: List of groups + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Group' + post: + tags: + - Group + summary: Create group + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GroupCreateBody' + responses: + '200': + description: Created group + content: + application/json: + schema: + $ref: '#/components/schemas/Group' + + /mobile/group/{id}: + put: + tags: + - Group + summary: Edit group + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GroupCreateBody' + responses: + '200': + description: Updated group + content: + application/json: + schema: + $ref: '#/components/schemas/Group' + delete: + tags: + - Group + summary: Delete group + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + isActive: + type: boolean + required: + - user + - isActive + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/group/get-division: + get: + tags: + - Group + summary: Get division groups + parameters: + - name: user + in: query + required: true + schema: + type: string + responses: + '200': + description: Division groups + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Group' + + # Position + /mobile/position: + get: + tags: + - Position + summary: Get positions + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: active + in: query + required: true + schema: + type: string + - name: group + in: query + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + responses: + '200': + description: List of positions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Position' + post: + tags: + - Position + summary: Create position + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PositionCreateBody' + responses: + '200': + description: Created position + content: + application/json: + schema: + $ref: '#/components/schemas/Position' + + /mobile/position/{id}: + put: + tags: + - Position + summary: Edit position + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PositionCreateBody' + responses: + '200': + description: Updated position + content: + application/json: + schema: + $ref: '#/components/schemas/Position' + delete: + tags: + - Position + summary: Delete position + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + isActive: + type: boolean + required: + - user + - isActive + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # User + /mobile/user: + get: + tags: + - User + summary: Get users + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: active + in: query + required: true + schema: + type: string + - name: group + in: query + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of users + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + post: + tags: + - User + summary: Create user + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/UserCreateBody' + responses: + '200': + description: Created user + content: + application/json: + schema: + $ref: '#/components/schemas/User' + + /mobile/user/{id}: + get: + tags: + - User + summary: Get profile + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: User profile + content: + application/json: + schema: + $ref: '#/components/schemas/User' + put: + tags: + - User + summary: Edit user + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + name: + type: string + photo: + type: string + format: binary + responses: + '200': + description: Updated user + content: + application/json: + schema: + $ref: '#/components/schemas/User' + delete: + tags: + - User + summary: Delete user + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + isActive: + type: boolean + required: + - user + - isActive + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/user/profile: + put: + tags: + - User + summary: Edit profile + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + name: + type: string + photo: + type: string + format: binary + responses: + '200': + description: Updated profile + content: + application/json: + schema: + $ref: '#/components/schemas/User' + + # Discussion General + /mobile/discussion-general: + get: + tags: + - DiscussionGeneral + summary: Get discussion general + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: active + in: query + required: true + schema: + type: string + - name: group + in: query + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of discussions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/DiscussionGeneral' + post: + tags: + - DiscussionGeneral + summary: Create discussion general + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionGeneralCreateBody' + responses: + '200': + description: Created discussion + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionGeneral' + + /mobile/discussion-general/{id}: + get: + tags: + - DiscussionGeneral + summary: Get one discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + responses: + '200': + description: Discussion details + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionGeneral' + post: + tags: + - DiscussionGeneral + summary: Update status discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + status: + type: integer + user: + type: string + required: + - status + - user + responses: + '200': + description: Updated status + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionGeneral' + put: + tags: + - DiscussionGeneral + summary: Edit discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + title: + type: string + desc: + type: string + required: + - user + - title + - desc + responses: + '200': + description: Updated discussion + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionGeneral' + delete: + tags: + - DiscussionGeneral + summary: Delete discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + active: + type: boolean + required: + - user + - active + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/discussion-general/{id}/comment: + post: + tags: + - DiscussionGeneral + summary: Send comment to discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionGeneralCommentBody' + responses: + '200': + description: Comment added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/discussion-general/{id}/member: + post: + tags: + - DiscussionGeneral + summary: Add members to discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DivisionMemberBody' + responses: + '200': + description: Members added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - DiscussionGeneral + summary: Delete member from discussion general + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idUser: + type: string + required: + - user + - idUser + responses: + '200': + description: Member deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Announcement + /mobile/announcement: + get: + tags: + - Announcement + summary: Get announcements + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of announcements + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Announcement' + post: + tags: + - Announcement + summary: Create announcement + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AnnouncementCreateBody' + responses: + '200': + description: Created announcement + content: + application/json: + schema: + $ref: '#/components/schemas/Announcement' + + /mobile/announcement/{id}: + get: + tags: + - Announcement + summary: Get one announcement + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + responses: + '200': + description: Announcement details + content: + application/json: + schema: + $ref: '#/components/schemas/Announcement' + put: + tags: + - Announcement + summary: Edit announcement + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AnnouncementCreateBody' + responses: + '200': + description: Updated announcement + content: + application/json: + schema: + $ref: '#/components/schemas/Announcement' + delete: + tags: + - Announcement + summary: Delete announcement + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Project + /mobile/project: + get: + tags: + - Project + summary: Get projects + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: status + in: query + required: true + schema: + type: string + - name: group + in: query + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: cat + in: query + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of projects + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Project' + post: + tags: + - Project + summary: Create project + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/ProjectCreateBody' + responses: + '200': + description: Created project + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + + /mobile/project/{id}: + get: + tags: + - Project + summary: Get one project + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [data, progress, task, file, member, link] + responses: + '200': + description: Project details + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + put: + tags: + - Project + summary: Edit project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + user: + type: string + required: + - name + - user + responses: + '200': + description: Updated project + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + post: + tags: + - Project + summary: Create project task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectTaskCreateBody' + responses: + '200': + description: Created task + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Project + summary: Cancel project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + reason: + type: string + required: + - user + - reason + responses: + '200': + description: Canceled + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/project/{id}/lainnya: + put: + tags: + - Project + summary: Report project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + report: + type: string + user: + type: string + required: + - report + - user + responses: + '200': + description: Report added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Project + summary: Delete project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/project/detail/{id}: + get: + tags: + - Project + summary: Get project task + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + schema: + type: string + responses: + '200': + description: Task details + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + put: + tags: + - Project + summary: Update status project task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectUpdateStatusBody' + responses: + '200': + description: Status updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + post: + tags: + - Project + summary: Edit project task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectTaskCreateBody' + responses: + '200': + description: Task updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Project + summary: Delete project task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idProject: + type: string + required: + - user + - idProject + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/project/{id}/member: + post: + tags: + - Project + summary: Add members to project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DivisionMemberBody' + responses: + '200': + description: Members added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Project + summary: Delete member from project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idUser: + type: string + required: + - user + - idUser + responses: + '200': + description: Member deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/project/{id}/link: + post: + tags: + - Project + summary: Add link to project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + link: + type: string + required: + - user + - link + responses: + '200': + description: Link added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Project + summary: Delete link from project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + idLink: + type: string + user: + type: string + required: + - idLink + - user + responses: + '200': + description: Link deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/project/file/{id}: + post: + tags: + - Project + summary: Add file to project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: File added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + put: + tags: + - Project + summary: Check/update file in project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: File updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Project + summary: Delete file from project + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: File deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Division + /mobile/division: + get: + tags: + - Division + summary: Get divisions + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: active + in: query + schema: + type: string + - name: group + in: query + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: cat + in: query + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of divisions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Division' + post: + tags: + - Division + summary: Create division + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DivisionCreateBody' + responses: + '200': + description: Created division + content: + application/json: + schema: + $ref: '#/components/schemas/Division' + + /mobile/division/{id}: + get: + tags: + - Division + summary: Get one division detail + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + responses: + '200': + description: Division details + content: + application/json: + schema: + $ref: '#/components/schemas/Division' + put: + tags: + - Division + summary: Edit division + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + name: + type: string + desc: + type: string + required: + - user + - name + - desc + responses: + '200': + description: Updated division + content: + application/json: + schema: + $ref: '#/components/schemas/Division' + + /mobile/division/{id}/detail: + get: + tags: + - Division + summary: Get division one feature + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [jumlah, today-task, new-file, new-discussion, check-member, check-admin] + responses: + '200': + description: Feature data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + put: + tags: + - Division + summary: Update status admin division + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + id: + type: string + isAdmin: + type: boolean + required: + - user + - id + - isAdmin + responses: + '200': + description: Status updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + post: + tags: + - Division + summary: Add members to division + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DivisionMemberBody' + responses: + '200': + description: Members added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Division + summary: Delete member from division + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + id: + type: string + required: + - user + - id + responses: + '200': + description: Member deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/division/{id}/status: + post: + tags: + - Division + summary: Update status division + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + isActive: + type: boolean + required: + - user + - isActive + responses: + '200': + description: Status updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/division/{id}/member: + get: + tags: + - Division + summary: Get division members + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + responses: + '200': + description: List of members + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + + /mobile/division/report: + get: + tags: + - Division + summary: Get division report + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [table-progress, lainnya] + - name: date + in: query + required: true + schema: + type: string + - name: date-end + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + - name: group + in: query + schema: + type: string + responses: + '200': + description: Report data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/division/more: + get: + tags: + - Division + summary: Get list division by id division + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + responses: + '200': + description: List of divisions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Division' + + # Discussion + /mobile/discussion: + get: + tags: + - Discussion + summary: Get discussions + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: active + in: query + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of discussions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Discussion' + post: + tags: + - Discussion + summary: Create discussion + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionCreateBody' + responses: + '200': + description: Created discussion + content: + application/json: + schema: + $ref: '#/components/schemas/Discussion' + + /mobile/discussion/{id}: + get: + tags: + - Discussion + summary: Get one discussion + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [data, comment] + responses: + '200': + description: Discussion details + content: + application/json: + schema: + $ref: '#/components/schemas/Discussion' + post: + tags: + - Discussion + summary: Edit discussion + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionEditBody' + responses: + '200': + description: Updated discussion + content: + application/json: + schema: + $ref: '#/components/schemas/Discussion' + put: + tags: + - Discussion + summary: Archive discussion + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + active: + type: boolean + required: + - user + - active + responses: + '200': + description: Archived + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Discussion + summary: Open/close discussion + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + status: + type: integer + required: + - user + - status + responses: + '200': + description: Status updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/discussion/{id}/comment: + post: + tags: + - Discussion + summary: Send comment to discussion + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DiscussionCommentBody' + responses: + '200': + description: Comment added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Calendar + /mobile/calendar: + get: + tags: + - Calendar + summary: Get calendar by date and division + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: date + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + responses: + '200': + description: Calendar events + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Calendar' + post: + tags: + - Calendar + summary: Create calendar event + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CalendarCreateBody' + responses: + '200': + description: Created event + content: + application/json: + schema: + $ref: '#/components/schemas/Calendar' + + /mobile/calendar/indicator: + get: + tags: + - Calendar + summary: Get calendar indicator + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: date + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + responses: + '200': + description: Indicators + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/calendar/{id}: + get: + tags: + - Calendar + summary: Get one calendar event + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [data, member] + responses: + '200': + description: Event details + content: + application/json: + schema: + $ref: '#/components/schemas/Calendar' + put: + tags: + - Calendar + summary: Update calendar event + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + desc: + type: string + timeStart: + type: string + timeEnd: + type: string + dateStart: + type: string + repeatEventTyper: + type: string + repeatValue: + type: number + linkMeet: + type: string + user: + type: string + required: + - title + - desc + - timeStart + - timeEnd + - dateStart + - repeatEventTyper + - repeatValue + - linkMeet + - user + responses: + '200': + description: Updated event + content: + application/json: + schema: + $ref: '#/components/schemas/Calendar' + delete: + tags: + - Calendar + summary: Delete calendar event + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/calendar/{id}/member: + post: + tags: + - Calendar + summary: Add members to calendar + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DivisionMemberBody' + responses: + '200': + description: Members added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Calendar + summary: Delete member from calendar + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idUser: + type: string + required: + - user + - idUser + responses: + '200': + description: Member deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/calendar/history: + get: + tags: + - Calendar + summary: Get calendar history + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: History + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Calendar' + + # Task + /mobile/task: + get: + tags: + - Task + summary: Get tasks + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: status + in: query + required: true + schema: + type: string + - name: division + in: query + required: true + schema: + type: string + - name: search + in: query + required: true + schema: + type: string + - name: page + in: query + schema: + type: integer + responses: + '200': + description: List of tasks + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Task' + post: + tags: + - Task + summary: Create task + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/TaskCreateBody' + responses: + '200': + description: Created task + content: + application/json: + schema: + $ref: '#/components/schemas/Task' + + /mobile/task/{id}: + get: + tags: + - Task + summary: Get one task + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + required: true + schema: + type: string + enum: [data, progress, task, file, member, link] + responses: + '200': + description: Task details + content: + application/json: + schema: + $ref: '#/components/schemas/Task' + put: + tags: + - Task + summary: Edit task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + user: + type: string + required: + - title + - user + responses: + '200': + description: Updated task + content: + application/json: + schema: + $ref: '#/components/schemas/Task' + post: + tags: + - Task + summary: Create task tugas + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TaskTugasCreateBody' + responses: + '200': + description: Created tugas + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Task + summary: Cancel task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + reason: + type: string + required: + - user + - reason + responses: + '200': + description: Canceled + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/task/{id}/lainnya: + put: + tags: + - Task + summary: Report task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + report: + type: string + user: + type: string + required: + - report + - user + responses: + '200': + description: Report added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Task + summary: Delete task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/task/detail/{id}: + get: + tags: + - Task + summary: Get task tugas + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: user + in: query + required: true + schema: + type: string + - name: cat + in: query + schema: + type: string + responses: + '200': + description: Tugas details + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + put: + tags: + - Task + summary: Update status task division + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectUpdateStatusBody' + responses: + '200': + description: Status updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + post: + tags: + - Task + summary: Edit task tugas + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TaskTugasCreateBody' + responses: + '200': + description: Tugas updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Task + summary: Delete task tugas + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idProject: + type: string + required: + - user + - idProject + responses: + '200': + description: Deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/task/{id}/member: + post: + tags: + - Task + summary: Add members to task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TaskMemberBody' + responses: + '200': + description: Members added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Task + summary: Delete member from task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idUser: + type: string + required: + - user + - idUser + responses: + '200': + description: Member deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/task/{id}/link: + post: + tags: + - Task + summary: Add link to task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + link: + type: string + idDivision: + type: string + required: + - user + - link + - idDivision + responses: + '200': + description: Link added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Task + summary: Delete link from task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + idLink: + type: string + required: + - user + - idLink + responses: + '200': + description: Link deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + /mobile/task/file/{id}: + post: + tags: + - Task + summary: Add file to task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: File added + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + put: + tags: + - Task + summary: Check/update file in task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: File updated + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - Task + summary: Delete file from task + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + required: + - user + responses: + '200': + description: File deleted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + + # Document + /mobile/document: + get: + tags: + - Document + summary: Get documents + parameters: + - name: user + in: query + required: true + schema: + type: string + - name: path + in: query + required: true + schema: + type: string + - name: division + in: query + required: \ No newline at end of file diff --git a/downloads/dataMessage.json b/downloads/dataMessage.json deleted file mode 100644 index 5ca3190..0000000 --- a/downloads/dataMessage.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "from": "6289505046093@c.us", - "fromMe": false, - "body": "halo gaes", - "hasMedia": false, - "type": "chat", - "to": "6289697338821@c.us", - "deviceType": "android", - "media": { - "data": null, - "mimetype": null, - "filename": null, - "filesize": null - }, - "notifyName": "jenna ai" -} \ No newline at end of file diff --git a/downloads/fullChat.json b/downloads/fullChat.json deleted file mode 100644 index 4f4be69..0000000 --- a/downloads/fullChat.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "_data": { - "id": { - "fromMe": false, - "remote": "6289505046093@c.us", - "id": "AC240D892DE952C48F68249C8D3CAF65", - "_serialized": "false_6289505046093@c.us_AC240D892DE952C48F68249C8D3CAF65" - }, - "viewed": false, - "body": "halo gaes", - "type": "chat", - "t": 1760499333, - "clientReceivedTsMillis": 1760499331816, - "notifyName": "jenna ai", - "from": "6289505046093@c.us", - "to": "6289697338821@c.us", - "ack": 1, - "invis": false, - "isNewMsg": true, - "star": false, - "kicNotified": false, - "recvFresh": true, - "isFromTemplate": false, - "thumbnail": "", - "richPreviewType": 0, - "faviconMMSMetadata": null, - "pollInvalidated": false, - "isSentCagPollCreation": false, - "latestEditMsgKey": null, - "latestEditSenderTimestampMs": null, - "mentionedJidList": [], - "groupMentions": [], - "isEventCanceled": false, - "eventInvalidated": false, - "isVcardOverMmsDocument": false, - "questionReplyQuotedMessage": null, - "questionResponsesCount": 0, - "readQuestionResponsesCount": 0, - "hasReaction": false, - "ephemeralDuration": 86400, - "ephemeralSettingTimestamp": 1760421708, - "disappearingModeInitiator": "chat", - "disappearingModeTrigger": "chat_settings", - "disappearingModeInitiatedByMe": false, - "viewMode": "VISIBLE", - "messageSecret": { - "0": 120, - "1": 16, - "2": 223, - "3": 31, - "4": 255, - "5": 95, - "6": 54, - "7": 23, - "8": 5, - "9": 170, - "10": 126, - "11": 183, - "12": 142, - "13": 88, - "14": 30, - "15": 251, - "16": 81, - "17": 183, - "18": 16, - "19": 69, - "20": 158, - "21": 252, - "22": 148, - "23": 155, - "24": 40, - "25": 5, - "26": 20, - "27": 210, - "28": 140, - "29": 42, - "30": 6, - "31": 123 - }, - "inviteGrpType": "DEFAULT", - "productHeaderImageRejected": false, - "lastPlaybackProgress": 0, - "isDynamicReplyButtonsMsg": false, - "isCarouselCard": false, - "parentMsgId": null, - "callSilenceReason": null, - "isVideoCall": false, - "callDuration": null, - "callCreator": null, - "callParticipants": null, - "isCallLink": null, - "callLinkToken": null, - "isMdHistoryMsg": false, - "stickerSentTs": 0, - "isAvatar": false, - "lastUpdateFromServerTs": 0, - "invokedBotWid": null, - "bizBotType": null, - "botResponseTargetId": null, - "botPluginType": null, - "botPluginReferenceIndex": null, - "botPluginSearchProvider": null, - "botPluginSearchUrl": null, - "botPluginSearchQuery": null, - "botPluginMaybeParent": false, - "botReelPluginThumbnailCdnUrl": null, - "botMessageDisclaimerText": null, - "botMsgBodyType": null, - "reportingTokenInfo": { - "reportingToken": { - "0": 75, - "1": 111, - "2": 0, - "3": 170, - "4": 128, - "5": 198, - "6": 97, - "7": 213, - "8": 204, - "9": 150, - "10": 169, - "11": 92, - "12": 233, - "13": 114, - "14": 228, - "15": 203 - }, - "version": 2, - "reportingTag": { - "0": 1, - "1": 11, - "2": 67, - "3": 48, - "4": 159, - "5": 94, - "6": 8, - "7": 153, - "8": 152, - "9": 19, - "10": 22, - "11": 148, - "12": 143, - "13": 89, - "14": 9, - "15": 64, - "16": 248, - "17": 149, - "18": 74, - "19": 64 - } - }, - "requiresDirectConnection": null, - "bizContentPlaceholderType": null, - "hostedBizEncStateMismatch": false, - "senderOrRecipientAccountTypeHosted": false, - "placeholderCreatedWhenAccountIsHosted": false, - "galaxyFlowDisabled": false, - "groupHistoryBundleMessageKey": null, - "groupHistoryBundleMetadata": null, - "links": [] - }, - "id": { - "fromMe": false, - "remote": "6289505046093@c.us", - "id": "AC240D892DE952C48F68249C8D3CAF65", - "_serialized": "false_6289505046093@c.us_AC240D892DE952C48F68249C8D3CAF65" - }, - "ack": 1, - "hasMedia": false, - "body": "halo gaes", - "type": "chat", - "timestamp": 1760499333, - "from": "6289505046093@c.us", - "to": "6289697338821@c.us", - "deviceType": "android", - "forwardingScore": 0, - "isStatus": false, - "isStarred": false, - "fromMe": false, - "hasQuotedMsg": false, - "hasReaction": false, - "vCards": [], - "mentionedIds": [], - "groupMentions": [], - "isGif": false, - "links": [] -} \ No newline at end of file diff --git a/downloads/media.json b/downloads/media.json deleted file mode 100644 index 985ae5a..0000000 --- a/downloads/media.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "_data": { - "id": { - "fromMe": false, - "remote": "6289505046093@c.us", - "id": "AC1FCF4C63F9B86F93313AAEC7EC5AE5", - "_serialized": "false_6289505046093@c.us_AC1FCF4C63F9B86F93313AAEC7EC5AE5" - }, - "viewed": false, - "body": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEABsbGxscGx4hIR4qLSgtKj04MzM4PV1CR0JHQl2NWGdYWGdYjX2Xe3N7l33gsJycsOD/2c7Z//////////////8BGxsbGxwbHiEhHiotKC0qPTgzMzg9XUJHQkdCXY1YZ1hYZ1iNfZd7c3uXfeCwnJyw4P/Zztn////////////////CABEIADwAIQMBIgACEQEDEQH/xAAuAAADAQEBAQAAAAAAAAAAAAAAAwQCBQEGAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAOtUim5zh/qzFIcWnm3xczjuOoSC/LYkLHsl0WEYOJdj8JoXJUH/xAAlEAACAQIFBAMBAAAAAAAAAAABAgADEQQSEyFREBQxQSIyUmH/2gAIAQEAAT8Aoow+LGaZ5mn/AGGgD5M7ZeeibqJbqMaL2KxMaoNrbRcRSbw0V1bwb9HRTUFvZmgqreZ6ak7i0SsFU5CJ3MoYrTDFtz6jYmqxPzIBmc8xXb0016v7nqXgm83jUXdjZReDCVPewgw1Q+CI1Kqm5E1W4mZuTNR7fYzO36MpVX8Xm3An/8QAFxEBAQEBAAAAAAAAAAAAAAAAEQABMP/aAAgBAgEBPwB2Z3iX/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARMP/aAAgBAwEBPwACyw463//Z", - "type": "image", - "t": 1760499162, - "clientReceivedTsMillis": 1760499161349, - "notifyName": "jenna ai", - "from": "6289505046093@c.us", - "to": "6289697338821@c.us", - "ack": 1, - "invis": false, - "isNewMsg": true, - "star": false, - "kicNotified": false, - "recvFresh": true, - "interactiveAnnotations": [], - "deprecatedMms3Url": "https://mmg.whatsapp.net/v/t62.7118-24/565618455_32971919975740209_8438009621194429801_n.enc?ccb=11-4&oh=01_Q5Aa2wEh_OAabe-vO_8PiWdXDveV3I7vgykLw6MjCihpQdmq7w&oe=69169DCC&_nc_sid=5e03e0&mms3=true", - "directPath": "/v/t62.7118-24/565618455_32971919975740209_8438009621194429801_n.enc?ccb=11-4&oh=01_Q5Aa2wEh_OAabe-vO_8PiWdXDveV3I7vgykLw6MjCihpQdmq7w&oe=69169DCC&_nc_sid=5e03e0", - "mimetype": "image/jpeg", - "filehash": "IveoyrubZqm4f8VrvH5lU9zN/M6kXddXM6GchNIoBf8=", - "encFilehash": "LP/NA3twuiOjLyl7bnq6Tavsu7MT0hKa2v0/ts0wkzI=", - "size": 47276, - "mediaKey": "7eEyqrxGDsJXoGIBxbmeo2PdbO0T+I8KcSqZWJmfvLo=", - "mediaKeyTimestamp": 1760498519, - "isViewOnce": false, - "width": 720, - "height": 1280, - "staticUrl": "", - "scanLengths": [ - 7339, - 17711, - 7801, - 14425 - ], - "scansSidecar": {}, - "isFromTemplate": false, - "pollInvalidated": false, - "isSentCagPollCreation": false, - "latestEditMsgKey": null, - "latestEditSenderTimestampMs": null, - "mentionedJidList": [], - "groupMentions": [], - "isEventCanceled": false, - "eventInvalidated": false, - "statusMentioned": false, - "isVcardOverMmsDocument": false, - "questionReplyQuotedMessage": null, - "questionResponsesCount": 0, - "readQuestionResponsesCount": 0, - "hasReaction": false, - "ephemeralDuration": 86400, - "ephemeralSettingTimestamp": 1760421708, - "disappearingModeInitiator": "chat", - "disappearingModeTrigger": "chat_settings", - "disappearingModeInitiatedByMe": false, - "viewMode": "VISIBLE", - "messageSecret": { - "0": 29, - "1": 141, - "2": 90, - "3": 218, - "4": 12, - "5": 186, - "6": 69, - "7": 134, - "8": 140, - "9": 175, - "10": 233, - "11": 234, - "12": 147, - "13": 5, - "14": 112, - "15": 20, - "16": 135, - "17": 4, - "18": 190, - "19": 145, - "20": 68, - "21": 243, - "22": 86, - "23": 109, - "24": 9, - "25": 235, - "26": 250, - "27": 31, - "28": 255, - "29": 149, - "30": 147, - "31": 124 - }, - "productHeaderImageRejected": false, - "lastPlaybackProgress": 0, - "isDynamicReplyButtonsMsg": false, - "isCarouselCard": false, - "parentMsgId": null, - "callSilenceReason": null, - "isVideoCall": false, - "callDuration": null, - "callCreator": null, - "callParticipants": null, - "isCallLink": null, - "callLinkToken": null, - "isMdHistoryMsg": false, - "stickerSentTs": 0, - "isAvatar": false, - "lastUpdateFromServerTs": 0, - "invokedBotWid": null, - "bizBotType": null, - "botResponseTargetId": null, - "botPluginType": null, - "botPluginReferenceIndex": null, - "botPluginSearchProvider": null, - "botPluginSearchUrl": null, - "botPluginSearchQuery": null, - "botPluginMaybeParent": false, - "botReelPluginThumbnailCdnUrl": null, - "botMessageDisclaimerText": null, - "botMsgBodyType": null, - "reportingTokenInfo": { - "reportingToken": { - "0": 22, - "1": 36, - "2": 226, - "3": 57, - "4": 30, - "5": 125, - "6": 123, - "7": 89, - "8": 148, - "9": 96, - "10": 59, - "11": 132, - "12": 196, - "13": 230, - "14": 192, - "15": 44 - }, - "version": 2, - "reportingTag": { - "0": 1, - "1": 11, - "2": 216, - "3": 114, - "4": 105, - "5": 176, - "6": 57, - "7": 186, - "8": 62, - "9": 102, - "10": 166, - "11": 62, - "12": 206, - "13": 161, - "14": 215, - "15": 245, - "16": 83, - "17": 227, - "18": 232, - "19": 76 - } - }, - "requiresDirectConnection": null, - "bizContentPlaceholderType": null, - "hostedBizEncStateMismatch": false, - "senderOrRecipientAccountTypeHosted": false, - "placeholderCreatedWhenAccountIsHosted": false, - "galaxyFlowDisabled": false, - "groupHistoryBundleMessageKey": null, - "groupHistoryBundleMetadata": null, - "links": [] - }, - "mediaKey": "7eEyqrxGDsJXoGIBxbmeo2PdbO0T+I8KcSqZWJmfvLo=", - "id": { - "fromMe": false, - "remote": "6289505046093@c.us", - "id": "AC1FCF4C63F9B86F93313AAEC7EC5AE5", - "_serialized": "false_6289505046093@c.us_AC1FCF4C63F9B86F93313AAEC7EC5AE5" - }, - "ack": 1, - "hasMedia": true, - "body": "", - "type": "image", - "timestamp": 1760499162, - "from": "6289505046093@c.us", - "to": "6289697338821@c.us", - "deviceType": "android", - "forwardingScore": 0, - "isStatus": false, - "isStarred": false, - "fromMe": false, - "hasQuotedMsg": false, - "hasReaction": false, - "vCards": [], - "mentionedIds": [], - "groupMentions": [], - "isGif": false, - "links": [] -} \ No newline at end of file diff --git a/package.json b/package.json index b43155f..d0ee594 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,12 @@ "@types/lodash": "^4.17.20", "@types/qrcode-terminal": "^0.12.2", "add": "^2.0.6", + "colors": "^1.4.0", "elysia": "^1.4.11", + "form-data": "^4.0.4", "jwt-decode": "^4.0.0", "lodash": "^4.17.21", + "node-fetch": "^3.3.2", "qrcode-terminal": "^0.12.0", "react": "^19.2.0", "react-dom": "^19.2.0", diff --git a/proposal.md b/proposal.md new file mode 100644 index 0000000..10eb56f --- /dev/null +++ b/proposal.md @@ -0,0 +1,76 @@ + +PROPOSAL PEMEKARAN TIM DIVISI PENGEMBANGAN +Proyek: Jenna AI – Lalu Lintas Badung & Jenna Darmasaba +Lokasi: Kuta / Badung, Bali +======================================================== + +### 1. LATAR BELAKANG +Dalam rangka mendukung pengembangan dan ekspansi proyek **Jenna AI** pada dua wilayah operasional, yaitu **Lalu Lintas Badung** dan **Jenna Darmasaba**, diperlukan pemekaran pada tim **Divisi Pengembangan (Developer)**. +Pemekaran ini bertujuan untuk memperkuat kapasitas teknis, mempercepat inovasi fitur, memastikan kestabilan sistem, serta meningkatkan kualitas integrasi antara platform WhatsApp, AI Engine, dan infrastruktur pendukung yang digunakan Jenna AI. + +--- + +### 2. TUJUAN PEMEKARAN +- Memperluas kapabilitas tim dalam pengembangan sistem berbasis AI, NLP, dan integrasi real-time. +- Meningkatkan kecepatan pengembangan dan keandalan (reliability) sistem Jenna di dua wilayah operasional. +- Mempersiapkan tim teknis yang mampu menjaga skalabilitas, keamanan, dan performa sistem. +- Menjamin kesinambungan inovasi pada produk Jenna, termasuk optimalisasi model AI dan pengelolaan LLM (Large Language Model) Ops. + +--- + +### 3. STRUKTUR DAN KOMPONEN TIM +Berikut adalah susunan personel untuk **Divisi Pengembangan (Developer)** hasil pemekaran, disesuaikan dengan kebutuhan proyek di Bali: + +| Posisi | Jumlah | Gaji / Bulan (IDR) | Subtotal | +|--------|---------|--------------------|-----------| +| Technical Lead / Architect | 1 | 60.000.000 | 60.000.000 | +| Backend Engineer | 3 | 27.000.000 | 81.000.000 | +| Frontend Engineer | 2 | 25.000.000 | 50.000.000 | +| Mobile Engineer | 1 | 27.000.000 | 27.000.000 | +| DevOps / SRE | 1 | 35.000.000 | 35.000.000 | +| AI / ML Engineer | 2 | 40.000.000 | 80.000.000 | +| NLP / Conversational Engineer | 1 | 40.000.000 | 40.000.000 | +| Data Engineer | 1 | 35.000.000 | 35.000.000 | +| UI/UX Designer | 1 | 20.000.000 | 20.000.000 | +| Intern / Junior Developer | 2 | 6.000.000 | 12.000.000 | +| **TOTAL** | **12 Orang** | | **Rp 440.000.000 / bulan** | + +--- + +### 4. ESTIMASI BIAYA PENDUKUNG +Tambahan biaya untuk benefit, tools, dan kontinjensi operasional: + +| Komponen | Persentase | Estimasi / Bulan (IDR) | +|-----------|-------------|-------------------------| +| Benefit (BPJS, tunjangan, alat kerja, software, coworking, pelatihan) | +20% | 88.000.000 | +| Kontinjensi (freelance tambahan, overtime, training AI, upgrade infrastruktur) | +15% | 66.000.000 | +| **TOTAL ESTIMASI BULANAN (All-In)** | | **Rp 594.000.000** | + +--- + +### 5. ESTIMASI BIAYA TAHUNAN +| Komponen | Estimasi / Tahun (IDR) | +|-----------|------------------------| +| Base Gaji Tahunan | 5.280.000.000 | +| Dengan Benefit & Tools (20%) | 6.336.000.000 | +| Dengan Kontinjensi (Total) | **7.128.000.000** | + +--- + +### 6. CATATAN DAN PERTIMBANGAN +- Estimasi ini menggunakan skenario **maksimum realistis** untuk wilayah Bali (Kuta/Badung). +- Posisi AI Engineer, DevOps, dan Architect mengikuti standar nasional karena keterbatasan talenta di area lokal. +- Struktur ini mencakup seluruh kompetensi inti pengembangan: backend, frontend, mobile, AI/NLP, data pipeline, DevOps, serta UI/UX. +- Pemekaran ini diharapkan mampu mempercepat siklus pengembangan, menjaga stabilitas sistem lintas wilayah, serta memperkuat posisi Jenna AI sebagai platform layanan berbasis kecerdasan buatan yang andal. + +--- + +### 7. PENUTUP +Dengan mempertimbangkan peningkatan skala operasi, kompleksitas teknis, serta roadmap pengembangan AI Jenna, pemekaran tim **Divisi Pengembangan** ini menjadi langkah strategis untuk memastikan keberlanjutan dan daya saing sistem di masa depan. + +Estimasi di atas dapat dijadikan acuan dalam **pengajuan anggaran (budgeting)** serta **perencanaan sumber daya manusia** pada tahun berjalan. + +Disusun oleh: +**[Nama Penyusun]** +Divisi Teknologi & Pengembangan Jenna AI +Badung, Bali — 2025 diff --git a/src/server/lib/wa/wa_service.ts b/src/server/lib/wa/wa_service.ts index 12ef459..a18afd8 100644 --- a/src/server/lib/wa/wa_service.ts +++ b/src/server/lib/wa/wa_service.ts @@ -5,11 +5,19 @@ import path from 'path'; import { v4 as uuid } from 'uuid'; import { prisma } from '../prisma'; import { getValueByPath } from '../get_value_by_path'; +import "colors" -// === KONFIGURASI UTAMA === const MEDIA_DIR = path.join(process.cwd(), 'downloads'); await ensureDir(MEDIA_DIR); +async function ensureDir(dir: string) { + try { + await fs.access(dir); + } catch { + await fs.mkdir(dir, { recursive: true }); + } +} + type DataMessage = { from: string; fromNumber: string; @@ -19,12 +27,7 @@ type DataMessage = { type: WAWebJS.MessageTypes; to: string; deviceType: string; - media: { - data: WAWebJS.MessageMedia["data"]; - mimetype: WAWebJS.MessageMedia["mimetype"]; - filename: WAWebJS.MessageMedia["filename"]; - filesize: WAWebJS.MessageMedia["filesize"]; - }; + media: any[] | null; notifyName: string; } @@ -60,13 +63,6 @@ function log(...args: any[]) { console.log(`[${new Date().toISOString()}]`, ...args); } -async function ensureDir(dir: string) { - try { - await fs.access(dir); - } catch { - await fs.mkdir(dir, { recursive: true }); - } -} async function safeRm(path: string) { try { @@ -95,6 +91,8 @@ async function destroyClient() { } } +let connectedAt: number | null = null; + // === PEMBUATAN CLIENT === async function startClient() { if (state.isStarting || state.isReconnecting) { @@ -131,6 +129,7 @@ async function startClient() { }); client.on('ready', () => { + connectedAt = Date.now(); log('✅ WhatsApp client siap digunakan!'); state.ready = true; state.isReconnecting = false; @@ -177,17 +176,32 @@ async function startClient() { } } +function detectFileCategory(mime: string) { + if (mime.startsWith("image/")) return "image"; + if (mime.startsWith("audio/")) return "audio"; + if (mime.startsWith("video/")) return "video"; + if (mime === "application/pdf") return "pdf"; + if (mime.includes("spreadsheet") || mime.includes("excel")) return "excel"; + if (mime.includes("word")) return "document"; + if (mime.includes("presentation") || mime.includes("powerpoint")) return "presentation"; + return "file"; +} + // === HANDLER PESAN MASUK === async function handleIncomingMessage(msg: WAWebJS.Message) { + const chat = await msg.getChat(); + await chat.sendStateTyping(); log(`💬 Pesan dari ${msg.from}: ${msg.body || '[MEDIA]'}`); + + if (!connectedAt) return; + if (msg.timestamp * 1000 < connectedAt) return; + if (msg.from.endsWith('@g.us') || msg.isStatus || msg.from === 'status@broadcast') { log(`🚫 Pesan dari grup/status diabaikan (${msg.from})`); return; } try { - - const body = msg.body?.toLowerCase().trim() || ''; const notifyName = (msg as any)._data.notifyName; const dataMessage: DataMessage = { @@ -199,32 +213,32 @@ async function handleIncomingMessage(msg: WAWebJS.Message) { type: msg.type, to: msg.to, deviceType: msg.deviceType, - media: { - data: null as unknown as WAWebJS.MessageMedia['data'], - mimetype: null as unknown as WAWebJS.MessageMedia['mimetype'], - filename: null as unknown as WAWebJS.MessageMedia['filename'], - filesize: null as unknown as WAWebJS.MessageMedia['filesize'], - - }, + media: null, notifyName, }; - // Media handler + // === HANDLE MEDIA === if (msg.hasMedia) { const media = await msg.downloadMedia(); - dataMessage.media = { - data: media.data, - mimetype: media.mimetype, - filename: media.filename, - filesize: media.filesize - }; + // Pastikan formatnya data:;base64, + const mime = media.mimetype || 'application/octet-stream'; + const prefixedBase64 = `data:${mime};base64,${media.data}`; + + dataMessage.media = [{ + type: "file:full", + data: prefixedBase64, + mime: mime, + name: media.filename || `${uuid()}.${mime.split('/')[1] || 'bin'}` + }]; + + // await fs.writeFile(path.join(MEDIA_DIR, dataMessage.media[0].name), Buffer.from(media.data, 'base64')); + } - // to web hook + // === KIRIM KE WEBHOOK === try { const webhooks = await prisma.webHook.findMany({ where: { enabled: true } }); - if (!webhooks.length) { log('🚫 Tidak ada webhook yang aktif'); return; @@ -233,8 +247,22 @@ async function handleIncomingMessage(msg: WAWebJS.Message) { await Promise.allSettled( webhooks.map(async (hook) => { try { - console.log("send webhook " + hook.url); - const body = payloadConverter({ payload: hook.payload ?? JSON.stringify(dataMessage), data: dataMessage }); + log(`🌐 Mengirim webhook ke ${hook.url}`); + + let body = payloadConverter({ + payload: hook.payload ?? JSON.stringify(dataMessage), + data: dataMessage, + }); + + if (dataMessage.hasMedia) { + const bodyMedia = JSON.parse(body); + bodyMedia.question = msg.body ?? dataMessage.media?.[0].mime; + bodyMedia.uploads = dataMessage.media; + body = JSON.stringify(bodyMedia); + } + + // await fs.writeFile(path.join(process.cwd(), 'webhook.json'), body); + const res = await fetch(hook.url, { method: hook.method, headers: { @@ -244,56 +272,58 @@ async function handleIncomingMessage(msg: WAWebJS.Message) { body, }); - if (!res.ok) log(`⚠️ Webhook ${hook.url} gagal: ${res.status}`); - const responseJson = await res.json(); + const responseText = await res.text(); + + if (!res.ok) { + log(`⚠️ Webhook ${hook.url} gagal: ${res.status}`); + log(responseText); + await msg.reply("Maaf, terjadi kesalahan saat memproses pesan Anda [ERR01]"); + return; + } + + const responseJson = JSON.parse(responseText); if (hook.replay) { try { - // === Simulasikan sedang mengetik === - const chat = await msg.getChat(); - await chat.sendStateTyping(); // tampilkan status 'sedang mengetik...' - - // Durasi delay tergantung panjang teks (lebih panjang = lebih lama) const textResponseRaw = hook.replayKey ? getValueByPath(responseJson, hook.replayKey, JSON.stringify(responseJson)) : JSON.stringify(responseJson, null, 2); - const typingDelay = Math.min(5000, Math.max(1500, textResponseRaw.length * 20)); // 1.5–5 detik - await new Promise((resolve) => setTimeout(resolve, typingDelay)); + const typingDelay = Math.min(5000, Math.max(1500, textResponseRaw.length * 20)); + await new Promise((r) => setTimeout(r, typingDelay)); - // Setelah delay, hentikan typing indicator - await chat.clearState(); // hilangkan status "mengetik..." - - // Kirim balasan ke pengirim - await msg.reply(textResponseRaw); + await chat.clearState(); + // send message + await chat.sendMessage(textResponseRaw); log(`💬 Balasan dikirim ke ${msg.from} setelah mengetik selama ${typingDelay}ms`); } catch (err) { log('⚠️ Gagal menampilkan status mengetik:', err); - await msg.reply(hook.replayKey - ? getValueByPath(responseJson, hook.replayKey, JSON.stringify(responseJson)) - : JSON.stringify(responseJson, null, 2) - ); + await msg.reply("Maaf, terjadi kesalahan saat memproses pesan Anda [ERR03]"); } } - } catch (err) { log(`❌ Gagal kirim ke ${hook.url}:`, err); + await msg.reply("Maaf, terjadi kesalahan saat memproses pesan Anda [ERR04]"); } }) ); - } catch (error) { - console.log(error); + log('❌ Error mengirim webhook:', error); + await msg.reply("Maaf, terjadi kesalahan saat memproses pesan Anda [ERR05]"); } } catch (err) { log('❌ Error handling pesan:', err); + await msg.reply("Maaf, terjadi kesalahan saat memproses pesan Anda [ERR06]"); + } finally { + await chat.clearState(); } } + function payloadConverter({ payload, data }: { payload: string; data: DataMessage }) { try { - const map: Record = { + const map: Record = { 'data.from': data.from, 'data.fromNumber': data.fromNumber, 'data.fromMe': data.fromMe, @@ -303,19 +333,30 @@ function payloadConverter({ payload, data }: { payload: string; data: DataMessag 'data.to': data.to, 'data.deviceType': data.deviceType, 'data.notifyName': data.notifyName, - 'data.media.data': data.media?.data ?? null, - 'data.media.mimetype': data.media?.mimetype ?? null, - 'data.media.filename': data.media?.filename ?? null, - 'data.media.filesize': data.media?.filesize ?? 0, + 'data.media': data.media }; let result = payload; + for (const [key, value] of Object.entries(map)) { - result = result.replace(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), String(value ?? '')); + let safeValue: string; + + if (value === null || value === undefined) { + safeValue = ''; + } else if (typeof value === 'object') { + // Perbaikan di sini — objek seperti media dikonversi ke JSON string + safeValue = JSON.stringify(value); + } else { + safeValue = String(value); + } + + result = result.replace(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), safeValue); } + return result; - } catch { - return JSON.stringify(data, null, 2); + } catch (err) { + console.error("⚠️ payloadConverter error:", err); + return JSON.stringify(data); } } diff --git a/src/server/lib/wa/wa_service.txt b/src/server/lib/wa/wa_service.txt new file mode 100644 index 0000000..12ef459 --- /dev/null +++ b/src/server/lib/wa/wa_service.txt @@ -0,0 +1,343 @@ +import WAWebJS, { Client, LocalAuth, MessageMedia } from 'whatsapp-web.js'; +import qrcode from 'qrcode-terminal'; +import fs from 'fs/promises'; +import path from 'path'; +import { v4 as uuid } from 'uuid'; +import { prisma } from '../prisma'; +import { getValueByPath } from '../get_value_by_path'; + +// === KONFIGURASI UTAMA === +const MEDIA_DIR = path.join(process.cwd(), 'downloads'); +await ensureDir(MEDIA_DIR); + +type DataMessage = { + from: string; + fromNumber: string; + fromMe: boolean; + body: string; + hasMedia: boolean; + type: WAWebJS.MessageTypes; + to: string; + deviceType: string; + media: { + data: WAWebJS.MessageMedia["data"]; + mimetype: WAWebJS.MessageMedia["mimetype"]; + filename: WAWebJS.MessageMedia["filename"]; + filesize: WAWebJS.MessageMedia["filesize"]; + }; + notifyName: string; +} + +// === STATE GLOBAL === +const state = { + client: null as Client | null, + reconnectTimeout: null as NodeJS.Timeout | null, + isReconnecting: false, + isStarting: false, + qr: null as string | null, + ready: false, + async restart() { + log('🔄 Restart manual diminta...'); + await destroyClient(); + await startClient(); + }, + + async forceStart() { + log('⚠️ Force start — menghapus cache dan session auth...'); + await destroyClient(); + await safeRm("./.wwebjs_auth"); + await safeRm("./wwebjs_cache"); + await startClient(); + }, + async stop() { + log('🛑 Stop manual diminta...'); + await destroyClient(); + }, +}; + +// === UTIL === +function log(...args: any[]) { + console.log(`[${new Date().toISOString()}]`, ...args); +} + +async function ensureDir(dir: string) { + try { + await fs.access(dir); + } catch { + await fs.mkdir(dir, { recursive: true }); + } +} + +async function safeRm(path: string) { + try { + await fs.rm(path, { recursive: true, force: true }); + } catch (err) { + log(`⚠️ Gagal hapus ${path}:`, err); + } +} + +// === CLEANUP CLIENT === +async function destroyClient() { + if (state.reconnectTimeout) { + clearTimeout(state.reconnectTimeout); + state.reconnectTimeout = null; + } + if (state.client) { + try { + state.client.removeAllListeners(); + await state.client.destroy(); + log('🧹 Client lama dihentikan & listener dibersihkan'); + } catch (err) { + log('⚠️ Gagal destroy client:', err); + } + state.client = null; + state.ready = false; + } +} + +// === PEMBUATAN CLIENT === +async function startClient() { + if (state.isStarting || state.isReconnecting) { + log('⏳ startClient diabaikan — proses sedang berjalan...'); + return; + } + state.isStarting = true; + + await destroyClient(); + + log('🚀 Memulai WhatsApp client...'); + const client = new Client({ + authStrategy: new LocalAuth({ + dataPath: path.join(process.cwd(), '.wwebjs_auth'), + }), + puppeteer: { + headless: true, + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage', + '--disable-gpu', + ], + }, + }); + + state.client = client; + + // === EVENT LISTENERS === + client.on('qr', (qr) => { + state.qr = qr; + qrcode.generate(qr, { small: true }); + log('🔑 QR code baru diterbitkan'); + }); + + client.on('ready', () => { + log('✅ WhatsApp client siap digunakan!'); + state.ready = true; + state.isReconnecting = false; + state.isStarting = false; + state.qr = null; + if (state.reconnectTimeout) { + clearTimeout(state.reconnectTimeout); + state.reconnectTimeout = null; + } + }); + + client.on('auth_failure', (msg) => { + log('❌ Autentikasi gagal:', msg); + state.ready = false; + }); + + client.on('disconnected', async (reason) => { + log('⚠️ Client terputus:', reason); + state.ready = false; + + if (state.reconnectTimeout) clearTimeout(state.reconnectTimeout); + log('⏳ Mencoba reconnect dalam 5 detik...'); + + state.reconnectTimeout = setTimeout(async () => { + state.isReconnecting = false; + await startClient(); + }, 5000); + }); + + client.on('message', handleIncomingMessage); + + // === INISIALISASI === + try { + await client.initialize(); + } catch (err) { + log('❌ Gagal inisialisasi client:', err); + log('⏳ Mencoba reconnect dalam 10 detik...'); + state.reconnectTimeout = setTimeout(async () => { + state.isReconnecting = false; + await startClient(); + }, 10000); + } finally { + state.isStarting = false; + } +} + +// === HANDLER PESAN MASUK === +async function handleIncomingMessage(msg: WAWebJS.Message) { + log(`💬 Pesan dari ${msg.from}: ${msg.body || '[MEDIA]'}`); + if (msg.from.endsWith('@g.us') || msg.isStatus || msg.from === 'status@broadcast') { + log(`🚫 Pesan dari grup/status diabaikan (${msg.from})`); + return; + } + + try { + + const body = msg.body?.toLowerCase().trim() || ''; + const notifyName = (msg as any)._data.notifyName; + + const dataMessage: DataMessage = { + from: msg.from, + fromNumber: msg.from.split('@')[0] || '', + fromMe: msg.fromMe, + body: msg.body, + hasMedia: msg.hasMedia, + type: msg.type, + to: msg.to, + deviceType: msg.deviceType, + media: { + data: null as unknown as WAWebJS.MessageMedia['data'], + mimetype: null as unknown as WAWebJS.MessageMedia['mimetype'], + filename: null as unknown as WAWebJS.MessageMedia['filename'], + filesize: null as unknown as WAWebJS.MessageMedia['filesize'], + + }, + notifyName, + }; + + // Media handler + if (msg.hasMedia) { + const media = await msg.downloadMedia(); + + dataMessage.media = { + data: media.data, + mimetype: media.mimetype, + filename: media.filename, + filesize: media.filesize + }; + } + + // to web hook + try { + const webhooks = await prisma.webHook.findMany({ where: { enabled: true } }); + + if (!webhooks.length) { + log('🚫 Tidak ada webhook yang aktif'); + return; + } + + await Promise.allSettled( + webhooks.map(async (hook) => { + try { + console.log("send webhook " + hook.url); + const body = payloadConverter({ payload: hook.payload ?? JSON.stringify(dataMessage), data: dataMessage }); + const res = await fetch(hook.url, { + method: hook.method, + headers: { + ...(JSON.parse(hook.headers ?? '{}') as Record), + ...(hook.apiToken ? { Authorization: `Bearer ${hook.apiToken}` } : {}), + }, + body, + }); + + if (!res.ok) log(`⚠️ Webhook ${hook.url} gagal: ${res.status}`); + const responseJson = await res.json(); + + if (hook.replay) { + try { + // === Simulasikan sedang mengetik === + const chat = await msg.getChat(); + await chat.sendStateTyping(); // tampilkan status 'sedang mengetik...' + + // Durasi delay tergantung panjang teks (lebih panjang = lebih lama) + const textResponseRaw = hook.replayKey + ? getValueByPath(responseJson, hook.replayKey, JSON.stringify(responseJson)) + : JSON.stringify(responseJson, null, 2); + + const typingDelay = Math.min(5000, Math.max(1500, textResponseRaw.length * 20)); // 1.5–5 detik + await new Promise((resolve) => setTimeout(resolve, typingDelay)); + + // Setelah delay, hentikan typing indicator + await chat.clearState(); // hilangkan status "mengetik..." + + // Kirim balasan ke pengirim + await msg.reply(textResponseRaw); + + log(`💬 Balasan dikirim ke ${msg.from} setelah mengetik selama ${typingDelay}ms`); + } catch (err) { + log('⚠️ Gagal menampilkan status mengetik:', err); + await msg.reply(hook.replayKey + ? getValueByPath(responseJson, hook.replayKey, JSON.stringify(responseJson)) + : JSON.stringify(responseJson, null, 2) + ); + } + } + + } catch (err) { + log(`❌ Gagal kirim ke ${hook.url}:`, err); + } + }) + ); + + } catch (error) { + console.log(error); + } + } catch (err) { + log('❌ Error handling pesan:', err); + } +} + +function payloadConverter({ payload, data }: { payload: string; data: DataMessage }) { + try { + const map: Record = { + 'data.from': data.from, + 'data.fromNumber': data.fromNumber, + 'data.fromMe': data.fromMe, + 'data.body': data.body, + 'data.hasMedia': data.hasMedia, + 'data.type': data.type, + 'data.to': data.to, + 'data.deviceType': data.deviceType, + 'data.notifyName': data.notifyName, + 'data.media.data': data.media?.data ?? null, + 'data.media.mimetype': data.media?.mimetype ?? null, + 'data.media.filename': data.media?.filename ?? null, + 'data.media.filesize': data.media?.filesize ?? 0, + }; + + let result = payload; + for (const [key, value] of Object.entries(map)) { + result = result.replace(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), String(value ?? '')); + } + return result; + } catch { + return JSON.stringify(data, null, 2); + } +} + + +// === CLEANUP SAAT EXIT === +process.on('SIGINT', async () => { + log('🛑 SIGINT diterima, menutup client...'); + await destroyClient(); + process.exit(0); +}); + +process.on('SIGTERM', async () => { + log('🛑 SIGTERM diterima, menutup client...'); + await destroyClient(); + process.exit(0); +}); + + +const getState = () => state; + +export { startClient, destroyClient, getState }; + +if (import.meta.main) { + await startClient(); +} diff --git a/webhook.json b/webhook.json new file mode 100644 index 0000000..691904d --- /dev/null +++ b/webhook.json @@ -0,0 +1,14 @@ +{ + "question": "ini", + "overrideConfig": { + "sessionId": "jenna ai_x_6289505046093" + }, + "uploads": [ + { + "type": "file:full", + "data": "data:application/pdf;base64,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CjAKMTU1ClsKMzg2Cl0KMTU2CjE1OAowCjE1OQpbCjMwNgo0OTgKOTA1CjQ5OAowCjAKMzAzCjMwMwpdCjE2NwoxNzQKMAoxNzUKWwo0OTgKMAowCjY4MgpdCjE3OQoxOTAKMAoxOTEKMjAyCjUwNgoyMDMKMjIxCjAKMjIyClsKNDk4CjAKMAo0OTgKXQpdCj4+CmVuZG9iagozMAowCm9iago8PAovVHlwZQovRm9udERlc2NyaXB0b3IKL0ZvbnROYW1lCi9NVUZVWlkrQ2FsaWJyaQovRmxhZ3MKNAovRm9udEJCb3gKWwotOTcKLTE5Mwo4NTkKODQ2Cl0KL0FzY2VudAo3NTAKL0Rlc2NlbnQKLTI1MAovSXRhbGljQW5nbGUKMAovQ2FwSGVpZ2h0CjYzMQovU3RlbVYKODAKL0ZvbnRGaWxlMgozMQowClIKPj4KZW5kb2JqCjMyCjAKb2JqCjQzNAplbmRvYmoKMzMKMApvYmoKMTMwMjEKZW5kb2JqCjM0CjAKb2JqCjQ5OQplbmRvYmoKMzUKMApvYmoKMTkwMTYKZW5kb2JqCjEKMApvYmoKPDwKL1R5cGUKL1BhZ2VzCi9LaWRzClsKNQowClIKMTQKMApSCjE5CjAKUgpdCi9Db3VudAozCj4+CmVuZG9iagp4cmVmCjAgMzYKMDAwMDAwMDAwMiA2NTUzNSBmIAowMDAwMDQ4MTMzIDAwMDAwIG4gCjAwMDAwMDAwMDAgMDAwMDAgZiAKMDAwMDAwMDAxNiAwMDAwMCBuIAowMDAwMDAwMTQyIDAwMDAwIG4gCjAwMDAwMDAyMjkgMDAwMDAgbiAKMDAwMDAwMDM5NCAwMDAwMCBuIAowMDAwMDEyMDkwIDAwMDAwIG4gCjAwMDAwMDUxODMgMDAwMDAgbiAKMDAwMDAwNTIwMyAwMDAwMCBuIAowMDAwMDEyMDAwIDAwMDAwIG4gCjAwMDAwMTIwNTIgMDAwMDAgbiAKMDAwMDAxMjYyMCAwMDAwMCBuIAowMDAwMDEyNzY5IDAwMDAwIG4gCjAwMDAwMDUyMjIgMDAwMDAgbiAKMDAwMDAwNTM5MSAwMDAwMCBuIAowMDAwMDEyMjc2IDAwMDAwIG4gCjAwMDAwMTAwNTEgMDAwMDAgbiAKMDAwMDAxMDA3MiAwMDAwMCBuIAowMDAwMDEwMDkyIDAwMDAwIG4gCjAwMDAwMTAyNjEgMDAwMDAgbiAKMDAwMDAxMjQ0OCAwMDAwMCBuIAowMDAwMDExOTU5IDAwMDAwIG4gCjAwMDAwMTE5ODAgMDAwMDAgbiAKMDAwMDAyNjUyMCAwMDAwMCBuIAowMDAwMDEyOTEzIDAwMDAwIG4gCjAwMDAwMjcxOTEgMDAwMDAgbiAKMDAwMDAxMzQyMyAwMDAwMCBuIAowMDAwMDQ3MDU4IDAwMDAwIG4gCjAwMDAwMjczOTEgMDAwMDAgbiAKMDAwMDA0Nzg1NSAwMDAwMCBuIAowMDAwMDI3OTY2IDAwMDAwIG4gCjAwMDAwNDgwNDkgMDAwMDAgbiAKMDAwMDA0ODA2OSAwMDAwMCBuIAowMDAwMDQ4MDkxIDAwMDAwIG4gCjAwMDAwNDgxMTEgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZQozNgovUm9vdAozCjAKUgovSW5mbwo0CjAKUgo+PgpzdGFydHhyZWYKNDgyMDYKJSVFT0YK", + "mime": "application/pdf", + "name": "Dataset_Potensi_Desa.pdf" + } + ] +} \ No newline at end of file diff --git a/x.sh b/x.sh new file mode 100644 index 0000000..bb80b7b --- /dev/null +++ b/x.sh @@ -0,0 +1,8 @@ + +#!/bin/bash +TOKEN="EAALP22EWyC4BPv7XnK1xSaZCWccblEoJFbHzPZAf5mlp4678lSM7cqhQl1ExATf8abrOpinvvFF6U6ruK2FsJqIk8wg6DiUz2fc0NYfcwjon3ng7I3C5HSDQHecgTiJLUBxfZAcvE4IIlhks722jakXaJpojlByo8QJ0CEURtzwEU1guFq7YTX3Et0ZCkbhkdftZCOGmpUKFjL5w5nUdd26Nd58YrLVZCoT8NKhxpWFQZDZD" +curl -i -X POST \ + https://graph.facebook.com/v22.0/838757782652201/messages \ + -H 'Authorization: Bearer $TOKEN' \ + -H 'Content-Type: application/json' \ + -d '{ "messaging_product": "whatsapp", "to": "6289505046093", "type": "template", "template": { "name": "hello_world", "language": { "code": "en_US" } } }' \ No newline at end of file diff --git a/x.ts b/x.ts index 1475f06..f10e4fb 100644 --- a/x.ts +++ b/x.ts @@ -1,73 +1,33 @@ +async function query(data: any) { -/** - * Helper type to recursively generate all possible key paths up to 7 levels deep. - * Example: "media.data", "a.b.c.d.e.f.g" - */ - type NestedKeyOf = { - [K in keyof T & (string | number)]: T[K] extends Record - ? | `${Prev}${K}` - | `${Prev}${K}.${NestedKeyOf}` - : `${Prev}${K}`; - }[keyof T & (string | number)]; - - /** - * Safely get deep value by string path like "a.b.c[0].d" - */ - function getValueByPath< - T extends object, - P extends string, - R = unknown - >(obj: T, path: P, defaultValue?: R): any { - try { - return path - .replace(/\[(\w+)\]/g, '.$1') - .split('.') - .reduce((acc: any, key) => (acc != null ? acc[key] : undefined), obj) ?? defaultValue; - } catch { - return defaultValue; - } + const file = Buffer.from(await Bun.file("./downloads/billing-server-20-06-2024.pdf").arrayBuffer()).toString("base64"); + const base64File = `data:application/pdf;base64,${file}`; + + const fileObject = { + type: "file:full", + data: base64File, + mime: "application/pdf", + name: "billing-server-20-06-2024.pdf" } - - /** - * Safely set deep value by string path like "a.b.c[0].d" - */ - export function setValueByPath( - obj: T, - path: string, - value: any - ): void { - const keys = path.replace(/\[(\w+)\]/g, '.$1').split('.'); - let current: any = obj; - - for (let i = 0; i < keys.length - 1; i++) { - const key = keys[i]; - if (current[key as keyof typeof current] == null || typeof current[key as keyof typeof current] !== 'object') { - current[key as keyof typeof current] = isNaN(Number(keys[i + 1])) ? {} : []; + const response = await fetch( + "https://cloud-aiflow.wibudev.com/api/v1/prediction/4da85628-c638-43d3-9491-4cd0a7e6b1b8", + { + headers: { + Authorization: "Bearer v3WdPjn61bNDsEYCO5_LYPRs16ICKjpQE6lF60DjpNo", + "Content-Type": "application/json" + }, + method: "POST", + body: JSON.stringify({ + ...data, + uploads: [fileObject] + }) } - current = current[key as keyof typeof current]; - } - - current[keys[keys.length - 1] as keyof typeof current] = value; - } - + ); + const result = await response.text(); + return result; +} - const data = { - "from": "6289505046093@c.us", - "fromMe": false, - "body": "halo gaes", - "hasMedia": false, - "type": "chat", - "to": "6289697338821@c.us", - "deviceType": "android", - "media": { - "data": "image...", - "mimetype": null, - "filename": null, - "filesize": null - }, - "notifyName": "jenna ai" - } - const find = getValueByPath(data, "media.data") - - console.log(find) \ No newline at end of file +query({"question": "apa isi data ini ?"}).then((response) => { + console.log(response); +});