{"_id":"@aseansc-admin/sea-http","_rev":"22-fdfdd557aeeca70f7523dfbc1f411ffe","name":"@aseansc-admin/sea-http","dist-tags":{"latest":"0.11.2"},"versions":{"0.1.0":{"name":"@aseansc-admin/sea-http","version":"0.1.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.1.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"3e4e7129dff8cd74ae8e2db61c4b28ec5b96a900","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.1.0.tgz","fileCount":5,"integrity":"sha512-C5fu/5mCSrt/btAjH6rqxwAWU3+ATEB3UBwME9f45pf8TG5db4W5YDRjEwzgCrbIZFHRkSAHEYD7y7HmG0OT8A==","signatures":[{"sig":"MEYCIQC492bWxe7TESLTyLSYwOQDwjPxbfKzkEgTvbHvofyZfgIhAKuPwMyKdGyFBVzr75zoa3eKO+wKWfG0P7w8bRyn9gKI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58398},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"28fbdad403b094de1597618b4c7ac47f674af415","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.1.0_1778829702388_0.9466510507434795","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aseansc-admin/sea-http","version":"0.1.1","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.1.1","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"f41df503e9189b65ee462394fc2341dc5efe5ac6","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.1.1.tgz","fileCount":5,"integrity":"sha512-LFbE3QpDgk9MAlW5oaOytE6U7Xa/gSTgcLIwvBss0PGzgLhfqKkw0L9Fp0obdl82fzb4NV6Z0GLf+KquZxGmIw==","signatures":[{"sig":"MEUCIAuYIz+C7LL6VCZLwe4iY0KOva4UA7vN327gLSN2qoPvAiEAz6LQHrwkmk5mXON+r7Dk6LU4t7l+gWCWTbA5Jtq02wE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":66101},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"7b26c041ed72f6171984398a8e83f4e402fbe1ce","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.1.1_1778833402969_0.3015702549183208","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@aseansc-admin/sea-http","version":"0.1.2","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.1.2","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"89b8fb1a320e7968ab1b73be16cfcbbf223a7274","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.1.2.tgz","fileCount":5,"integrity":"sha512-Y3gjXBHQeuRppOAa4upkltiq1cUJ1tLqkIcY1JLyjs7Mc0Pnqt5X632wSbK1PphxCjZGd9WOjg0E4wPycN0wrQ==","signatures":[{"sig":"MEQCIHrzXHiXf2efk8x+Yc55YSpkQLgwDOvkVgGGfOi7o17eAiAWv/6P0/X4/9U45+OdVZcbER3XJ4fuDHvPz0peQ/7RRw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":67542},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"44afbffc4637e9fc4f751b50125f0423d69cca0a","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.1.2_1779174810364_0.742657535863753","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@aseansc-admin/sea-http","version":"0.1.3","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.1.3","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"df3717dfde6d017e3d0b182e4374cd38c7090ba6","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.1.3.tgz","fileCount":5,"integrity":"sha512-/j0wmpVT1v/FeqB1uh+AlH3scS81Z8UPG8GJLRs3wtQSmegQ80dqZu3yUh8Naj/54W2byUGX4zu0+vgSjt7LUA==","signatures":[{"sig":"MEUCIQCtk3oHYAGjQiNmL79qXBTnsbN8wA6eYXIC43jnBZ9I9wIgH0MkpXr91nvXbJPZp540vZ/AZtqmTN43bt/kVsa80fU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68512},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"c76225bc12f4e019783070afc9ce7e4008213ea0","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.1.3_1779176574447_0.8526491398601304","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@aseansc-admin/sea-http","version":"0.1.4","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.1.4","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"e079cc1222282f08852d53263655a9198e168afa","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.1.4.tgz","fileCount":5,"integrity":"sha512-J6tgwTOQBbs+8AtlQFqR3hrWyMcex2kFKed5SVMa6jnwIwADd/0MdJRiQOTICGQ0kTFCbxVdyBpYp8f3B5LUPg==","signatures":[{"sig":"MEQCIH/iRNaHJgmvgHrXycDwoL1znkL4JyaI2BNJDBaz7qPvAiA9oyBMyGvHUHDtxR7C/ITTwaMTXHtM+UHfV2ZC9a96JA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70960},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"11519f38daba9156c06e4da2eb2797e04fd9bb9c","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.1.4_1779181257053_0.7951121374981063","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@aseansc-admin/sea-http","version":"0.2.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.2.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"c3e98fe65c356467d369d928c9b75be9bd17537e","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.2.0.tgz","fileCount":6,"integrity":"sha512-G7rGE5VZRxasa2R1bh2XOI3XIob88ohQWPqVmnXqW65NaFBjFhh9YsF7YENLfUnM+WrVYt99ylfvYRfd954uQg==","signatures":[{"sig":"MEUCIQCrRR+MciYWQtq75J1A/zFpBr59h0gCyRITeA0Obs8yFgIgNBeZmofVr+zcGVXou6tebaHWQCgagKv0cHrgWHm7l3M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":72403},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"6c644272c9f20a0f340090ed039fed0978da25c8","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.2.0_1779354029312_0.919838569093103","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@aseansc-admin/sea-http","version":"0.3.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.3.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"576331eada5eb2d61f396ae59de6ed56abd155a0","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.3.0.tgz","fileCount":6,"integrity":"sha512-MZD2xNReSHhWgkzCXHauIfM9o3L3kWOvg5BN7eJsCeC4JXWI5wGkG15oeC2dtWwIu9WdKpaMO8QAzlW18lKekA==","signatures":[{"sig":"MEQCIBojkGQ6OG+iZ5n31KmLFFMFaCKKMrMtqCWaif/KSFUUAiAZonMLQRP7qPyBP3h/+le4hW7pyqvTsnFfP7aPAc2k9A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":121120},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"2946c9f1aa8a74a2763e5d9d5286c05599f8ca54","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.3.0_1779865691587_0.25897403700195043","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@aseansc-admin/sea-http","version":"0.3.1","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.3.1","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"75bab6d430ac256c0d0618efa449032c3ebf2b5b","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.3.1.tgz","fileCount":6,"integrity":"sha512-x16SqwIAJkL2FN3/Ca3N776xSx7YC5S4g2Q/eSqe9SV5XhzHKME7LlECWoJe93icQIlgo56Zuq2IWjc5ZmRmRg==","signatures":[{"sig":"MEUCIQCy62CSncQaLsj3JQPcKM/DqZJCDTy/vNYT80XFq+784wIgTIXqNqNwqXjIiyOuJc1HPNiXsawycBeUFrEu/j6/Zac=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":122223},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"df44671f7a0086cfc82fa8cc228484ae8e695b74","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.3.1_1779868000062_0.43774509498461134","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@aseansc-admin/sea-http","version":"0.4.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.4.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"f069c846d7a5abf43389db4f1de5ca192b3fc049","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.4.0.tgz","fileCount":9,"integrity":"sha512-fHbJmSuaYVuQz5lUjR5UXkiqZn4DD1kmFVe9F1CjifducRwokANMXl3ObMMv1V1B0h8YLjJc+eLUzMF2X0bqJA==","signatures":[{"sig":"MEYCIQC9XY2QO2aA5aiLgbBHvK9QtM73TwSOM2Fr4RT0kDYnKAIhALJLY7Y9P2W9lK3bTgAbudxfPGEJA02Y//lfZMGU/a2w","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":152016},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"61997b8a2ed6e78ee77e979692db69c5ab518699","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":">=2.0.0","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.4.0_1782179574557_0.6188472176726036","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@aseansc-admin/sea-http","version":"0.4.1","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.4.1","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"e7a0d8514a659ab56c0f9b272944a623ecaaa2d3","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.4.1.tgz","fileCount":9,"integrity":"sha512-ICOX9C59Q0AGkNQOQOWlzo9l0zpz3ICwNBDS/v3Kg3479COD/7AJyHagfttKB9v+CQpdwIHozN1o0247JxA/kg==","signatures":[{"sig":"MEUCIGoJS3o4NCT0lx46ovtG68auKNXr4CzUbNTJvRwcplNOAiEAsYhou/OREfYwfIBTQMFmucN+0Yk99rREKXiovF2MDUw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":153678},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"2af7b73043edf5ae3a04d1665f266955ba9c82b0","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.4.1_1782198912161_0.7383802967724111","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@aseansc-admin/sea-http","version":"0.4.2","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.4.2","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"f60ad03ddea50543e6f88d08de8917f872352b5c","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.4.2.tgz","fileCount":9,"integrity":"sha512-EdWHZYe3Cs5cXvT73MzFtcRLGLHC02kogMqWNKFyfmmG8G42lmL2kHbHcLZKTgYpuKQnFo02FuMM/szfP1+dzQ==","signatures":[{"sig":"MEUCIHa1A1bMWaLj4ZbbWgd+obxS3b265G55FD+082/P66gYAiEA+/MOZi9uJTU7P2ioOHIxMW/c+hO+kMKnU+aVlKwUDig=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":158104},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"7e6aa023f4a50f5a41025a08f20f9bf376b073c4","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.4.2_1782276974314_0.18851221916829264","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@aseansc-admin/sea-http","version":"0.5.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.5.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"c19de0c557b829ca941f4f446c1df04db99373c0","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.5.0.tgz","fileCount":9,"integrity":"sha512-ec8mCLizTiE6JdIpNl+tckA+fIbEHIyBfqfBWtqpx4HeKE7/WabV/CIn2St0iU+I772ng3xVDtfa/Iw1lB1bVw==","signatures":[{"sig":"MEQCICdO+5On0qfITJ2v1HZsH4fYjgzjlqwCt+M02SbnRTsuAiBlK1XzFZpbytWwRwsor8F2vjeZ6tGqqByFs+/+Wbc+gQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":173565},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"a9e2a71b405b99076a9f4a31b1e2a7d28f65822d","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.5.0_1782972804568_0.7702590444062878","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@aseansc-admin/sea-http","version":"0.6.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.6.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"3bc9cf47ef429bd1f25f295b2076b59daf02841f","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.6.0.tgz","fileCount":9,"integrity":"sha512-Oi3Yt7BESSd+qeFPx8dezKSxz6RsbP2aWv3SHd8I4eBbJ0EPIYPNuA8VdyGkk2jJVkcyU+W9+odDMPGJFj64YQ==","signatures":[{"sig":"MEUCIQC/d8Ddi3CDw0GZNN8sYp7Q0maH/e9y595j13kS4WeMrQIgBFC8ckXa++V03Dh6XQ8TxP396eMEDC8Ekq2eSprDbUQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":182206},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"d0e678d0f6e7ee376fcc48c94d258059f08c75c1","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.6.0_1783414229336_0.19620613552860577","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@aseansc-admin/sea-http","version":"0.7.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.7.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"679a601aad96f66507de81462bd3520ea7e10c2d","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.7.0.tgz","fileCount":9,"integrity":"sha512-1Cu//OJCgzGjo/Qy0lT8XkCxX36kx0KXJbUlLngqwmXPrzqhilab/xhSYHxNqJH1ALnhR0DfMQltMrbjgGt83g==","signatures":[{"sig":"MEQCIH5NIgoHDcuiSbyLJCF4jMEI2nP0lK6WETVbuc0SLcXPAiATeAG5SwJUmtGUtixSg3BKIWHk9CXEitL+lb6fiNsZPQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":195243},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"217dc884e8bc42c205fa24884d2622dbf44c37ba","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.7.0_1783995379567_0.37560585131621393","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@aseansc-admin/sea-http","version":"0.8.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.8.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"e81c4a6a1abd8d693eaf33b9a7a13b2b3dadd154","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.8.0.tgz","fileCount":9,"integrity":"sha512-p1NV2Ctdw3EQ+Wof5vLmMaHioKX8u0eltVkAdOJN43NwebL1nvvDele3HcskPgme8MxPv2CjndWE9z1HeUJWaA==","signatures":[{"sig":"MEUCIFP143ZSJR91BVA+GRtlfmYIFT7Gxrl8P+DndRAFI47cAiEAiv8deS+CJz5UN7Azba9WG1/Tf99JxFiaR/h01IvqwT8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":195671},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"4a9c4df2075821506bcc76dda077eb645ea2e2b6","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.8.0_1784012123344_0.003031972743332556","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@aseansc-admin/sea-http","version":"0.9.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.9.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"d17a3816505888f011719f413162e10dd5af9cd5","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.9.0.tgz","fileCount":9,"integrity":"sha512-PsvKbZtygn7F9M92usu/Q1rZuzozcEQPyaaEFjQUPKTlPpAM8rsOwLNArHx1YIfNl9yWKNx+W6dLee2/mr01uQ==","signatures":[{"sig":"MEQCIEZNU9lu+tz+YE32Hhishg9rrIc/1WQMQJj/bwJC4ujhAiBTrGVSJG0RLYwX4PQ41wbz1ywQf3qtWodBnI004b6pow==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":199110},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"928f770da8b913c77094f9b4d56cfb2c60edf929","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.9.0_1784019095009_0.8549334573285683","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@aseansc-admin/sea-http","version":"0.10.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.10.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"08c0006d3c8ae7e0cba802c21bc4134b52569a41","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.10.0.tgz","fileCount":9,"integrity":"sha512-3YI329/Mf3cmnWok4puAUekHMcvRccNA4PgBZ+Np8fThAMgm9nOzF0o6Zl2SScg+QLmgLs0TPTRoAA0NmchHfQ==","signatures":[{"sig":"MEUCIQDp2h0bap9KolYq+3mKvPOiFoJjCFeXWn/IKKSqOT3vwQIgE/cferSU5siNjjG0aJ7WTrdpUKi1IoA2YptTFRgec3k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":205900},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"89095a589674b7f12476f9fe4ee4f9f2413ccfe6","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.10.0_1784272454892_0.18305597080038538","host":"s3://npm-registry-packages-npm-production"}},"0.10.1":{"name":"@aseansc-admin/sea-http","version":"0.10.1","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.10.1","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"98c9fc52cf1859ac8576de6ed28f4b2b21e6820c","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.10.1.tgz","fileCount":9,"integrity":"sha512-6f75e9KqzDVeujA7NumMfvqbrqPbE7g3Twj7zsJ66cUl+P8llW7tighiamiq1uTTNEatF/B3f4o+8zI4fIYwhw==","signatures":[{"sig":"MEQCIACVRD7OjhqHs6KwkwgYFde5WgR4X1Zlq4+tz8GU/mHxAiAPKdVpygbC5T346JVhxYd66dosYELSziu6LsDAzguwVA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":206609},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"34422dab36f045c637843a4c452db8caf8efc3b4","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.10.1_1784519494024_0.18521488472698766","host":"s3://npm-registry-packages-npm-production"}},"0.10.2":{"name":"@aseansc-admin/sea-http","version":"0.10.2","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.10.2","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"d464aa04a76e37451ed790c62503dacc2adcf2af","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.10.2.tgz","fileCount":9,"integrity":"sha512-APUHPUVVpnTRWYyPxfC2OERq7LUwLYebWyRSvlsAeiw6NqlNTlT1lWW8xM16jjqIK90d1vV5vi671owK1X37/Q==","signatures":[{"sig":"MEQCIFo+BoSrmeAvUkGh7VA+U/oqT4c5/uxKpF0QMBpXo0JDAiAjfaNW0bQXS6G+//R11LCkR5x35w3mQZIkomA/Rz1aXQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":208287},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"1b245f97dd3ec11b3c9801761a9288f3773ca69d","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.10.2_1785981212923_0.79632244885483","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@aseansc-admin/sea-http","version":"0.11.0","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.11.0","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"3277e31d8237a16b5ccc4bc04bea9df2abbbfce2","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.11.0.tgz","fileCount":9,"integrity":"sha512-emvOW/e2vPaZEAcS97apKosxilDZKHRV8P5ze/433accbXX5up3mcUrO2rY9Gwmkw84ML2x1p5wr6Z/9jC9HgQ==","signatures":[{"sig":"MEQCICr/HfJvLhkObAUcF2+z0uQJMklBze57VNiJXS5esqDJAiBehBSiFU6N1yBw7COFdiMU/INvgoW7biAiYh7HJd7iJg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":217482},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"7d1a7783b1556fb5ddc30d2db6ab873d788d077e","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.11.0_1786081585972_0.10186306815634105","host":"s3://npm-registry-packages-npm-production"}},"0.11.1":{"name":"@aseansc-admin/sea-http","version":"0.11.1","author":{"name":"ASC Team"},"license":"UNLICENSED","_id":"@aseansc-admin/sea-http@0.11.1","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"dist":{"shasum":"7304c67ee8c566ce1b01fa2f2c368015fffad5a6","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.11.1.tgz","fileCount":9,"integrity":"sha512-fPMCbsxWIFf7dq18d2uQ3czKpLBSYyxeo1Gb1+ls0grVCZ+STvqeMEkH14giLTjOviQjjg1IaTBf8kVmjhv7GA==","signatures":[{"sig":"MEUCIQDcGNu0LrarNExuWpb36QdCryVM5K2SJxCg3MuhwTTV5wIgU5L+9yHvPAn3CdizF3sTS7jQH0jUlco8SclH1iGQQ3Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":224408},"module":"fesm2022/aseansc-admin-sea-http.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"9ae31ab8580e8ed428c9ec903f713656e1cbe3a0","typings":"index.d.ts","_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"_npmVersion":"11.6.4","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"msw":"^2.14.6","@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0"},"peerDependenciesMeta":{"msw":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sea-http_0.11.1_1786691815316_0.5990065311841768","host":"s3://npm-registry-packages-npm-production"}},"0.11.2":{"name":"@aseansc-admin/sea-http","version":"0.11.2","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","license":"UNLICENSED","author":{"name":"ASC Team"},"sideEffects":false,"peerDependencies":{"@angular/core":"^20.0.0","@angular/common":"^20.0.0","@angular/router":"^20.0.0","msw":"^2.14.6"},"peerDependenciesMeta":{"msw":{"optional":true}},"module":"fesm2022/aseansc-admin-sea-http.mjs","typings":"index.d.ts","exports":{"./package.json":{"default":"./package.json"},".":{"types":"./index.d.ts","default":"./fesm2022/aseansc-admin-sea-http.mjs"},"./testing":{"types":"./testing/index.d.ts","default":"./fesm2022/aseansc-admin-sea-http-testing.mjs"}},"dependencies":{"tslib":"^2.3.0"},"gitHead":"a2d5ce611f5d4934a25768bd4159d893ff2efd5a","_id":"@aseansc-admin/sea-http@0.11.2","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-pVuxNK7PjtuIbAfiCVJrMK9GuYr2RQ+aLA08Dk+/4dMS9lCNhF3bIxs50IdtqE2iN5hjUIPm2BesBJ/t7UDuvg==","shasum":"47448bd7ff26e9cfbcc8f99095352bde8e9a5b72","tarball":"https://registry.npmjs.org/@aseansc-admin/sea-http/-/sea-http-0.11.2.tgz","fileCount":9,"unpackedSize":224781,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFcnIwaDk/o9T0TKtnKHFozh6tJpDLZ6OxsNnudu+mhMAiEAg7ciWXjpw1BdPtjNbtEQiELkdb4SQB7i0LA6ueZDDVA="}]},"_npmUser":{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"},"directories":{},"maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sea-http_0.11.2_1789548606657_0.36697654222737164"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-15T07:21:42.260Z","modified":"2026-09-16T08:50:07.907Z","0.1.0":"2026-05-15T07:21:42.550Z","0.1.1":"2026-05-15T08:23:23.183Z","0.1.2":"2026-05-19T07:13:30.517Z","0.1.3":"2026-05-19T07:42:54.628Z","0.1.4":"2026-05-19T09:00:57.221Z","0.2.0":"2026-05-21T09:00:29.447Z","0.3.0":"2026-05-27T07:08:11.752Z","0.3.1":"2026-05-27T07:46:40.192Z","0.4.0":"2026-06-23T01:52:54.688Z","0.4.1":"2026-06-23T07:15:12.299Z","0.4.2":"2026-06-24T04:56:14.445Z","0.5.0":"2026-07-02T06:13:24.825Z","0.6.0":"2026-07-07T08:50:29.471Z","0.7.0":"2026-07-14T02:16:19.720Z","0.8.0":"2026-07-14T06:55:23.483Z","0.9.0":"2026-07-14T08:51:35.160Z","0.10.0":"2026-07-17T07:14:15.023Z","0.10.1":"2026-07-20T03:51:34.153Z","0.10.2":"2026-08-06T01:53:33.066Z","0.11.0":"2026-08-07T05:46:26.103Z","0.11.1":"2026-08-14T07:16:55.462Z","0.11.2":"2026-09-16T08:50:06.809Z"},"author":{"name":"ASC Team"},"license":"UNLICENSED","description":"ASC HTTP client — envelope wrapper, interceptors, error handling","maintainers":[{"name":"aseansc-admin","email":"tuan.nd@aseansc.com.vn"}],"readme":"# @aseansc-admin/sea-http\n\nAngular HTTP client for the ASEAN SC API — envelope wrapper, interceptors, auth storage, and error handling.\n\n## Installation\n\n```bash\nnpm install @aseansc-admin/sea-http\n```\n\n**Peer dependencies:** `@angular/core`, `@angular/common`, `@angular/router` ≥ 20.\n\n---\n\n## Quick Setup\n\nAdd to `app.config.ts`:\n\n```ts\nimport { provideHttpClient, withInterceptors } from '@angular/common/http';\nimport {\n  provideAscHttp,\n  ascAuthInterceptor,\n  ascErrorInterceptor,\n  ascLoadingInterceptor,\n} from '@aseansc-admin/sea-http';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideHttpClient(\n      withInterceptors([\n        ascAuthInterceptor,\n        ascErrorInterceptor,\n        ascLoadingInterceptor,\n      ]),\n    ),\n    provideAscHttp({\n      baseUrl: 'https://api.aseansc.com.vn/api',\n      apiKey:  'your-api-key',\n      api:     'sea-meetings',\n    }),\n  ],\n};\n```\n\n### `provideAscHttp` options\n\n| Option        | Type                     | Required | Default     | Description                              |\n|--------------|--------------------------|----------|-------------|------------------------------------------|\n| `baseUrl`    | `string`                 | ✅        | —           | Default API endpoint                     |\n| `endpoints`  | `Record<string, string>` | —        | —           | Named endpoints for multi-URL apps       |\n| `apiKey`     | `string`                 | ✅        | —           | API key injected into every header       |\n| `api`        | `string`                 | ✅        | —           | Service name, e.g. `sea-meetings`        |\n| `channel`    | `string`                 | —        | `'ASEANSC'` | Request channel                          |\n| `subChannel` | `string`                 | —        | `'ASEANSC'` | Request sub-channel                      |\n| `context`    | `string`                 | —        | `'WEB'`     | Request context                          |\n| `priority`   | `string`                 | —        | `'1'`       | Request priority                         |\n\n### Multiple base URLs\n\nIf your app talks to more than one API endpoint, declare them in `endpoints` and pass the key via the `endpoint` option to `post()` / `login()`. Falls back to `baseUrl` when the key is omitted or not found.\n\n```ts\nprovideAscHttp({\n  baseUrl: 'https://api.aseansc.com.vn/main',\n  endpoints: {\n    auth: 'https://api.aseansc.com.vn/auth',\n  },\n  apiKey: 'your-api-key',\n  api:    'sea-meetings',\n})\n```\n\n```ts\n// → hits baseUrl\nthis.api.post({ authenType: 'getAllMeetings', data })\n\n// → hits endpoints.auth\nthis.api.post({ authenType: 'doSomething', data, endpoint: 'auth' })\nthis.api.login({ ...credentials, endpoint: 'auth' })\n```\n\n---\n\n## Making API Calls\n\n### General API — `AscApiService.post()`\n\nWraps calls in the standard `{ header, body: { authenType, data } }` envelope and unwraps `body.data` from the response automatically.\n\n```ts\nimport { inject, Injectable } from '@angular/core';\nimport { AscApiService } from '@aseansc-admin/sea-http';\n\ninterface MeetingListData { /* ... */ }\n\n@Injectable({ providedIn: 'root' })\nexport class MeetingService {\n  private api = inject(AscApiService);\n\n  getAll(pageNumber = 0, pageSize = 25) {\n    return this.api.post<MeetingListData>('getAllMeetingAsean', {\n      pagination: { pageNumber, pageSize },\n      search: '',\n    });\n  }\n}\n```\n\n**Request envelope sent:**\n```json\n{\n  \"header\": { \"reqType\": \"REQUEST\", \"api\": \"sea-meetings\", \"...\" },\n  \"body\": {\n    \"authenType\": \"getAllMeetingAsean\",\n    \"data\": { \"pagination\": { \"pageNumber\": 0, \"pageSize\": 25 }, \"search\": \"\" }\n  }\n}\n```\n\n### Login API — `AscApiService.login()`\n\nThe login endpoint uses a different envelope (`command` instead of `authenType`). Use the dedicated `login()` method.\n\n`login()` is generic — sea-http only needs a `token` field to make auth storage/`ascAuthInterceptor` work; every other field in the login response is up to your app. Define your own response interface extending `AscAuthUser` and pass it as the type argument:\n\n```ts\nimport { inject, Injectable } from '@angular/core';\nimport { AscApiService, AscSessionStorageAuthService, AscAuthUser } from '@aseansc-admin/sea-http';\nimport { tap } from 'rxjs';\n\ninterface MyLoginResponse extends AscAuthUser {\n  fullName: string;\n  userCode: string;\n  permissionList: { functionId: string; rightIdList: string[] }[];\n}\n\n@Injectable({ providedIn: 'root' })\nexport class AuthService {\n  private api     = inject(AscApiService);\n  // or AscLocalStorageAuthService / AscCookieAuthService — see Auth Storage\n  private storage = inject(AscSessionStorageAuthService);\n\n  login(username: string, password: string) {\n    return this.api.login<MyLoginResponse>({\n      username,\n      password,\n      authenType: 'getLogin',\n      type: 'INHOUSE',\n    }).pipe(\n      tap(user => this.storage.save(user)),\n    );\n  }\n\n  logout() {\n    this.storage.clear();\n  }\n}\n```\n\n**Request envelope sent:**\n```json\n{\n  \"header\": { \"reqType\": \"REQUEST\", \"...\" },\n  \"body\": {\n    \"command\": \"GET_ENQUIRY\",\n    \"data\": { \"username\": \"...\", \"password\": \"...\", \"authenType\": \"getLogin\", \"type\": \"INHOUSE\" }\n  }\n}\n```\n\n---\n\n### File Upload — `AscApiService.postFormData()`\n\nGọi API envelope kèm file upload (`multipart/form-data`). Cùng unwrap `body.data` / throw `AscApiError` như `post()`, nhưng **không dùng chung cơ chế inject `userID`** của `ascAuthInterceptor`: interceptor chỉ inject `userID` bằng cách mutate JSON body, còn với `FormData` thì nó không \"nhìn\" được vào bên trong — nên `userID` sẽ luôn rỗng nếu để mặc định. `postFormData()` tự lấy `userID` thật trực tiếp qua `ASC_HTTP_USER_ID_FN` ngay lúc build header, không phụ thuộc interceptor. Bearer token vẫn được interceptor tự inject bình thường (không phân biệt body type).\n\nEnvelope `{ header, body: { authenType, data } }` được đóng gói thành 1 field multipart tên `request` (`JSON.stringify`); mỗi file trong `files` được append riêng theo `field` tương ứng.\n\n```ts\nimport { inject, Injectable } from '@angular/core';\nimport { AscApiService } from '@aseansc-admin/sea-http';\n\ninterface UploadResult { url: string; }\n\n@Injectable({ providedIn: 'root' })\nexport class ProfileService {\n  private api = inject(AscApiService);\n\n  uploadAvatar(userId: string, file: File) {\n    return this.api.postFormData<UploadResult>({\n      authenType: 'uploadAvatar',\n      data: { userId },\n      files: [{ field: 'avatar', file }],\n    });\n  }\n\n  uploadWithAttachments(data: Record<string, unknown>, attachments: File[]) {\n    return this.api.postFormData<UploadResult>({\n      authenType: 'submitTicket',\n      data,\n      files: attachments.map((file, i) => ({ field: `attachment${i}`, file })),\n    });\n  }\n\n  // file: null → xoá avatar hiện có (theo quy ước BE: field multipart rỗng = xoá).\n  // Không đưa field vào `files` nếu muốn giữ nguyên file cũ.\n  removeAvatar(userId: string) {\n    return this.api.postFormData<UploadResult>({\n      authenType: 'updateProfile',\n      data: { userId },\n      files: [{ field: 'avatar', file: null }],\n    });\n  }\n}\n```\n\n**`AscPostFormDataOptions`:**\n\n| Option        | Type                                    | Required | Description                                                |\n|---------------|-------------------------------------------|----------|--------------------------------------------------------------|\n| `authenType`  | `string`                                   | ✅        | Tên action/operation, vd `'uploadAvatar'`                    |\n| `data`        | `TBody`                                    | ✅        | Payload nghiệp vụ — đóng gói cùng header vào field `request`  |\n| `files`       | `{ field: string; file: File \\| null }[]`  | ✅        | Danh sách file — mỗi phần tử tạo 1 field multipart riêng. `file: null` → gửi field rỗng (`''`), theo quy ước BE nghĩa là xoá file đó khỏi record |\n| `endpoint`    | `string`                                   | —        | Named endpoint trong `AscHttpConfig.endpoints`                |\n| `skipLoading` | `boolean`                                  | —        | Bỏ qua global loading indicator                               |\n\n---\n\n### Plain REST — `AscApiService.request()`\n\nDùng cho endpoint BE trả thẳng chuẩn HTTP (không bọc envelope `{ header, body }`). Đi qua **cùng interceptor chain** với `post()`/`login()` — Bearer token vẫn tự inject, lỗi vẫn tự xử lý qua `ascErrorInterceptor` + `ASC_HTTP_ERROR_HANDLER`, loading indicator vẫn tự đếm. Khác biệt duy nhất: không build/unwrap envelope, và lỗi luôn là `HttpErrorResponse` chuẩn (không có `AscApiError`).\n\n```ts\nimport { inject, Injectable } from '@angular/core';\nimport { AscApiService } from '@aseansc-admin/sea-http';\n\ninterface User { id: string; name: string; }\ninterface CreateUserDto { name: string; email: string; }\n\n@Injectable({ providedIn: 'root' })\nexport class UserService {\n  private api = inject(AscApiService);\n\n  getById(id: string) {\n    return this.api.request<User>({ path: `/users/${id}` });\n  }\n\n  list(status: 'active' | 'inactive') {\n    return this.api.request<User[]>({ path: '/users', params: { status } });\n  }\n\n  create(dto: CreateUserDto) {\n    return this.api.request<User, CreateUserDto>({ method: 'POST', path: '/users', body: dto });\n  }\n\n  delete(id: string) {\n    return this.api.request<void>({ method: 'DELETE', path: `/users/${id}` });\n  }\n}\n```\n\n**`AscRestOptions`:**\n\n| Option        | Type                                                    | Default | Description                                              |\n|---------------|----------------------------------------------------------|---------|------------------------------------------------------------|\n| `method`      | `'GET' \\| 'POST' \\| 'PUT' \\| 'PATCH' \\| 'DELETE'`         | `'GET'` | HTTP method                                               |\n| `path`        | `string`                                                  | —       | Nối vào `baseUrl`/`endpoints[endpoint]`, vd `/users/123`  |\n| `body`        | `TBody`                                                   | —       | Request body — POST/PUT/PATCH/DELETE                      |\n| `params`      | `Record<string, string \\| number \\| boolean \\| null \\| undefined>` | —       | Query params — `null`/`undefined` bị bỏ qua               |\n| `headers`     | `Record<string, string>`                                  | —       | Header bổ sung (không ghi đè `Authorization`)             |\n| `endpoint`    | `string`                                                  | —       | Named endpoint trong `AscHttpConfig.endpoints`             |\n| `skipLoading` | `boolean`                                                 | `false` | Bỏ qua global loading indicator                            |\n\n> **Khi nào dùng `post()`/`login()`/`postFormData()` vs `request()`?** Dùng `post()`/`login()`/`postFormData()` cho BE theo chuẩn envelope cũ (`sea-meetings`, `sea-auth`...) — `postFormData()` là biến thể của `post()` khi cần gửi kèm file. Dùng `request()` cho BE mới trả thẳng REST chuẩn HTTP — các flow chạy song song, không xung đột, dùng chung 1 `AscApiService`/interceptor chain.\n\n---\n\n## Auth Storage\n\nThree ready-made services for persisting the token and user session. All implement the abstract `AscAuthStorageService`.\n\n### `AscLocalStorageAuthService` — localStorage\n\nNo size limits. Recommended when `permissionList` is large.\n\n```ts\nimport { inject } from '@angular/core';\nimport { AscLocalStorageAuthService } from '@aseansc-admin/sea-http';\n\nconst storage = inject(AscLocalStorageAuthService);\n\nstorage.save(loginResponseData);       // saves token + full user data\nstorage.getToken();                    // string | null\nstorage.getUser<MyLoginResponse>();    // MyLoginResponse | null — pass your own type\nstorage.clear();                       // removes both keys\n```\n\n### `AscCookieAuthService` — Cookie\n\nUseful when the token needs to be sent automatically by the browser. Note: each cookie is limited to ~4 KB — if `permissionList` is large, use `AscLocalStorageAuthService` instead.\n\n```ts\nimport { inject } from '@angular/core';\nimport { AscCookieAuthService } from '@aseansc-admin/sea-http';\n\nconst storage = inject(AscCookieAuthService);\n\nstorage.save(loginResponseData, 7); // expires in 7 days (default: 1)\nstorage.getToken();\nstorage.getUser<MyLoginResponse>();\nstorage.clear();\n```\n\nCookies are set with `SameSite=Strict; path=/`.\n\n### `AscSessionStorageAuthService` — sessionStorage\n\nCleared automatically when the tab/browser is closed — use when the session shouldn't outlive the tab.\n\n```ts\nimport { inject } from '@angular/core';\nimport { AscSessionStorageAuthService } from '@aseansc-admin/sea-http';\n\nconst storage = inject(AscSessionStorageAuthService);\n\nstorage.save(loginResponseData);\nstorage.getToken();\nstorage.getUser<MyLoginResponse>();\nstorage.clear();\n```\n\n### Using the abstract token for DI\n\nIf you want to swap implementations without changing consuming services, provide one via `AscAuthStorageService`:\n\n```ts\n// app.config.ts\nimport {\n  AscAuthStorageService,\n  AscLocalStorageAuthService,\n  // or AscCookieAuthService / AscSessionStorageAuthService\n} from '@aseansc-admin/sea-http';\n\nproviders: [\n  { provide: AscAuthStorageService, useExisting: AscLocalStorageAuthService },\n]\n```\n\n```ts\n// any service\nprivate storage = inject(AscAuthStorageService);\n```\n\n---\n\n## Interceptors\n\n| Interceptor            | What it does                                                                 |\n|------------------------|------------------------------------------------------------------------------|\n| `ascAuthInterceptor`   | Injects `userID` into the request header from `ASC_HTTP_USER_ID_FN`         |\n| `ascErrorInterceptor`  | Handles 401 (redirect to `/login`); every other error status (400, 403, 404, network, 5xx...) goes through `ASC_HTTP_ERROR_HANDLER` |\n| `ascLoadingInterceptor`| Auto-increments/decrements `AscLoadingService` counter per active request   |\n\nAll three are opt-in — add only what you need to `withInterceptors([...])`.\n\n### Configure `userID` injection\n\n```ts\n// app.config.ts\nimport { ASC_HTTP_USER_ID_FN } from '@aseansc-admin/sea-http';\n\n{\n  provide:    ASC_HTTP_USER_ID_FN,\n  useFactory: (auth: AuthService) => () => auth.currentUser()?.userCode ?? '',\n  deps:       [AuthService],\n}\n```\n\n### Configure global error handler\n\n```ts\nimport { ASC_HTTP_ERROR_HANDLER, AscApiError } from '@aseansc-admin/sea-http';\n\n{\n  provide:    ASC_HTTP_ERROR_HANDLER,\n  useFactory: (toast: ToastService) =>\n    (err: unknown) => toast.error(err instanceof AscApiError ? err.message : 'Connection error'),\n  deps:       [ToastService],\n}\n```\n\n### Global loading indicator\n\n`ascLoadingInterceptor` tự động đếm request đang active qua `AscLoadingService`. Mặc định **BẬT** cho mọi request.\n\nDùng `AscLoadingBarComponent` từ `@aseansc-admin/ui` để hiển thị thanh loading đầu trang:\n\n```ts\n// app.component.ts\nimport { AscLoadingService } from '@aseansc-admin/sea-http';\n\nloading = inject(AscLoadingService);\n```\n\n```html\n<!-- app.component.html -->\n<asc-loading-bar [visible]=\"loading.isLoading()\" />\n<p-toast />\n<p-confirmdialog />\n<router-outlet />\n```\n\n### Tắt loading cho request cụ thể\n\nDùng `skipLoading: true` trong `AscApiService.post()` để bỏ qua loading indicator — hữu ích cho background polling, auto-refresh, silent call:\n\n```ts\n// Loading bật — thanh loading hiện khi gọi API này\nthis.api.post({ authenType: 'getData', data: {} })\n\n// Loading tắt — call âm thầm, không ảnh hưởng UI\nthis.api.post({ authenType: 'silentPoll', data: {}, skipLoading: true })\n\n// Tương tự với request() (REST thuần)\nthis.api.request({ path: '/status', skipLoading: true })\n```\n\nHoặc dùng `SKIP_LOADING` token trực tiếp với `HttpClient`:\n\n```ts\nimport { HttpContext }  from '@angular/common/http';\nimport { SKIP_LOADING } from '@aseansc-admin/sea-http';\n\nthis.http.post(url, body, {\n  context: new HttpContext().set(SKIP_LOADING, true),\n})\n```\n\n---\n\n## Error Handling\n\nAPI-level errors (when `body.status !== 'OK'`, only for `post()`/`login()`) are thrown as `AscApiError`:\n\n```ts\nimport { AscApiError } from '@aseansc-admin/sea-http';\n\nthis.api.post('someAction', data).subscribe({\n  error: (err) => {\n    if (err instanceof AscApiError) {\n      console.log(err.status);     // e.g. 'UNAUTHORIZED'\n      console.log(err.authenType); // the operation name\n      console.log(err.data);       // raw error payload from server\n      console.log(err.message);    // human-readable message — see below\n    }\n  }\n});\n```\n\n`err.message` tries to surface the real message the backend sent, since `body.data`'s shape isn't standardized across endpoints. It looks for a string field named `messageVn`, `message`, `msg`, `errorMessage`, `desc`, `description`, or `messageEn` (in that order — Vietnamese fields first, matching the app's default locale) and uses the first match. If none of those fields exist, it falls back to a debug string: `` `[${authenType}] API responded with status: ${status}` ``.\n\nSome backends (e.g. bos-api) don't put error details in `body.data` at all — they return a sibling `error` field instead:\n\n```json\n{\n  \"header\": { \"reqType\": \"RESPONSE\", \"api\": \"bos-api\", \"...\": \"...\" },\n  \"body\":   { \"status\": \"FAILE\", \"authenType\": \"manualMatchStatement\" },\n  \"error\":  { \"code\": \"RECON001\", \"desc\": \"Không tìm thấy bản ghi đối chiếu\", \"messageVn\": \"Không tìm thấy bản ghi đối chiếu\", \"messageEn\": null }\n}\n```\n\n`AscApiError` handles this too — when `body.data` is absent, it falls back to `response.error` for both `err.message` extraction and `err.data`.\n\nEither way, `err.data` holds the raw, untouched payload (`body.data`, or `response.error` when `body.data` is absent) for cases where the app needs more than just the message.\n\nHTTP-level errors (any non-2xx status, network errors) are handled automatically by `ascErrorInterceptor` for **both** `post()`/`login()` and `request()` — since it works purely off `HttpErrorResponse.status`, not the envelope shape:\n\n- `401` → clears session (localStorage + cookie + sessionStorage), redirects to `/login` (does **not** call the error handler)\n- everything else (`400`, `403`, `404`, `0` network error, `5xx`...) → passed to `ASC_HTTP_ERROR_HANDLER`\n- `500` retries up to 3× (1s/2s/3s delay) before falling through to the error handler\n\n`request()` never throws `AscApiError` — its errors are always plain `HttpErrorResponse`.\n\n---\n\n## Testing with MSW (Mock Service Worker)\n\nImport từ secondary entry point `@aseansc-admin/sea-http/testing` — tách biệt hoàn toàn với production bundle, MSW không bao giờ được ship.\n\n### Install\n\n```bash\nnpm install msw@2.14.6 --save-dev\n```\n\n### 1. Khởi tạo MSW service worker (browser)\n\n```bash\nnpx msw init public/ --save\n```\n\nTạo file `src/mocks/browser.ts`:\n\n```ts\nimport { setupWorker } from 'msw/browser';\nimport { handlers } from './handlers';\n\nexport const worker = setupWorker(...handlers);\n```\n\nKhởi động worker trong `main.ts` khi dev:\n\n```ts\n// main.ts\nif (isDevMode()) {\n  const { worker } = await import('./mocks/browser');\n  await worker.start({ onUnhandledRequest: 'bypass' });\n}\nbootstrapApplication(AppComponent, appConfig);\n```\n\n### 2. Khởi tạo MSW server (Jest / Vitest)\n\n```ts\n// jest.setup.ts  (hoặc vitest.setup.ts)\nimport { setupServer } from 'msw/node';\nimport { handlers } from './mocks/handlers';\n\nexport const server = setupServer(...handlers);\n\nbeforeAll(() => server.listen({ onUnhandledRequest: 'warn' }));\nafterEach(() => server.resetHandlers());\nafterAll(() => server.close());\n```\n\n### 3. Tạo handlers\n\n```ts\n// src/mocks/handlers.ts\nimport { createAscHandler, ascOperation } from '@aseansc-admin/sea-http/testing';\n\nexport const handlers = [\n  createAscHandler('https://api.example.com/api', [\n\n    // ── OK response ───────────────────────────────────────────────────────\n    ascOperation('getAllMeeting', () => ({\n      meetings: [\n        { id: '1', title: 'Kickoff Q3', date: '2026-07-01' },\n        { id: '2', title: 'Sprint Review', date: '2026-07-08' },\n      ],\n      total: 2,\n    })),\n\n    // ── Đọc payload từ request ────────────────────────────────────────────\n    ascOperation('getMeetingById', ({ data }) => {\n      const req = data as { id: string };\n      return { id: req.id, title: `Meeting ${req.id}`, status: 'ACTIVE' };\n    }),\n\n    // ── Login ─────────────────────────────────────────────────────────────\n    // sea-http dùng body.command thay vì authenType cho login\n    ascOperation('getLogin', ({ data }) => {\n      const creds = data as { username: string };\n      return { token: 'mock-jwt-token', userCode: creds.username, stateType: 'LOGIN' };\n    }),\n\n  ]),\n];\n```\n\n### 4. Error cases\n\n#### 4a. Business error — `errorStatus`\n\nsea-http ném `AscApiError` khi `body.status !== 'OK'`. HTTP status vẫn là 200.\n\n```ts\n// AscApiError { status: 'USER_NOT_FOUND', data: { id: '99' } }\nascOperation(\n  'getUserById',\n  ({ data }) => ({ id: (data as any).id }),\n  { errorStatus: 'USER_NOT_FOUND' },\n)\n\n// AscApiError { status: 'VALIDATION_ERROR', data: { field: 'email', msg: 'Invalid email' } }\nascOperation(\n  'createUser',\n  () => ({ field: 'email', msg: 'Invalid email' }),\n  { errorStatus: 'VALIDATION_ERROR' },\n)\n\n// Dùng trực tiếp ascFail nếu cần tuỳ chỉnh ngoài ascOperation\nimport { ascFail } from '@aseansc-admin/sea-http/testing';\nreturn HttpResponse.json(ascFail('LOCKED', { retryAfter: 60 }));\n```\n\n#### 4b. HTTP 401 Unauthorized\n\n`ascErrorInterceptor` bắt 401 → xoá session + redirect `/login` tự động.\n\n```ts\nascOperation('getSecureData', () => null, { httpStatus: 401 })\n```\n\n> **Lưu ý:** Resolver KHÔNG được gọi khi `httpStatus` được đặt.\n\n#### 4c. HTTP 403 Forbidden\n\n`ascErrorInterceptor` bắt 403 → gọi `ASC_HTTP_ERROR_HANDLER`.\n\n```ts\nascOperation('deleteRecord', () => null, { httpStatus: 403 })\n```\n\n#### 4d. HTTP 500 Internal Server Error\n\n`ascErrorInterceptor` tự **retry tối đa 3 lần** (delay 1 s / 2 s / 3 s), sau đó gọi `ASC_HTTP_ERROR_HANDLER`.  \nMock này hữu ích để kiểm tra xem app có hiện đúng trạng thái loading và thông báo lỗi sau khi hết retry không.\n\n```ts\nascOperation('getReport', () => null, { httpStatus: 500 })\n\n// Kết hợp với delay để thấy rõ retry effect\nascOperation('getReport', () => null, { httpStatus: 500, delayMs: 300 })\n```\n\n#### 4e. HTTP 404 Not Found\n\n`ascErrorInterceptor` gọi `ASC_HTTP_ERROR_HANDLER` (giống mọi status khác ngoài 401/0), sau đó vẫn ném `HttpErrorResponse` về subscriber.\n\n```ts\nascOperation('getAttachment', () => null, { httpStatus: 404 })\n```\n\n#### 4f. Network error (status 0)\n\nGiả lập mất kết nối mạng (connection refused, timeout). Angular nhận `HttpErrorResponse { status: 0 }`.  \n`ascErrorInterceptor` gọi `ASC_HTTP_ERROR_HANDLER` với `statusText: 'Network Error — Không kết nối được server'`.\n\n```ts\nascOperation('getData', () => null, { networkError: true })\n```\n\n> **Lưu ý:** `networkError` và `httpStatus` đều bỏ qua resolver. Nếu đặt cả hai cùng lúc, `networkError` được ưu tiên.\n\n### 5. Kết hợp delay + error để test loading UI\n\n```ts\n// Thấy loading spinner, sau 2 giây hiện lỗi 500 → retry 3 lần → hiện toast error\nascOperation('heavyReport', () => null, { httpStatus: 500, delayMs: 2000 })\n\n// Thấy loading, sau 800 ms hiện lỗi nghiệp vụ\nascOperation('submitForm', () => ({ msg: 'Duplicate entry' }), {\n  errorStatus: 'DUPLICATE',\n  delayMs: 800,\n})\n```\n\n### 6. Override trong từng test\n\nDùng `server.use()` để override handler tạm thời trong một test case — không ảnh hưởng test khác nhờ `server.resetHandlers()` sau mỗi test.\n\n```ts\nimport { server } from '../jest.setup';\nimport { createAscHandler, ascOperation } from '@aseansc-admin/sea-http/testing';\n\nit('hiện thông báo lỗi khi API trả về UNAUTHORIZED', async () => {\n  server.use(\n    createAscHandler('https://api.example.com/api', [\n      ascOperation('getProfile', () => null, { errorStatus: 'UNAUTHORIZED' }),\n    ]),\n  );\n\n  // ... render component, kiểm tra toast / error message\n});\n\nit('redirect về /login khi server trả về 401', async () => {\n  server.use(\n    createAscHandler('https://api.example.com/api', [\n      ascOperation('getProfile', () => null, { httpStatus: 401 }),\n    ]),\n  );\n\n  // ... kiểm tra router.navigate đã được gọi với ['/login']\n});\n\nit('hiện banner lỗi mạng khi mất kết nối', async () => {\n  server.use(\n    createAscHandler('https://api.example.com/api', [\n      ascOperation('getProfile', () => null, { networkError: true }),\n    ]),\n  );\n\n  // ... kiểm tra error handler được gọi với status 0\n});\n```\n\n### 7. Nhiều endpoints\n\nNếu app dùng nhiều `endpoints` trong `provideAscHttp`, tạo nhiều handler riêng:\n\n```ts\nimport { createAscHandler, ascOperation } from '@aseansc-admin/sea-http/testing';\n\nexport const handlers = [\n  // baseUrl\n  createAscHandler('https://api.example.com/api', [\n    ascOperation('getAllMeeting', () => ({ meetings: [] })),\n  ]),\n\n  // endpoints.auth\n  createAscHandler('https://auth.example.com/api', [\n    ascOperation('getLogin', () => ({ token: 'mock-token', userCode: 'admin' })),\n  ]),\n];\n```\n\nHoặc dùng wildcard để khớp mọi origin (hữu ích khi base URL thay đổi theo môi trường):\n\n```ts\ncreateAscHandler('*/api', [...operations])\n```\n\n### 8. Bảng tham chiếu\n\n| Option | Type | Resolver gọi? | Mô tả |\n|---|---|---|---|\n| _(mặc định)_ | — | ✅ | Trả OK envelope, resolver result vào `body.data` |\n| `errorStatus` | `string` | ✅ | Trả error envelope với `body.status = errorStatus` → sea-http ném `AscApiError` |\n| `httpStatus` | `number` | ❌ | Trả HTTP error response (401/403/500...) — bypass envelope |\n| `networkError` | `boolean` | ❌ | Giả lập mất kết nối — Angular nhận `HttpErrorResponse.status = 0` |\n| `delayMs` | `number` | — | Thêm delay (ms) trước khi trả response, kết hợp được với mọi option trên |\n\n| HTTP Status | Xử lý bởi `ascErrorInterceptor` |\n|---|---|\n| `401` | Redirect `/login` (không gọi error handler) |\n| `500` | Retry 3× (1s/2s/3s) → gọi `ASC_HTTP_ERROR_HANDLER` |\n| `0` (network) | Gọi `ASC_HTTP_ERROR_HANDLER` với 'Network Error' |\n| `403`, `404`, `400`, khác | Gọi `ASC_HTTP_ERROR_HANDLER` |\n\n---\n\n## Server-Sent Events (SSE)\n\n`AscSseService` wraps the browser's `EventSource` API. Since `EventSource` does not support custom headers, the JWT token is passed automatically as a URL query param (`?token=<jwt>`).\n\nNo extra setup needed — the service reads token from localStorage / cookie (see [Auth Storage](#auth-storage)) and appends it to every URL.\n\n### Unnamed events\n\nThe server sends lines in the format:\n```\ndata: {\"meetingId\":\"123\",\"status\":\"STARTED\"}\\n\\n\n```\n\n```ts\nimport { inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AscSseService } from '@aseansc-admin/sea-http';\n\ninterface NotificationDto {\n  type:    string;\n  message: string;\n}\n\n@Component({ ... })\nexport class NotificationBell {\n  private sse = inject(AscSseService);\n\n  constructor() {\n    this.sse.connect<NotificationDto>('/notifications/stream')\n      .pipe(takeUntilDestroyed())\n      .subscribe({\n        next:     event => console.log(event.type, event.data),\n        error:    err   => console.error('SSE error', err),\n        complete: ()    => console.log('SSE closed'),\n      });\n  }\n}\n```\n\n### Named events\n\nThe server sends lines in the format:\n```\nevent: meeting-update\ndata: {\"meetingId\":\"123\",\"agenda\":\"Updated agenda\"}\\n\\n\n```\n\nUse `sse.on()` to filter by event type — the returned Observable emits the parsed `data` directly:\n\n```ts\nimport { inject, Component, OnInit } from '@angular/core';\nimport { takeUntilDestroyed }        from '@angular/core/rxjs-interop';\nimport { AscSseService }             from '@aseansc-admin/sea-http';\n\ninterface MeetingUpdate {\n  meetingId: string;\n  agenda:    string;\n}\n\n@Component({ ... })\nexport class MeetingDetailPage implements OnInit {\n  private sse = inject(AscSseService);\n\n  ngOnInit() {\n    // Chỉ nhận events có type = 'meeting-update'\n    this.sse.on<MeetingUpdate>('/notifications/stream', 'meeting-update')\n      .pipe(takeUntilDestroyed())\n      .subscribe(data => this.applyUpdate(data));\n\n    // Có thể subscribe nhiều event type cùng lúc từ cùng 1 path\n    this.sse.on<ParticipantUpdate>('/notifications/stream', 'participant-joined')\n      .pipe(takeUntilDestroyed())\n      .subscribe(data => this.addParticipant(data));\n  }\n\n  private applyUpdate(update: MeetingUpdate) { /* ... */ }\n  private addParticipant(p: ParticipantUpdate) { /* ... */ }\n}\n```\n\n### SSE options\n\n| Option            | Type      | Default  | Description                                    |\n|-------------------|-----------|----------|------------------------------------------------|\n| `tokenParam`      | `string`  | `'token'`| Tên query param chứa JWT token                 |\n| `params`          | `Record`  | `{}`     | Query params thêm vào URL                      |\n| `withCredentials` | `boolean` | `false`  | Gửi cookie theo request                        |\n| `reconnect`       | `boolean` | `true`   | Tự động reconnect khi mất kết nối              |\n| `reconnectDelay`  | `number`  | `3000`   | Delay giữa các lần reconnect (ms)              |\n\n```ts\n// Ví dụ: thêm query params, đổi tên token param\nthis.sse.connect('/stream', {\n  tokenParam: 'access_token',\n  params:     { roomId: '42' },\n  reconnect:  true,\n  reconnectDelay: 5000,\n});\n```\n\n---\n\n## WebSocket\n\n`AscWebSocketService.connect()` trả về một `AscWsConnection` handle. Outgoing và incoming messages đều dùng cùng envelope protocol:\n\n```json\n{\n  \"header\": { \"api\": \"sea-meetings\", \"apiKey\": \"...\", \"userID\": \"u01\", \"channel\": \"ASEANSC\", \"subChannel\": \"ASEANSC\" },\n  \"body\":   { \"authenType\": \"meetingUpdate\", \"data\": { ... } }\n}\n```\n\n### Basic usage\n\n```ts\nimport { inject, Component, OnInit, OnDestroy } from '@angular/core';\nimport { AscWebSocketService, AscWsConnection } from '@aseansc-admin/sea-http';\n\ninterface MeetingEvent  { meetingId: string; status: string; }\ninterface ChatMessage   { from: string; text: string; }\n\n@Component({ ... })\nexport class MeetingRoomPage implements OnInit, OnDestroy {\n  private ws   = inject(AscWebSocketService);\n  private conn!: AscWsConnection;\n\n  ngOnInit() {\n    this.conn = this.ws.connect('/ws/meetings');\n\n    // Theo dõi trạng thái kết nối\n    this.conn.status$.subscribe(status => {\n      // 'connecting' | 'connected' | 'disconnected' | 'error'\n      console.log('WS status:', status);\n    });\n\n    // Nhận tất cả messages\n    this.conn.messages$.subscribe(msg => {\n      console.log(msg.body.authenType, msg.body.data);\n    });\n\n    // Lọc theo authenType\n    this.conn.on<MeetingEvent>('meetingUpdate').subscribe(data => {\n      console.log('Meeting updated:', data.status);\n    });\n\n    this.conn.on<ChatMessage>('chatMessage').subscribe(msg => {\n      this.appendChat(msg);\n    });\n\n    // Gửi message\n    this.conn.send('subscribeMeeting', { meetingId: '123' });\n  }\n\n  sendChat(text: string) {\n    this.conn.send('sendChat', { text });\n  }\n\n  ngOnDestroy() {\n    this.conn.close();\n  }\n\n  private appendChat(msg: ChatMessage) { /* ... */ }\n}\n```\n\n### Với `takeUntilDestroyed` (Angular 16+)\n\n```ts\nimport { Component, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AscWebSocketService } from '@aseansc-admin/sea-http';\n\n@Component({ ... })\nexport class ChatComponent {\n  private ws   = inject(AscWebSocketService);\n  private conn = this.ws.connect('/ws/chat');\n\n  constructor() {\n    this.conn.on<ChatMessage>('chatMessage')\n      .pipe(takeUntilDestroyed())\n      .subscribe(msg => this.messages.push(msg));\n  }\n}\n```\n\n> **Lưu ý:** Dùng `takeUntilDestroyed()` thì không cần gọi `conn.close()` để cleanup subscription, nhưng vẫn nên gọi `conn.close()` trong `ngOnDestroy` để đóng WebSocket connection.\n\n### Multiple connections\n\nMỗi lần gọi `connect()` tạo một WebSocket connection riêng biệt:\n\n```ts\n// Kết nối đến meeting room\nconst meetingConn = this.ws.connect('/ws/meetings');\n\n// Kết nối riêng đến notification channel\nconst notifConn = this.ws.connect('/ws/notifications', { reconnect: true });\n\n// Kết nối đến URL khác hoàn toàn\nconst externalConn = this.ws.connect('wss://other.service.com/ws');\n```\n\n### WebSocket options\n\n| Option           | Type             | Default  | Description                                        |\n|------------------|------------------|----------|----------------------------------------------------|\n| `tokenParam`     | `string \\| false`| `'token'`| Tên query param chứa JWT. `false` = không gửi token|\n| `reconnect`      | `boolean`        | `true`   | Tự động reconnect khi mất kết nối                  |\n| `maxRetries`     | `number`         | `5`      | Số lần retry tối đa                                |\n| `reconnectDelay` | `number`         | `3000`   | Delay cơ bản giữa các lần retry (ms), tăng dần     |\n\n```ts\nthis.ws.connect('/ws/meetings', {\n  tokenParam:     'access_token',\n  reconnect:      true,\n  maxRetries:     10,\n  reconnectDelay: 2000,\n});\n```\n\n### Retry back-off\n\nDelay giữa các lần reconnect tăng tuyến tính theo số lần thử:\n\n| Lần retry | Delay           |\n|-----------|-----------------|\n| 1         | 1× reconnectDelay |\n| 2         | 2× reconnectDelay |\n| 3         | 3× reconnectDelay |\n| …         | …               |\n\nSau `maxRetries` lần thất bại, `messages$` sẽ complete và không reconnect nữa.\n\n---\n\n## Types Reference\n\n```ts\nimport type {\n  // Config\n  AscHttpConfig,\n\n  // Request / Response envelope\n  AscApiRequest,\n  AscApiRequestHeader,\n  AscApiResponse,\n  AscApiResponseHeader,\n\n  // Plain REST\n  AscHttpMethod,\n  AscRestOptions,\n\n  // File upload\n  AscPostFormDataOptions,\n  AscFormDataFile,\n\n  // Login\n  LoginRequestData,\n  AscAuthUser,\n\n  // SSE\n  AscSseOptions,\n  AscSseEvent,\n\n  // WebSocket\n  AscWsOptions,\n  AscWsMessage,\n  AscWsHeader,\n  AscWsStatus,\n} from '@aseansc-admin/sea-http';\n\nimport { AscApiError, isAscApiRequest } from '@aseansc-admin/sea-http';\n```\n","readmeFilename":"README.md"}