Rebuild client dist with Hanzo branding, update Makefile
- Rebuild client/dist with updated icons and branding assets - Update .dockerignore and Makefile for Hanzo build
@@ -10,3 +10,8 @@ tests
|
||||
*.tgz
|
||||
log.txt
|
||||
docker/Dockerfile.*
|
||||
node_modules
|
||||
**/node_modules
|
||||
.env
|
||||
.env.*
|
||||
!.env.static
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Static SPA — pre-built dist served by lightweight file server
|
||||
# Gateway/ingress handles load balancing, rate limiting, SSL, SPA routing.
|
||||
#
|
||||
# Pre-requisite: run `make build-static-local` first to build client/dist
|
||||
#
|
||||
# Build: docker build -f Dockerfile.static -t ghcr.io/hanzoai/chat:latest .
|
||||
# Run: docker run -p 3080:3080 ghcr.io/hanzoai/chat:latest
|
||||
|
||||
FROM node:22-alpine
|
||||
|
||||
RUN npm install -g serve@14
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy pre-built static files
|
||||
COPY client/dist/ /app/dist/
|
||||
COPY client/public/ /app/public/
|
||||
|
||||
# Merge public assets into dist (favicon, icons, etc.)
|
||||
RUN cp -rn /app/public/* /app/dist/ 2>/dev/null || true && rm -rf /app/public
|
||||
|
||||
EXPOSE 3080
|
||||
|
||||
# serve with SPA fallback on port 3080
|
||||
CMD ["serve", "-s", "dist", "-l", "3080"]
|
||||
@@ -130,6 +130,28 @@ build-prod:
|
||||
@echo "$(GREEN)Building production image...$(NC)"
|
||||
@docker build -f docker/Dockerfile -t hanzoai/chat:latest .
|
||||
|
||||
build-static-local:
|
||||
@echo "$(GREEN)Building static SPA locally...$(NC)"
|
||||
@cp .env.static .env
|
||||
@pnpm run build:data-provider
|
||||
@pnpm run --filter @librechat/client build
|
||||
@cd client && pnpm run build
|
||||
@cp .env.backup .env 2>/dev/null || true
|
||||
@echo "$(GREEN)Local build complete: client/dist/$(NC)"
|
||||
|
||||
build-static: build-static-local
|
||||
@echo "$(GREEN)Building Docker image...$(NC)"
|
||||
@docker build -f Dockerfile.static -t ghcr.io/hanzoai/chat:latest .
|
||||
@echo "$(GREEN)Image built: ghcr.io/hanzoai/chat:latest$(NC)"
|
||||
|
||||
deploy-static:
|
||||
@echo "$(GREEN)Pushing and deploying static SPA...$(NC)"
|
||||
@docker push ghcr.io/hanzoai/chat:latest
|
||||
@kubectl apply -f k8s/deployment-static.yaml
|
||||
@kubectl rollout restart deployment/chat -n hanzo
|
||||
@echo "$(GREEN)Deployed. Watching rollout...$(NC)"
|
||||
@kubectl rollout status deployment/chat -n hanzo --timeout=120s
|
||||
|
||||
# ============================================================================
|
||||
# PRODUCTION
|
||||
# ============================================================================
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
import{r as e,j as s,bE as a}from"./vendor.hYViCx_o.js";import{ay as t,az as r,aC as o}from"./radix-ui.zUF2t8pu.js";import{g as i,Q as n,S as c,u as l,a as m,d,T as u,c as j,B as p}from"./index.ChtrlAPT.js";import{u as x}from"./tanstack-vendor.CcfA9pap.js";import"./utilities.D3AhyVZJ.js";import"./animations.C9kiQ0P7.js";import{E as h,l as g,y as f,P as b}from"./headlessui.CpNfReFM.js";import"./react-interactions.CDNIj_P0.js";import"./markdown_highlight.Dt5gy-Cs.js";import"./validation.CgW5gGeX.js";import"./math-katex.DxUdIsOj.js";import"./locales.CneDv1Po.js";import"./i18n.B6o-Gbrg.js";import"./routing.D6ZJbNew.js";import"./http-client.B1ynDCuQ.js";import"./date-utils.CHq2fTxU.js";import"./forms.CgWlvBRM.js";import"./framer-motion.BeyjVqYH.js";import"./advanced-inputs.oQ6kIoBT.js";import"./security-ui.MEypZJRJ.js";import"./markdown-processing.TTzZ1vwl.js";import"./avatars.zbie9GOZ.js";import"./virtualization.CzFJ0wKU.js";import"./heic-converter.CBfFuDy-.js";import"./sandpack.DtKLOr2o.js";import"./codemirror-core.K3HVILnM.js";import"./codemirror-state.ClnsKiKb.js";import"./codemirror-view.yuH3vRs8.js";import"./codemirror-language.B5LqEgWw.js";const v=({tag:a,selected:o,handleSubmit:i,icon:n,...l})=>{const[m,d]=e.useState(!1);return s.jsx(h,{"aria-label":a,className:"group flex w-full gap-2 rounded-lg p-2.5 text-sm text-text-primary transition-colors duration-200 focus:outline-none data-[focus]:bg-surface-hover data-[focus-visible]:ring-2 data-[focus-visible]:ring-primary",...l,as:"button",onClick:async()=>{"New Bookmark"!==a?(d(!0),i(a),d(!1)):i()},children:s.jsx("div",{className:"flex grow items-center justify-between gap-2",children:s.jsxs("div",{className:"flex items-center gap-2",children:[null!=n?n:m?s.jsx(c,{className:"size-4"}):o?s.jsx(t,{className:"size-4"}):s.jsx(r,{className:"size-4"}),s.jsx("div",{style:{wordBreak:"break-word",overflowWrap:"anywhere"},children:a})]})})})},k=({tags:e,handleSubmit:a,header:t})=>{const{bookmarks:r}=l();return s.jsxs(s.Fragment,{children:[t,r.length>0&&s.jsx("div",{className:"my-1.5 h-px",role:"none"}),r.map((t,r)=>s.jsx(v,{tag:t.tag,selected:e.includes(t.tag),handleSubmit:a},`${t._id??t.tag}-${r}`))]})},y=({conversation:a,tags:t=[],setTags:r})=>{const[i,n]=e.useState(),{bookmarks:c}=l(),d=m();e.useEffect(()=>{i||n(a)},[a,i]);const u=()=>{r([])};return 0===c.length?s.jsxs("div",{className:"flex flex-col",children:[s.jsx(v,{tag:d("com_ui_clear_all"),"data-testid":"bookmark-item-clear",handleSubmit:u,selected:!1,icon:s.jsx(o,{className:"size-4"})}),s.jsx(v,{tag:d("com_ui_no_bookmarks"),"data-testid":"bookmark-item-no-bookmarks",handleSubmit:()=>Promise.resolve(),selected:!1,icon:"🤔"})]}):s.jsx("div",{className:"flex flex-col",children:s.jsx(k,{tags:t,handleSubmit:e=>{if(void 0===e)return;const s=(e=>t.some(s=>s===e)?t.filter(s=>s!==e):[...t,e])(e);r(s)},header:s.jsx(v,{tag:d("com_ui_clear_all"),"data-testid":"bookmark-item-clear",handleSubmit:u,selected:!1,icon:s.jsx(o,{className:"size-4"})})})})},N=({tags:o,setTags:c,isSmallScreen:l})=>{const h=m(),{data:v}=x([n.conversationTags],()=>i(),{refetchOnWindowFocus:!1,refetchOnReconnect:!1,refetchOnMount:!1,...k});var k;const N=a(d.conversationByIndex(0)),w=e.useMemo(()=>o.length>0?o.join(", "):h("com_ui_bookmarks"),[o,h]);return s.jsx(g,{as:"div",className:"group relative",children:({open:e})=>s.jsxs(s.Fragment,{children:[s.jsx(u,{description:w,render:s.jsx(f,{id:"bookmark-menu-button","aria-label":h("com_ui_bookmarks"),className:j("flex items-center justify-center","size-10 border-none text-text-primary hover:bg-accent hover:text-accent-foreground","rounded-full border-none p-2 hover:bg-surface-hover md:rounded-xl",e?"bg-surface-hover":""),"data-testid":"bookmark-menu",children:o.length>0?s.jsx(t,{className:j("text-text-primary",l?"icon-md-heavy":"icon-lg"),"aria-hidden":"true"}):s.jsx(r,{className:j("text-text-primary",l?"icon-md-heavy":"icon-lg"),"aria-hidden":"true"})})}),s.jsx(b,{anchor:"bottom",className:"absolute left-0 top-full z-[100] mt-1 w-60 translate-y-0 overflow-hidden rounded-lg bg-surface-secondary p-1.5 shadow-lg outline-none",children:v&&N&&s.jsx(p.Provider,{value:{bookmarks:v.filter(e=>e.count>0)},children:s.jsx(y,{conversation:N,tags:o,setTags:c})})})]})})};export{N as default};
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 254 B After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 366 B |
@@ -1,9 +0,0 @@
|
||||
<svg width="67" height="67" viewBox="0 0 67 67" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="white"/>
|
||||
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="#D3D3D3"/>
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="white"/>
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="white"/>
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="white"/>
|
||||
<path d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" fill="#D3D3D3"/>
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 571 B |
@@ -1,9 +0,0 @@
|
||||
<svg width="67" height="67" viewBox="0 0 67 67" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="black"/>
|
||||
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="#4A4A4A"/>
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="black"/>
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="black"/>
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="black"/>
|
||||
<path d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" fill="#4A4A4A"/>
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 571 B |
@@ -1,25 +0,0 @@
|
||||
<svg width="67" height="67" viewBox="0 0 67 67" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.logo-main {
|
||||
fill: #000000;
|
||||
}
|
||||
.logo-shadow {
|
||||
fill: #222222;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.logo-main {
|
||||
fill: #FFFFFF;
|
||||
}
|
||||
.logo-shadow {
|
||||
fill: #D3D3D3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<path class="logo-main" d="M22.21 67V44.6369H0V67H22.21Z"/>
|
||||
<path class="logo-shadow" d="M0 44.6369L22.21 46.8285V44.6369H0Z"/>
|
||||
<path class="logo-main" d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z"/>
|
||||
<path class="logo-main" d="M22.21 0H0V22.3184H22.21V0Z"/>
|
||||
<path class="logo-main" d="M66.7198 0H44.5098V22.3184H66.7198V0Z"/>
|
||||
<path class="logo-shadow" d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z"/>
|
||||
<path class="logo-main" d="M66.7198 67V44.6369H44.5098V67H66.7198Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 835 B |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,25 +1,10 @@
|
||||
<svg width="67" height="67" viewBox="0 0 67 67" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.logo-main {
|
||||
fill: #000000;
|
||||
}
|
||||
.logo-shadow {
|
||||
fill: #222222;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.logo-main {
|
||||
fill: #FFFFFF;
|
||||
}
|
||||
.logo-shadow {
|
||||
fill: #D3D3D3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<path class="logo-main" d="M22.21 67V44.6369H0V67H22.21Z"/>
|
||||
<path class="logo-shadow" d="M0 44.6369L22.21 46.8285V44.6369H0Z"/>
|
||||
<path class="logo-main" d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z"/>
|
||||
<path class="logo-main" d="M22.21 0H0V22.3184H22.21V0Z"/>
|
||||
<path class="logo-main" d="M66.7198 0H44.5098V22.3184H66.7198V0Z"/>
|
||||
<path class="logo-shadow" d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z"/>
|
||||
<path class="logo-main" d="M66.7198 67V44.6369H44.5098V67H66.7198Z"/>
|
||||
<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="64" height="64" rx="8" fill="#000000"/>
|
||||
<g transform="translate(8, 8) scale(0.716)">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="#ffffff"/>
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="#ffffff"/>
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="#ffffff"/>
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#ffffff"/>
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#ffffff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 836 B After Width: | Height: | Size: 536 B |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 60 KiB |
@@ -1,86 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="135.46666mm"
|
||||
height="135.46666mm"
|
||||
viewBox="0 0 135.46666 135.46666"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
sodipodi:docname="web-browser.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.829812"
|
||||
inkscape:cx="339.10587"
|
||||
inkscape:cy="281.44968"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1369"
|
||||
inkscape:window-x="1072"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs2"><linearGradient
|
||||
id="linearGradient1021"
|
||||
inkscape:collect="always"><stop
|
||||
style="stop-color:#6914d1;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1017" /><stop
|
||||
style="stop-color:#c82090;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop1019" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1021"
|
||||
id="linearGradient5957"
|
||||
x1="75.754601"
|
||||
y1="163.95738"
|
||||
x2="146.97395"
|
||||
y2="86.082359"
|
||||
gradientUnits="userSpaceOnUse" /></defs><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-38.978451,-51.992085)"><g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Layer 2"
|
||||
transform="translate(38.978451,51.992085)"
|
||||
style="fill:#000000;fill-opacity:1"><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke-width:34.9999"
|
||||
id="rect3228"
|
||||
width="135.46666"
|
||||
height="135.46666"
|
||||
x="0"
|
||||
y="0" /></g><g
|
||||
id="g5792"
|
||||
transform="matrix(0.10863854,0,0,0.10863854,51.849445,65.949185)"><path
|
||||
style="display:inline;fill:url(#linearGradient5957);fill-opacity:1;stroke-width:34.9999"
|
||||
id="path5949"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="106.16872"
|
||||
sodipodi:cy="120.26846"
|
||||
sodipodi:rx="53.232887"
|
||||
sodipodi:ry="53.232887"
|
||||
sodipodi:start="0.31945228"
|
||||
sodipodi:end="0.31361418"
|
||||
sodipodi:open="true"
|
||||
sodipodi:arc-type="arc"
|
||||
d="M 156.70842,136.98607 A 53.232887,53.232887 0 0 1 89.524891,170.83252 53.232887,53.232887 0 0 1 55.580426,103.69845 53.232887,53.232887 0 0 1 122.66487,69.656042 53.232887,53.232887 0 0 1 156.80516,136.69073"
|
||||
transform="matrix(9.2048366,0,0,9.2048366,-477.26567,-607.05147)" /><path
|
||||
d="m 500,10 c -0.1,0 -0.3,0 -0.4,0 -0.1,0 -0.1,0 -0.2,0 -0.2,0 -0.4,0 -0.6,0 C 228.7,10.6 10,229.8 10,500 c 0,270.2 218.7,489.3 488.8,490 0.2,0 0.4,0 0.6,0 0.1,0 0.1,0 0.2,0 0.2,0 0.3,0 0.4,0 C 770.6,990 990,770.6 990,500 990,229.4 770.6,10 500,10 Z m 19.6,293.2 c 51.9,-1.4 102.5,-8.3 151.2,-20.1 14.7,57.8 23.8,124.3 25.2,197.3 H 519.6 Z m 0,-39.2 V 52.3 C 572.4,66.9 626,137.4 660.1,245.4 614.8,256.3 567.9,262.7 519.6,264 Z M 480.4,51.8 V 264 c -48.7,-1.4 -96,-7.8 -141.6,-19 C 373.2,136.4 427.2,65.7 480.4,51.8 Z m 0,251.4 V 480.4 H 302.8 c 1.4,-73.1 10.6,-139.7 25.2,-197.5 49.1,12 100,18.9 152.4,20.3 z M 263.3,480.4 H 49.7 c 4.3,-100.8 41.9,-193.1 102,-266.2 43.6,24 89.9,43.7 138.4,58.4 -15.8,62.5 -25.3,133 -26.8,207.8 z m 0,39.2 c 1.4,74.8 10.9,145.2 26.8,207.8 -48.5,14.7 -94.8,34.4 -138.4,58.5 C 91.6,712.7 54,620.4 49.7,519.6 Z m 39.5,0 h 177.6 v 177 C 428,698 377.1,705 328,717 313.3,659.2 304.2,592.6 302.8,519.6 Z M 480.4,735.7 V 948.1 C 427.2,934.2 373.1,863.4 338.7,754.6 c 45.7,-11 93,-17.5 141.7,-18.9 z m 39.2,212 v -212 c 48.3,1.4 95.2,7.8 140.5,18.7 C 626,862.5 572.5,933.1 519.6,947.7 Z m 0,-251.1 v -177 H 696 C 694.6,592.5 685.5,659 670.8,716.7 622.1,704.8 571.6,698 519.6,696.6 Z m 215.8,-177 H 950.3 C 946,620.4 908.5,712.7 848.4,785.8 804.4,761.6 757.7,741.8 708.8,727 724.5,664.5 734,594.2 735.4,519.6 Z m 0,-39.2 C 734,405.7 724.5,335.3 708.7,272.8 757.6,258 804.3,238.2 848.2,214 c 60.2,73.1 97.7,165.5 102.1,266.3 z M 821.2,184.1 C 782.2,204.8 741,222 698.1,235 675.2,161.3 643,101.1 605,61.6 688.4,81.7 762.9,124.8 821.2,184.1 Z M 393.5,62 c -37.8,39.4 -69.9,99.3 -92.7,172.7 -42.6,-13 -83.4,-30 -122,-50.6 C 236.7,125.2 310.6,82.2 393.5,62 Z M 178.6,815.7 c 38.7,-20.6 79.5,-37.6 122.1,-50.6 22.8,73.4 54.9,133.4 92.7,172.9 C 310.6,917.8 236.6,874.7 178.6,815.7 Z m 426.3,122.6 c 38.1,-39.5 70.3,-99.7 93.2,-173.6 43,13.1 84.2,30.2 123.2,51 C 763,875.1 688.5,918.3 604.9,938.3 Z"
|
||||
id="path5790"
|
||||
style="fill:#000000;fill-opacity:1" /></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 427 B |
@@ -2,16 +2,16 @@
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<base href="/" />
|
||||
<meta name="theme-color" content="#171717" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="description" content="Chat - Unified interface to Agents, LLMs, MCPs and any AI model or OpenAPI documented API with full RAG stack" />
|
||||
<meta name="description" content="Hanzo Chat - AI chat platform with support for multiple AI models" />
|
||||
<title>Hanzo Chat</title>
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png" />
|
||||
<link rel="apple-touch-icon" href="/assets/apple-touch-icon-180x180.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/favicon-16x16.png" />
|
||||
<link rel="apple-touch-icon" href="assets/apple-touch-icon-180x180.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content" />
|
||||
<style>
|
||||
html,
|
||||
@@ -48,38 +48,38 @@
|
||||
`;
|
||||
document.head.appendChild(loadingContainerStyle);
|
||||
</script>
|
||||
<script type="module" crossorigin src="/assets/react-interactions.CDNIj_P0.js"></script>
|
||||
<script type="module" crossorigin src="/assets/markdown_highlight.Dt5gy-Cs.js"></script>
|
||||
<script type="module" crossorigin src="/assets/validation.CgW5gGeX.js"></script>
|
||||
<script type="module" crossorigin src="/assets/math-katex.DxUdIsOj.js"></script>
|
||||
<script type="module" crossorigin src="/assets/vendor.hYViCx_o.js"></script>
|
||||
<script type="module" crossorigin src="/assets/i18n.B6o-Gbrg.js"></script>
|
||||
<script type="module" crossorigin src="/assets/locales.CneDv1Po.js"></script>
|
||||
<script type="module" crossorigin src="/assets/routing.D6ZJbNew.js"></script>
|
||||
<script type="module" crossorigin src="/assets/radix-ui.zUF2t8pu.js"></script>
|
||||
<script type="module" crossorigin src="/assets/tanstack-vendor.CcfA9pap.js"></script>
|
||||
<script type="module" crossorigin src="/assets/http-client.B1ynDCuQ.js"></script>
|
||||
<script type="module" crossorigin src="/assets/date-utils.CHq2fTxU.js"></script>
|
||||
<script type="module" crossorigin src="/assets/utilities.D3AhyVZJ.js"></script>
|
||||
<script type="module" crossorigin src="/assets/forms.CgWlvBRM.js"></script>
|
||||
<script type="module" crossorigin src="/assets/framer-motion.BeyjVqYH.js"></script>
|
||||
<script type="module" crossorigin src="/assets/advanced-inputs.oQ6kIoBT.js"></script>
|
||||
<script type="module" crossorigin src="/assets/animations.C9kiQ0P7.js"></script>
|
||||
<script type="module" crossorigin src="/assets/security-ui.MEypZJRJ.js"></script>
|
||||
<script type="module" crossorigin src="/assets/markdown-processing.TTzZ1vwl.js"></script>
|
||||
<script type="module" crossorigin src="/assets/avatars.zbie9GOZ.js"></script>
|
||||
<script type="module" crossorigin src="/assets/headlessui.CpNfReFM.js"></script>
|
||||
<script type="module" crossorigin src="/assets/virtualization.CzFJ0wKU.js"></script>
|
||||
<script type="module" crossorigin src="/assets/heic-converter.CBfFuDy-.js"></script>
|
||||
<script type="module" crossorigin src="/assets/codemirror-state.ClnsKiKb.js"></script>
|
||||
<script type="module" crossorigin src="/assets/codemirror-view.yuH3vRs8.js"></script>
|
||||
<script type="module" crossorigin src="/assets/codemirror-language.B5LqEgWw.js"></script>
|
||||
<script type="module" crossorigin src="/assets/codemirror-core.K3HVILnM.js"></script>
|
||||
<script type="module" crossorigin src="/assets/sandpack.DtKLOr2o.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index.ChtrlAPT.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/math-katex.DAKDMjqk.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index.BhoPS7BO.css">
|
||||
<link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
||||
<script type="module" crossorigin src="./assets/react-interactions.CfyqjqXP.js"></script>
|
||||
<script type="module" crossorigin src="./assets/validation.DFZwsG5o.js"></script>
|
||||
<script type="module" crossorigin src="./assets/math-katex.DLu84ADl.js"></script>
|
||||
<script type="module" crossorigin src="./assets/markdown_highlight.ABKSddnD.js"></script>
|
||||
<script type="module" crossorigin src="./assets/vendor.Byl_tGc2.js"></script>
|
||||
<script type="module" crossorigin src="./assets/i18n.CA3mTzMG.js"></script>
|
||||
<script type="module" crossorigin src="./assets/locales.D47CaVtF.js"></script>
|
||||
<script type="module" crossorigin src="./assets/routing.CZbmXRkT.js"></script>
|
||||
<script type="module" crossorigin src="./assets/radix-ui.CVh3Dd4P.js"></script>
|
||||
<script type="module" crossorigin src="./assets/tanstack-vendor.DyoeZ73M.js"></script>
|
||||
<script type="module" crossorigin src="./assets/avatars.CwJDtxyh.js"></script>
|
||||
<script type="module" crossorigin src="./assets/advanced-inputs.w0JmX-rs.js"></script>
|
||||
<script type="module" crossorigin src="./assets/virtualization.CbKUaacL.js"></script>
|
||||
<script type="module" crossorigin src="./assets/animations.CbDvfLyt.js"></script>
|
||||
<script type="module" crossorigin src="./assets/headlessui.CJGpwcHH.js"></script>
|
||||
<script type="module" crossorigin src="./assets/framer-motion.C9OoZPLA.js"></script>
|
||||
<script type="module" crossorigin src="./assets/http-client.BNDKsQmf.js"></script>
|
||||
<script type="module" crossorigin src="./assets/utilities.Cp-QZ9vZ.js"></script>
|
||||
<script type="module" crossorigin src="./assets/date-utils.CHq2fTxU.js"></script>
|
||||
<script type="module" crossorigin src="./assets/forms.gP1Bt4Ju.js"></script>
|
||||
<script type="module" crossorigin src="./assets/security-ui.DNmv7C0T.js"></script>
|
||||
<script type="module" crossorigin src="./assets/markdown-processing.BGeF1fRm.js"></script>
|
||||
<script type="module" crossorigin src="./assets/codemirror-state.C-fPAHjK.js"></script>
|
||||
<script type="module" crossorigin src="./assets/codemirror-view.Dyel3EV1.js"></script>
|
||||
<script type="module" crossorigin src="./assets/codemirror-language.BdbQ9O-9.js"></script>
|
||||
<script type="module" crossorigin src="./assets/codemirror-core.DeBwLQXr.js"></script>
|
||||
<script type="module" crossorigin src="./assets/sandpack.DnyQb158.js"></script>
|
||||
<script type="module" crossorigin src="./assets/heic-converter.-u32bK9M.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index.BzPea_a_.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/math-katex.f1Jb2Qab.css">
|
||||
<link rel="stylesheet" crossorigin href="./assets/index.CbU1k9ZB.css">
|
||||
<link rel="manifest" href="./manifest.webmanifest" crossorigin="use-credentials"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
|
||||
<body>
|
||||
<div id="root">
|
||||
<div id="loading-container"></div>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"name":"Hanzo","short_name":"Hanzo","description":"Hanzo Chat Frontend - Modern AI Chat Interface","start_url":"/","display":"standalone","background_color":"#000000","theme_color":"#009688","lang":"en","scope":"/","icons":[{"src":"/assets/favicon-32x32.png","sizes":"32x32","type":"image/png"},{"src":"/assets/favicon-16x16.png","sizes":"16x16","type":"image/png"},{"src":"/assets/apple-touch-icon-180x180.png","sizes":"180x180","type":"image/png"},{"src":"/assets/icon-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/assets/maskable-icon.png","sizes":"512x512","type":"image/png","purpose":"maskable"}]}
|
||||
{"name":"Hanzo Chat","short_name":"Hanzo Chat","description":"","start_url":"/","display":"standalone","background_color":"#000000","theme_color":"#fd4444","lang":"en","scope":"./","icons":[{"src":"assets/favicon-32x32.png","sizes":"32x32","type":"image/png"},{"src":"assets/favicon-16x16.png","sizes":"16x16","type":"image/png"},{"src":"assets/apple-touch-icon-180x180.png","sizes":"180x180","type":"image/png"},{"src":"assets/icon-192x192.png","sizes":"192x192","type":"image/png"},{"src":"assets/maskable-icon.png","sizes":"512x512","type":"image/png","purpose":"maskable"}]}
|
||||
|
||||
@@ -1 +1 @@
|
||||
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
||||
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('./sw.js', { scope: './' })})}
|
||||
@@ -1 +1 @@
|
||||
if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,r)=>{const n=s||("document"in self?document.currentScript.src:"")||location.href;if(e[n])return;let t={};const u=s=>i(s,n),o={module:{uri:n},exports:t,require:u};e[n]=Promise.all(l.map(s=>o[s]||u(s))).then(s=>(r(...s),t))}}define(["./workbox-4c320e2c"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"assets/AccountSettings.BX_UYV36.js",revision:null},{url:"assets/advanced-inputs.oQ6kIoBT.js",revision:null},{url:"assets/animations.C9kiQ0P7.js",revision:null},{url:"assets/avatars.zbie9GOZ.js",revision:null},{url:"assets/BookmarkNav.C-AY-f8K.js",revision:null},{url:"assets/codemirror-core.K3HVILnM.js",revision:null},{url:"assets/codemirror-language.B5LqEgWw.js",revision:null},{url:"assets/codemirror-state.ClnsKiKb.js",revision:null},{url:"assets/codemirror-view.yuH3vRs8.js",revision:null},{url:"assets/date-utils.CHq2fTxU.js",revision:null},{url:"assets/forms.CgWlvBRM.js",revision:null},{url:"assets/framer-motion.BeyjVqYH.js",revision:null},{url:"assets/headlessui.CpNfReFM.js",revision:null},{url:"assets/heic-converter.CBfFuDy-.js",revision:null},{url:"assets/http-client.B1ynDCuQ.js",revision:null},{url:"assets/i18n.B6o-Gbrg.js",revision:null},{url:"assets/index.BhoPS7BO.css",revision:null},{url:"assets/index.ChtrlAPT.js",revision:null},{url:"assets/locales.CneDv1Po.js",revision:null},{url:"assets/markdown_highlight.Dt5gy-Cs.js",revision:null},{url:"assets/markdown-processing.TTzZ1vwl.js",revision:null},{url:"assets/math-katex.DAKDMjqk.css",revision:null},{url:"assets/math-katex.DxUdIsOj.js",revision:null},{url:"assets/radix-ui.zUF2t8pu.js",revision:null},{url:"assets/react-interactions.CDNIj_P0.js",revision:null},{url:"assets/routing.D6ZJbNew.js",revision:null},{url:"assets/sandpack.DtKLOr2o.js",revision:null},{url:"assets/security-ui.MEypZJRJ.js",revision:null},{url:"assets/tanstack-vendor.CcfA9pap.js",revision:null},{url:"assets/utilities.D3AhyVZJ.js",revision:null},{url:"assets/validation.CgW5gGeX.js",revision:null},{url:"assets/vendor.hYViCx_o.js",revision:null},{url:"assets/virtualization.CzFJ0wKU.js",revision:null},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"manifest.webmanifest",revision:"df5fe024fb89bdcd2bdbb079181799c0"},{url:"manifest.webmanifest",revision:"df5fe024fb89bdcd2bdbb079181799c0"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"),{denylist:[/^\/oauth/,/^\/api/]}))});
|
||||
if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,r)=>{const n=s||("document"in self?document.currentScript.src:"")||location.href;if(e[n])return;let t={};const u=s=>i(s,n),o={module:{uri:n},exports:t,require:u};e[n]=Promise.all(l.map(s=>o[s]||u(s))).then(s=>(r(...s),t))}}define(["./workbox-7fc22fbe"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"assets/virtualization.CbKUaacL.js",revision:null},{url:"assets/vendor.Byl_tGc2.js",revision:null},{url:"assets/validation.DFZwsG5o.js",revision:null},{url:"assets/utilities.Cp-QZ9vZ.js",revision:null},{url:"assets/tanstack-vendor.DyoeZ73M.js",revision:null},{url:"assets/security-ui.DNmv7C0T.js",revision:null},{url:"assets/sandpack.DnyQb158.js",revision:null},{url:"assets/routing.CZbmXRkT.js",revision:null},{url:"assets/react-interactions.CfyqjqXP.js",revision:null},{url:"assets/radix-ui.CVh3Dd4P.js",revision:null},{url:"assets/mermaid.BzRMe_od.js",revision:null},{url:"assets/math-katex.f1Jb2Qab.css",revision:null},{url:"assets/math-katex.DLu84ADl.js",revision:null},{url:"assets/markdown_highlight.ABKSddnD.js",revision:null},{url:"assets/markdown-processing.BGeF1fRm.js",revision:null},{url:"assets/locales.D47CaVtF.js",revision:null},{url:"assets/index.CbU1k9ZB.css",revision:null},{url:"assets/index.BzPea_a_.js",revision:null},{url:"assets/i18n.CA3mTzMG.js",revision:null},{url:"assets/http-client.BNDKsQmf.js",revision:null},{url:"assets/heic-converter.-u32bK9M.js",revision:null},{url:"assets/headlessui.CJGpwcHH.js",revision:null},{url:"assets/framer-motion.C9OoZPLA.js",revision:null},{url:"assets/forms.gP1Bt4Ju.js",revision:null},{url:"assets/date-utils.CHq2fTxU.js",revision:null},{url:"assets/codemirror-view.Dyel3EV1.js",revision:null},{url:"assets/codemirror-state.C-fPAHjK.js",revision:null},{url:"assets/codemirror-language.BdbQ9O-9.js",revision:null},{url:"assets/codemirror-core.DeBwLQXr.js",revision:null},{url:"assets/avatars.CwJDtxyh.js",revision:null},{url:"assets/animations.CbDvfLyt.js",revision:null},{url:"assets/advanced-inputs.w0JmX-rs.js",revision:null},{url:"assets/BookmarkNav.B6VVre05.js",revision:null},{url:"assets/AccountSettings.BSt_pskB.js",revision:null},{url:"manifest.webmanifest",revision:"8d1943f9698bf1604968186da99f2fdf"},{url:"manifest.webmanifest",revision:"8d1943f9698bf1604968186da99f2fdf"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"),{denylist:[/^\/oauth/,/^\/api/]}))});
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^6.4.1",
|
||||
"vite-plugin-compression2": "^2.2.1",
|
||||
"vite-plugin-node-polyfills": "^0.23.0",
|
||||
"vite-plugin-node-polyfills": "^0.25.0",
|
||||
"vite-plugin-pwa": "^0.21.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,36 @@ import { getLoginError } from '~/utils';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import LoginForm from './LoginForm';
|
||||
|
||||
/**
|
||||
* Build Hanzo IAM OIDC authorize URL from env vars.
|
||||
* Used in static SPA mode when VITE_HANZO_IAM_URL is set.
|
||||
*/
|
||||
function getHanzoIamUrl(): string | null {
|
||||
const iamUrl = import.meta.env.VITE_HANZO_IAM_URL;
|
||||
const appId = import.meta.env.VITE_HANZO_IAM_APP;
|
||||
const org = import.meta.env.VITE_HANZO_IAM_ORG;
|
||||
|
||||
if (!iamUrl || !appId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const redirectUri = `${window.location.origin}/auth/callback`;
|
||||
const state = `hanzo-chat-${Date.now()}`;
|
||||
|
||||
// Store state for CSRF verification
|
||||
sessionStorage.setItem('oauth_state', state);
|
||||
|
||||
const params = new URLSearchParams({
|
||||
client_id: appId,
|
||||
redirect_uri: redirectUri,
|
||||
response_type: 'code',
|
||||
state,
|
||||
scope: 'openid profile email',
|
||||
});
|
||||
|
||||
return `${iamUrl}/login/oauth/authorize?${params.toString()}`;
|
||||
}
|
||||
|
||||
function Login() {
|
||||
const localize = useLocalize();
|
||||
const { showToast } = useToastContext();
|
||||
@@ -23,6 +53,10 @@ function Login() {
|
||||
// Persist the disable flag locally so that once detected, auto-redirect stays disabled.
|
||||
const [isAutoRedirectDisabled, setIsAutoRedirectDisabled] = useState(disableAutoRedirect);
|
||||
|
||||
// Check if we're in static/IAM mode
|
||||
const hanzoIamUrl = getHanzoIamUrl();
|
||||
const isStaticMode = !!import.meta.env.VITE_HANZO_API_URL;
|
||||
|
||||
useEffect(() => {
|
||||
const oauthError = searchParams?.get('error');
|
||||
if (oauthError && oauthError === ErrorTypes.AUTH_FAILED) {
|
||||
@@ -46,44 +80,54 @@ function Login() {
|
||||
}
|
||||
}, [disableAutoRedirect, searchParams, setSearchParams]);
|
||||
|
||||
// Determine whether we should auto-redirect to OpenID.
|
||||
// Determine whether we should auto-redirect to OpenID or Hanzo IAM
|
||||
const shouldAutoRedirect =
|
||||
startupConfig?.openidLoginEnabled &&
|
||||
startupConfig?.openidAutoRedirect &&
|
||||
startupConfig?.serverDomain &&
|
||||
!isAutoRedirectDisabled;
|
||||
!isAutoRedirectDisabled &&
|
||||
((startupConfig?.openidLoginEnabled &&
|
||||
startupConfig?.openidAutoRedirect &&
|
||||
startupConfig?.serverDomain) ||
|
||||
(isStaticMode && hanzoIamUrl));
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldAutoRedirect) {
|
||||
console.log('Auto-redirecting to OpenID provider...');
|
||||
window.location.href = `${startupConfig.serverDomain}/oauth/openid`;
|
||||
if (isStaticMode && hanzoIamUrl) {
|
||||
console.log('Auto-redirecting to Hanzo IAM...');
|
||||
window.location.href = hanzoIamUrl;
|
||||
} else if (startupConfig?.serverDomain) {
|
||||
console.log('Auto-redirecting to OpenID provider...');
|
||||
window.location.href = `${startupConfig.serverDomain}/oauth/openid`;
|
||||
}
|
||||
}
|
||||
}, [shouldAutoRedirect, startupConfig]);
|
||||
}, [shouldAutoRedirect, startupConfig, isStaticMode, hanzoIamUrl]);
|
||||
|
||||
// Render fallback UI if auto-redirect is active.
|
||||
if (shouldAutoRedirect) {
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col items-center justify-center p-4">
|
||||
<p className="text-lg font-semibold">
|
||||
{localize('com_ui_redirecting_to_provider', { 0: startupConfig.openidLabel })}
|
||||
{isStaticMode
|
||||
? 'Redirecting to Hanzo...'
|
||||
: localize('com_ui_redirecting_to_provider', { 0: startupConfig?.openidLabel })}
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<SocialButton
|
||||
key="openid"
|
||||
enabled={startupConfig.openidLoginEnabled}
|
||||
serverDomain={startupConfig.serverDomain}
|
||||
oauthPath="openid"
|
||||
Icon={() =>
|
||||
startupConfig.openidImageUrl ? (
|
||||
<img src={startupConfig.openidImageUrl} alt="OpenID Logo" className="h-5 w-5" />
|
||||
) : (
|
||||
<OpenIDIcon />
|
||||
)
|
||||
}
|
||||
label={startupConfig.openidLabel}
|
||||
id="openid"
|
||||
/>
|
||||
</div>
|
||||
{!isStaticMode && startupConfig && (
|
||||
<div className="mt-4">
|
||||
<SocialButton
|
||||
key="openid"
|
||||
enabled={startupConfig.openidLoginEnabled}
|
||||
serverDomain={startupConfig.serverDomain}
|
||||
oauthPath="openid"
|
||||
Icon={() =>
|
||||
startupConfig.openidImageUrl ? (
|
||||
<img src={startupConfig.openidImageUrl} alt="OpenID Logo" className="h-5 w-5" />
|
||||
) : (
|
||||
<OpenIDIcon />
|
||||
)
|
||||
}
|
||||
label={startupConfig.openidLabel}
|
||||
id="openid"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -91,7 +135,24 @@ function Login() {
|
||||
return (
|
||||
<>
|
||||
{error != null && <ErrorMessage>{localize(getLoginError(error))}</ErrorMessage>}
|
||||
{startupConfig?.emailLoginEnabled === true && (
|
||||
|
||||
{/* Hanzo IAM button (static mode) */}
|
||||
{isStaticMode && hanzoIamUrl && (
|
||||
<div className="mt-4">
|
||||
<a
|
||||
href={hanzoIamUrl}
|
||||
className="flex w-full items-center justify-center space-x-3 rounded-2xl border border-border-light bg-surface-primary px-5 py-3 text-text-primary transition-colors duration-200 hover:bg-surface-tertiary"
|
||||
>
|
||||
<svg className="h-5 w-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
||||
</svg>
|
||||
<p>Sign in with Hanzo</p>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Email/password form (non-static mode or as fallback) */}
|
||||
{startupConfig?.emailLoginEnabled === true && !isStaticMode && (
|
||||
<LoginForm
|
||||
onSubmit={login}
|
||||
startupConfig={startupConfig}
|
||||
@@ -99,7 +160,7 @@ function Login() {
|
||||
setError={setError}
|
||||
/>
|
||||
)}
|
||||
{startupConfig?.registrationEnabled === true && (
|
||||
{startupConfig?.registrationEnabled === true && !isStaticMode && (
|
||||
<p className="my-4 text-center text-sm font-light text-gray-700 dark:text-white">
|
||||
{' '}
|
||||
{localize('com_auth_no_account')}{' '}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* OAuth Callback Handler for Hanzo IAM (hanzo.id)
|
||||
*
|
||||
* Flow:
|
||||
* 1. User clicks "Sign in" → redirects to hanzo.id OIDC
|
||||
* 2. After auth, hanzo.id redirects back with ?code=xxx&state=yyy
|
||||
* 3. This component exchanges the code via cloud gateway /api/signin
|
||||
* 4. Gateway sets session cookie, returns user claims + access token
|
||||
* 5. We set the auth context and redirect to /c/new
|
||||
*/
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useSearchParams, useNavigate } from 'react-router-dom';
|
||||
import { setTokenHeader, dataService } from 'librechat-data-provider';
|
||||
import { Spinner } from '@librechat/client';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
|
||||
export default function OAuthCallback() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const { login } = useAuthContext();
|
||||
const exchangedRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (exchangedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const code = searchParams.get('code');
|
||||
const state = searchParams.get('state');
|
||||
|
||||
if (!code || !state) {
|
||||
console.error('Missing code or state in OAuth callback');
|
||||
navigate('/login', { replace: true });
|
||||
return;
|
||||
}
|
||||
|
||||
exchangedRef.current = true;
|
||||
|
||||
// Exchange code for session via cloud gateway
|
||||
const exchangeCode = async () => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${import.meta.env.VITE_HANZO_API_URL || ''}/api/signin?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Signin failed: ${response.status}`);
|
||||
}
|
||||
|
||||
const body = await response.json();
|
||||
const claims = body.status === 'ok' ? body.data : body;
|
||||
|
||||
// Set the access token if present
|
||||
if (claims?.accessToken || claims?.AccessToken) {
|
||||
const token = claims.accessToken || claims.AccessToken;
|
||||
setTokenHeader(token);
|
||||
}
|
||||
|
||||
// Navigate to chat
|
||||
navigate('/c/new', { replace: true });
|
||||
} catch (err) {
|
||||
console.error('OAuth code exchange failed:', err);
|
||||
navigate('/login?error=auth_failed', { replace: true });
|
||||
}
|
||||
};
|
||||
|
||||
exchangeCode();
|
||||
}, [searchParams, navigate, login]);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<div className="text-center">
|
||||
<Spinner className="mx-auto mb-4 h-8 w-8" />
|
||||
<p className="text-text-secondary">Signing in...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -130,10 +130,31 @@ const thirdPartyModels = [
|
||||
/* Component */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
function getLoginHref(serverDomain: string): string {
|
||||
// Static mode: build Hanzo IAM OIDC URL
|
||||
const iamUrl = import.meta.env.VITE_HANZO_IAM_URL;
|
||||
const appId = import.meta.env.VITE_HANZO_IAM_APP;
|
||||
if (iamUrl && appId) {
|
||||
const redirectUri = `${window.location.origin}/auth/callback`;
|
||||
const state = `hanzo-chat-${Date.now()}`;
|
||||
sessionStorage.setItem('oauth_state', state);
|
||||
const params = new URLSearchParams({
|
||||
client_id: appId,
|
||||
redirect_uri: redirectUri,
|
||||
response_type: 'code',
|
||||
state,
|
||||
scope: 'openid profile email',
|
||||
});
|
||||
return `${iamUrl}/login/oauth/authorize?${params.toString()}`;
|
||||
}
|
||||
// Backend mode: OAuth via server
|
||||
return `${serverDomain}/oauth/openid`;
|
||||
}
|
||||
|
||||
export default function LandingPage() {
|
||||
const { data: config } = useGetStartupConfig();
|
||||
const serverDomain = config?.serverDomain || '';
|
||||
const loginHref = `${serverDomain}/oauth/openid`;
|
||||
const loginHref = getLoginHref(serverDomain);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -141,8 +141,12 @@ const AuthContextProvider = ({
|
||||
const { user, token = '' } = data ?? {};
|
||||
if (token) {
|
||||
setUserContext({ token, isAuthenticated: true, user });
|
||||
} else if (user) {
|
||||
// Session-based auth: no JWT token, but user data means session is valid
|
||||
// Use a sentinel value so isAuthenticated works
|
||||
setUserContext({ token: 'session', isAuthenticated: true, user });
|
||||
} else {
|
||||
console.log('Token is not present. User is not authenticated.');
|
||||
console.log('No valid session. User is not authenticated.');
|
||||
if (authConfig?.test === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TwoFactorScreen,
|
||||
RequestPasswordReset,
|
||||
} from '~/components/Auth';
|
||||
import OAuthCallback from '~/components/Auth/OAuthCallback';
|
||||
import { MarketplaceProvider } from '~/components/Agents/MarketplaceContext';
|
||||
import AgentMarketplace from '~/components/Agents/Marketplace';
|
||||
import { OAuthSuccess, OAuthError } from '~/components/OAuth';
|
||||
@@ -38,6 +39,15 @@ export const router = createBrowserRouter(
|
||||
element: <ShareRoute />,
|
||||
errorElement: <RouteErrorBoundary />,
|
||||
},
|
||||
{
|
||||
path: 'auth/callback',
|
||||
element: (
|
||||
<AuthContextProvider>
|
||||
<OAuthCallback />
|
||||
</AuthContextProvider>
|
||||
),
|
||||
errorElement: <RouteErrorBoundary />,
|
||||
},
|
||||
{
|
||||
path: 'oauth',
|
||||
errorElement: <RouteErrorBoundary />,
|
||||
|
||||
@@ -8,9 +8,24 @@ import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
// When VITE_HANZO_API_URL is set, the frontend talks directly to the cloud gateway
|
||||
// and no local backend proxy is needed (static SPA mode).
|
||||
const hanzoApiUrl = process.env.VITE_HANZO_API_URL;
|
||||
const backendPort = process.env.BACKEND_PORT && Number(process.env.BACKEND_PORT) || 3080;
|
||||
const backendURL = process.env.HOST ? `http://${process.env.HOST}:${backendPort}` : `http://localhost:${backendPort}`;
|
||||
|
||||
// Only proxy to local backend if not using cloud gateway directly
|
||||
const devProxy = hanzoApiUrl ? {} : {
|
||||
'/api': {
|
||||
target: backendURL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/oauth': {
|
||||
target: backendURL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default defineConfig(({ command }) => ({
|
||||
base: '',
|
||||
server: {
|
||||
@@ -18,20 +33,11 @@ export default defineConfig(({ command }) => ({
|
||||
host: process.env.HOST || 'localhost',
|
||||
port: process.env.PORT && Number(process.env.PORT) || 3090,
|
||||
strictPort: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: backendURL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/oauth': {
|
||||
target: backendURL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
proxy: devProxy,
|
||||
},
|
||||
// Set the directory where environment variables are loaded from and restrict prefixes
|
||||
envDir: '../',
|
||||
envPrefix: ['VITE_', 'SCRIPT_', 'DOMAIN_', 'ALLOW_'],
|
||||
envPrefix: ['VITE_', 'SCRIPT_', 'DOMAIN_', 'ALLOW_', 'HANZO_'],
|
||||
plugins: [
|
||||
react(),
|
||||
nodePolyfills(),
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
model_list:
|
||||
- model_name: "gpt-4"
|
||||
llm_params:
|
||||
model: openai/fake
|
||||
api_key: fake-key
|
||||
api_base: https://exampleopenaiendpoint-production.up.railway.app/
|
||||
|
||||
general_settings:
|
||||
alerting: ["slack"]
|
||||
@@ -0,0 +1,61 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: chat
|
||||
namespace: hanzo
|
||||
labels:
|
||||
app: chat
|
||||
app.kubernetes.io/managed-by: hanzo-universe
|
||||
app.kubernetes.io/name: chat
|
||||
app.kubernetes.io/part-of: hanzo-platform
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: chat
|
||||
app.kubernetes.io/managed-by: hanzo-universe
|
||||
app.kubernetes.io/name: chat
|
||||
app.kubernetes.io/part-of: hanzo-platform
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: chat
|
||||
app.kubernetes.io/managed-by: hanzo-universe
|
||||
app.kubernetes.io/name: chat
|
||||
app.kubernetes.io/part-of: hanzo-platform
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: ghcr-secret
|
||||
containers:
|
||||
- name: chat
|
||||
image: ghcr.io/hanzoai/chat:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3080
|
||||
# Static file server — simple TCP check
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 3080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 30
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 3080
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
@@ -51,6 +51,7 @@
|
||||
"build": "npx turbo run build",
|
||||
"frontend": "npm run build:data-provider && npm run build:data-schemas && npm run build:api && npm run build:client-package && cd client && npm run build",
|
||||
"frontend:ci": "npm run build:data-provider && npm run build:client-package && cd client && npm run build:ci",
|
||||
"build:static": "cp .env.static .env && npm run build:data-provider && npm run build:client-package && cd client && npm run build",
|
||||
"frontend:dev": "cd client && npm run dev",
|
||||
"e2e": "playwright test --config=e2e/playwright.config.local.ts",
|
||||
"e2e:headed": "playwright test --config=e2e/playwright.config.local.ts --headed",
|
||||
|
||||
@@ -1,12 +1,64 @@
|
||||
/**
|
||||
* Hanzo Cloud Gateway API Endpoints
|
||||
*
|
||||
* Single source of truth for all API URLs.
|
||||
* The cloud gateway at api.hanzo.ai provides:
|
||||
* - REST endpoints for CRUD (chats, messages, files, auth)
|
||||
* - OpenAI/Anthropic-compatible LLM endpoints
|
||||
* - ZAP WebSocket for streaming & MCP tools
|
||||
*
|
||||
* No backward compat, no adapter layers. One way to do everything.
|
||||
*/
|
||||
import type { AssistantsEndpoint } from './schemas';
|
||||
import * as q from './types/queries';
|
||||
import { ResourceType } from './accessPermissions';
|
||||
/** Runtime override for API base URL */
|
||||
export declare function setApiBaseUrl(url: string): void;
|
||||
export declare const apiBaseUrl: () => string;
|
||||
/** ZAP WebSocket URL (derived from API base, or explicit) */
|
||||
export declare function zapUrl(): string;
|
||||
export declare const health: () => string;
|
||||
export declare const systemInfo: () => string;
|
||||
export declare const versionInfo: () => string;
|
||||
/** Sign in via hanzo.id OAuth code exchange */
|
||||
export declare const signin: (code: string, state: string) => string;
|
||||
/** Sign out */
|
||||
export declare const signout: () => string;
|
||||
/** Get current account (session-based) */
|
||||
export declare const getAccount: () => string;
|
||||
export declare const login: () => string;
|
||||
export declare const logout: () => string;
|
||||
export declare const register: () => string;
|
||||
export declare const refreshToken: (retry?: boolean) => string;
|
||||
export declare const user: () => string;
|
||||
export declare const loginPage: () => string;
|
||||
export declare const registerPage: () => string;
|
||||
export declare const loginFacebook: () => string;
|
||||
export declare const loginGoogle: () => string;
|
||||
export declare const verifyEmail: () => string;
|
||||
export declare const resendVerificationEmail: () => string;
|
||||
export declare const requestPasswordReset: () => string;
|
||||
export declare const resetPassword: () => string;
|
||||
export declare const enableTwoFactor: () => string;
|
||||
export declare const verifyTwoFactor: () => string;
|
||||
export declare const confirmTwoFactor: () => string;
|
||||
export declare const disableTwoFactor: () => string;
|
||||
export declare const regenerateBackupCodes: () => string;
|
||||
export declare const verifyTwoFactorTemp: () => string;
|
||||
export declare const balance: () => string;
|
||||
export declare const userPlugins: () => string;
|
||||
export declare const deleteUser: () => string;
|
||||
export declare const conversationsRoot: string;
|
||||
export declare const conversations: (params: q.ConversationListParams) => string;
|
||||
export declare const conversationById: (id: string) => string;
|
||||
export declare const genTitle: (conversationId: string) => string;
|
||||
export declare const updateConversation: () => string;
|
||||
export declare const archiveConversation: () => string;
|
||||
export declare const deleteConversation: () => string;
|
||||
export declare const deleteAllConversation: () => string;
|
||||
export declare const importConversation: () => string;
|
||||
export declare const forkConversation: () => string;
|
||||
export declare const duplicateConversation: () => string;
|
||||
export declare const messages: (params: q.MessagesListParams) => string;
|
||||
export declare const messagesArtifacts: (messageId: string) => string;
|
||||
export declare const messagesBranch: () => string;
|
||||
@@ -21,65 +73,19 @@ export declare const revokeUserKey: (name: string) => string;
|
||||
export declare const revokeAllUserKeys: () => string;
|
||||
export declare const apiKeys: () => string;
|
||||
export declare const apiKeyById: (id: string) => string;
|
||||
export declare const conversationsRoot: string;
|
||||
export declare const conversations: (params: q.ConversationListParams) => string;
|
||||
export declare const conversationById: (id: string) => string;
|
||||
export declare const genTitle: (conversationId: string) => string;
|
||||
export declare const updateConversation: () => string;
|
||||
export declare const archiveConversation: () => string;
|
||||
export declare const deleteConversation: () => string;
|
||||
export declare const deleteAllConversation: () => string;
|
||||
export declare const importConversation: () => string;
|
||||
export declare const forkConversation: () => string;
|
||||
export declare const duplicateConversation: () => string;
|
||||
export declare const search: (q: string, cursor?: string | null) => string;
|
||||
export declare const searchEnabled: () => string;
|
||||
export declare const presets: () => string;
|
||||
export declare const deletePreset: () => string;
|
||||
export declare const plugins: () => string;
|
||||
export declare const config: () => string;
|
||||
export declare const aiEndpoints: () => string;
|
||||
export declare const models: () => string;
|
||||
export declare const tokenizer: () => string;
|
||||
export declare const login: () => string;
|
||||
export declare const logout: () => string;
|
||||
export declare const register: () => string;
|
||||
export declare const loginFacebook: () => string;
|
||||
export declare const loginGoogle: () => string;
|
||||
export declare const refreshToken: (retry?: boolean) => string;
|
||||
export declare const requestPasswordReset: () => string;
|
||||
export declare const resetPassword: () => string;
|
||||
export declare const verifyEmail: () => string;
|
||||
export declare const loginPage: () => string;
|
||||
export declare const registerPage: () => string;
|
||||
export declare const resendVerificationEmail: () => string;
|
||||
export declare const plugins: () => string;
|
||||
export declare const mcpReinitialize: (serverName: string) => string;
|
||||
export declare const mcpConnectionStatus: () => string;
|
||||
export declare const mcpServerConnectionStatus: (serverName: string) => string;
|
||||
export declare const mcpAuthValues: (serverName: string) => string;
|
||||
export declare const cancelMCPOAuth: (serverName: string) => string;
|
||||
export declare const mcpOAuthBind: (serverName: string) => string;
|
||||
export declare const actionOAuthBind: (actionId: string) => string;
|
||||
export declare const config: () => string;
|
||||
export declare const prompts: () => string;
|
||||
export declare const addPromptToGroup: (groupId: string) => string;
|
||||
export declare const assistants: ({ path, options, version, endpoint, isAvatar, }: {
|
||||
path?: string;
|
||||
options?: object;
|
||||
endpoint?: AssistantsEndpoint;
|
||||
version: number | string;
|
||||
isAvatar?: boolean;
|
||||
}) => string;
|
||||
export declare const agents: ({ path, options }: {
|
||||
path?: string;
|
||||
options?: object;
|
||||
}) => string;
|
||||
export declare const activeJobs: () => string;
|
||||
export declare const mcp: {
|
||||
tools: string;
|
||||
servers: string;
|
||||
};
|
||||
export declare const mcpServer: (serverName: string) => string;
|
||||
export declare const revertAgentVersion: (agent_id: string) => string;
|
||||
export declare const chatCompletions: () => string;
|
||||
export declare const anthropicMessages: () => string;
|
||||
export declare const providers: () => string;
|
||||
export declare const provider: (id: string) => string;
|
||||
export declare const files: () => string;
|
||||
export declare const fileUpload: () => string;
|
||||
export declare const fileDelete: () => string;
|
||||
@@ -94,6 +100,34 @@ export declare const textToSpeech: () => string;
|
||||
export declare const textToSpeechManual: () => string;
|
||||
export declare const textToSpeechVoices: () => string;
|
||||
export declare const getCustomConfigSpeech: () => string;
|
||||
export declare const assistants: ({ path, options, version, endpoint, isAvatar, }: {
|
||||
path?: string;
|
||||
options?: object;
|
||||
endpoint?: AssistantsEndpoint;
|
||||
version: number | string;
|
||||
isAvatar?: boolean;
|
||||
}) => string;
|
||||
export declare const agents: ({ path, options }: {
|
||||
path?: string;
|
||||
options?: object;
|
||||
}) => string;
|
||||
export declare const activeJobs: () => string;
|
||||
export declare const revertAgentVersion: (agent_id: string) => string;
|
||||
export declare const mcp: {
|
||||
tools: string;
|
||||
servers: string;
|
||||
};
|
||||
export declare const mcpServer: (serverName: string) => string;
|
||||
export declare const mcpReinitialize: (serverName: string) => string;
|
||||
export declare const mcpConnectionStatus: () => string;
|
||||
export declare const mcpServerConnectionStatus: (serverName: string) => string;
|
||||
export declare const mcpAuthValues: (serverName: string) => string;
|
||||
export declare const cancelMCPOAuth: (serverName: string) => string;
|
||||
export declare const mcpOAuthBind: (serverName: string) => string;
|
||||
export declare const actionOAuthBind: (actionId: string) => string;
|
||||
export declare const refreshMcpTools: () => string;
|
||||
export declare const prompts: () => string;
|
||||
export declare const addPromptToGroup: (groupId: string) => string;
|
||||
export declare const getPromptGroup: (_id: string) => string;
|
||||
export declare const getPromptGroupsWithFilters: (filter: object) => string;
|
||||
export declare const getPromptsWithFilters: (filter: object) => string;
|
||||
@@ -126,12 +160,6 @@ export declare const userTerms: () => string;
|
||||
export declare const acceptUserTerms: () => string;
|
||||
export declare const banner: () => string;
|
||||
export declare const feedback: (conversationId: string, messageId: string) => string;
|
||||
export declare const enableTwoFactor: () => string;
|
||||
export declare const verifyTwoFactor: () => string;
|
||||
export declare const confirmTwoFactor: () => string;
|
||||
export declare const disableTwoFactor: () => string;
|
||||
export declare const regenerateBackupCodes: () => string;
|
||||
export declare const verifyTwoFactorTemp: () => string;
|
||||
export declare const memories: () => string;
|
||||
export declare const memory: (key: string) => string;
|
||||
export declare const memoryPreferences: () => string;
|
||||
@@ -142,3 +170,14 @@ export declare const updateResourcePermissions: (resourceType: ResourceType, res
|
||||
export declare const getEffectivePermissions: (resourceType: ResourceType, resourceId: string) => string;
|
||||
export declare const getAllEffectivePermissions: (resourceType: ResourceType) => string;
|
||||
export declare const graphToken: (scopes: string) => string;
|
||||
export declare const stores: () => string;
|
||||
export declare const store: (id: string) => string;
|
||||
export declare const addStore: () => string;
|
||||
export declare const updateStore: () => string;
|
||||
export declare const deleteStore: () => string;
|
||||
export declare const refreshStoreVectors: () => string;
|
||||
export declare const vectors: () => string;
|
||||
export declare const addVector: () => string;
|
||||
export declare const deleteVector: () => string;
|
||||
export declare const workflows: () => string;
|
||||
export declare const tasks: () => string;
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
export declare function setAcceptLanguageHeader(value: string): void;
|
||||
export declare function setTokenHeader(token: string): void;
|
||||
/**
|
||||
* Set a publishable key (pk-) as the default auth header.
|
||||
* Used for unauthenticated access (model listing, health checks).
|
||||
*/
|
||||
export declare function setPublishableKeyHeader(key: string): void;
|
||||
/**
|
||||
* Enable cross-origin credentials for cloud gateway requests.
|
||||
* Required when frontend (hanzo.chat) talks to api.hanzo.ai.
|
||||
*/
|
||||
export declare function enableCrossOriginCredentials(): void;
|
||||
|
||||
@@ -23,10 +23,12 @@ export * from './types/graph';
|
||||
export * from './accessPermissions';
|
||||
export * from './keys';
|
||||
export * from './headers-helpers';
|
||||
export { loginPage, registerPage, apiBaseUrl } from './api-endpoints';
|
||||
export { default as request } from './request';
|
||||
export { loginPage, registerPage, apiBaseUrl, setApiBaseUrl, zapUrl } from './api-endpoints';
|
||||
export { default as request, setPublishableKey, getWithPk } from './request';
|
||||
export { dataService };
|
||||
import * as dataService from './data-service';
|
||||
export { ZapClient, getZapClient, connectZap } from './zap';
|
||||
export type { ZapConfig, ChatStreamChunk } from './zap';
|
||||
export * from './utils';
|
||||
export * from './actions';
|
||||
export { default as createPayload } from './createPayload';
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* HTTP request layer for Hanzo Cloud Gateway.
|
||||
*
|
||||
* Handles:
|
||||
* - Response unwrapping: gateway returns { status: "ok", data: X } → X
|
||||
* - Session-based auth (cookies) with fallback to Bearer token
|
||||
* - Auto-retry on session expiry via /api/get-account
|
||||
* - pk- key support for unauthenticated requests
|
||||
*/
|
||||
import { AxiosRequestConfig } from 'axios';
|
||||
import type * as t from './types';
|
||||
declare function _get<T>(url: string, options?: AxiosRequestConfig): Promise<T>;
|
||||
@@ -9,6 +18,10 @@ declare function _put(url: string, data?: any): Promise<any>;
|
||||
declare function _delete<T>(url: string): Promise<T>;
|
||||
declare function _deleteWithOptions<T>(url: string, options?: AxiosRequestConfig): Promise<T>;
|
||||
declare function _patch(url: string, data?: any): Promise<any>;
|
||||
/** Set a publishable key (pk-) for unauthenticated API access */
|
||||
export declare function setPublishableKey(key: string): void;
|
||||
/** Make a request with pk- key (no session needed) */
|
||||
export declare function getWithPk<T>(url: string): Promise<T>;
|
||||
declare const _default: {
|
||||
get: typeof _get;
|
||||
getResponse: typeof _getResponse;
|
||||
@@ -20,6 +33,9 @@ declare const _default: {
|
||||
deleteWithOptions: typeof _deleteWithOptions;
|
||||
patch: typeof _patch;
|
||||
refreshToken: (retry?: boolean) => Promise<t.TRefreshTokenResponse | undefined>;
|
||||
refreshSession: () => Promise<any>;
|
||||
dispatchTokenUpdatedEvent: (token: string) => void;
|
||||
setPublishableKey: typeof setPublishableKey;
|
||||
getWithPk: typeof getWithPk;
|
||||
};
|
||||
export default _default;
|
||||
|
||||