@waterplus-ai/waterbuddy 0.1.10 → 0.1.17

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.
@@ -143,6 +143,14 @@ window.__ModuleLoader__.load({
143
143
  })
144
144
  }
145
145
 
146
+ function SkipWelcomeNotice({ complete }) {
147
+ const { useEffect } = require('react')
148
+ useEffect(() => {
149
+ complete()
150
+ }, [complete])
151
+ return null
152
+ }
153
+
146
154
  const inject = ['slots']
147
155
  function apply(ctx) {
148
156
  ctx.effect(() => {
@@ -181,6 +189,7 @@ window.__ModuleLoader__.load({
181
189
  yield ctx.slots.register({ name: 'sidebar.brand.name', priority: -10 }, WaterBuddyName)
182
190
  }))
183
191
  ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({ name: 'sidebar.footer.action', id: 'waterbuddy-user', order: 90, label: '登录 WaterBuddy' }, UserAction))
192
+ ctx.slots.inject('settings.onboarding', () => ctx.slots.register({ name: 'settings.onboarding', id: 'welcome-notice', priority: -1000, order: -100 }, SkipWelcomeNotice))
184
193
  }
185
194
 
186
195
  exports.inject = inject
package/lib/host/index.js CHANGED
@@ -17,8 +17,8 @@ function readPersistedAuth() {
17
17
  try {
18
18
  const value = JSON.parse(fs.readFileSync(authFile, 'utf8'))
19
19
  if (value?.token && value?.user) {
20
- persistedAuth = value
21
- currentUser = value.user
20
+ currentUser = normalizeUser(value.user)
21
+ persistedAuth = { ...value, user: currentUser }
22
22
  }
23
23
  } catch {}
24
24
  }
@@ -38,12 +38,24 @@ function clearPersistedAuth() {
38
38
  try { fs.rmSync(authFile, { force: true }) } catch {}
39
39
  }
40
40
 
41
+ function isSupportedAvatarUrl(url) {
42
+ return (url.protocol === 'http:' || url.protocol === 'https:') && !url.username && !url.password
43
+ }
44
+
41
45
  function normalizeAvatar(value) {
42
46
  if (typeof value !== 'string' || !value) return undefined
43
47
  if (value.startsWith('data:')) return value
44
48
  try {
45
- const url = new URL(value, AI_URL)
46
- if (url.protocol !== 'https:' || url.host !== new URL(AI_URL).host) return undefined
49
+ let source = value
50
+ for (let depth = 0; depth < 4; depth += 1) {
51
+ const candidate = new URL(source, 'http://127.0.0.1')
52
+ if (candidate.pathname !== '/api/waterbuddy/avatar') break
53
+ const nested = candidate.searchParams.get('url')
54
+ if (!nested) return undefined
55
+ source = nested
56
+ }
57
+ const url = new URL(source, AI_URL)
58
+ if (!isSupportedAvatarUrl(url)) return undefined
47
59
  return `/api/waterbuddy/avatar?url=${encodeURIComponent(url.href)}`
48
60
  } catch { return undefined }
49
61
  }
@@ -143,7 +155,7 @@ async function proxyAvatar(req, res) {
143
155
  const value = new URL(req.url, 'http://127.0.0.1').searchParams.get('url')
144
156
  let target
145
157
  try { target = new URL(value) } catch { return json(res, 400, { error: 'invalid-avatar-url' }) }
146
- if (target.protocol !== 'https:' || target.host !== new URL(AI_URL).host) return json(res, 403, { error: 'avatar-host-not-allowed' })
158
+ if (!isSupportedAvatarUrl(target)) return json(res, 400, { error: 'avatar-url-not-supported' })
147
159
  const response = await fetch(target)
148
160
  if (!response.ok || !response.body) return json(res, response.status || 502, { error: 'avatar-fetch-failed' })
149
161
  res.writeHead(response.status, { 'content-type': response.headers.get('content-type') || 'image/jpeg', 'cache-control': 'private, max-age=3600' })
@@ -152,6 +164,7 @@ async function proxyAvatar(req, res) {
152
164
  }
153
165
 
154
166
  export const inject = ['webServer', 'systemPrompt']
167
+ export { normalizeAvatar }
155
168
 
156
169
  export function apply(ctx) {
157
170
  readPersistedAuth()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waterplus-ai/waterbuddy",
3
- "version": "0.1.10",
3
+ "version": "0.1.17",
4
4
  "description": "WaterBuddy branding and Web profile bundle for DeepSeek Harness",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",