ikanban-web 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -30,8 +30,9 @@ const PORT = portFlag !== -1 ? parseInt(args[portFlag + 1], 10) : 3000
30
30
  // OpenCode backend: honour OPENCODE_URL or default to localhost:4096
31
31
  const OPENCODE_URL = process.env.OPENCODE_URL || "http://localhost:4096"
32
32
 
33
- function proxyRequest(req, res) {
33
+ function proxyRequest(req, res, overridePath) {
34
34
  const target = new URL(req.url, OPENCODE_URL)
35
+ if (overridePath !== undefined) target.pathname = overridePath
35
36
  const mod = target.protocol === "https:" ? https : http
36
37
  const options = {
37
38
  hostname: target.hostname,
@@ -51,9 +52,18 @@ function proxyRequest(req, res) {
51
52
  req.pipe(proxy)
52
53
  }
53
54
 
55
+ const BASE = "/ikanban"
56
+
54
57
  const server = http.createServer((req, res) => {
55
58
  const url = new URL(req.url, `http://localhost:${PORT}`)
56
59
 
60
+ // Redirect bare /ikanban to /ikanban/
61
+ if (url.pathname === BASE) {
62
+ res.writeHead(301, { Location: BASE + "/" })
63
+ res.end()
64
+ return
65
+ }
66
+
57
67
  // Proxy OpenCode API paths to backend.
58
68
  // These are the top-level path segments used by @opencode-ai/sdk.
59
69
  const API_PREFIXES = [
@@ -82,15 +92,37 @@ const server = http.createServer((req, res) => {
82
92
  "/tui",
83
93
  "/vcs",
84
94
  ]
95
+ // Support both /session/... (SDK default, same-origin) and
96
+ // /ikanban/session/... (prefixed, e.g. from a reverse proxy).
97
+ // Determine the effective API pathname by stripping the base prefix if present.
98
+ let apiPathname = url.pathname
99
+ if (apiPathname.startsWith(BASE + "/")) {
100
+ const stripped = apiPathname.slice(BASE.length)
101
+ if (API_PREFIXES.some((p) => stripped === p || stripped.startsWith(p + "/"))) {
102
+ apiPathname = stripped
103
+ }
104
+ }
85
105
  const isApi = API_PREFIXES.some(
86
- (p) => url.pathname === p || url.pathname.startsWith(p + "/"),
106
+ (p) => apiPathname === p || apiPathname.startsWith(p + "/"),
87
107
  )
88
108
  if (isApi) {
89
- return proxyRequest(req, res)
109
+ // Pass the stripped path so the backend never sees the /ikanban prefix
110
+ return proxyRequest(req, res, apiPathname !== url.pathname ? apiPathname : undefined)
111
+ }
112
+
113
+ // Strip /ikanban prefix before resolving static files
114
+ let pathname = url.pathname
115
+ if (pathname.startsWith(BASE + "/")) {
116
+ pathname = pathname.slice(BASE.length) || "/"
117
+ } else if (pathname !== BASE) {
118
+ // Anything outside /ikanban/ that isn't an API call gets a 404
119
+ res.writeHead(404)
120
+ res.end("Not found")
121
+ return
90
122
  }
91
123
 
92
124
  // Serve static files from dist/
93
- let filePath = path.join(DIST, url.pathname)
125
+ let filePath = path.join(DIST, pathname)
94
126
  if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
95
127
  filePath = path.join(DIST, "index.html")
96
128
  }
@@ -110,7 +142,7 @@ const server = http.createServer((req, res) => {
110
142
  })
111
143
 
112
144
  server.listen(PORT, () => {
113
- console.log(`iKanban running at http://localhost:${PORT}`)
145
+ console.log(`iKanban running at http://localhost:${PORT}${BASE}/`)
114
146
  console.log(`OpenCode backend: ${OPENCODE_URL}`)
115
147
  console.log("Press Ctrl+C to stop")
116
148
  })