Skip to content

feat(ispx): support setting username before running (xbuilder_set_username)#3365

Merged
nighca merged 2 commits into
devfrom
fennoai/issue-3364-1784693647
Jul 24, 2026
Merged

feat(ispx): support setting username before running (xbuilder_set_username)#3365
nighca merged 2 commits into
devfrom
fennoai/issue-3364-1784693647

Conversation

@fennoai

@fennoai fennoai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

背景

在 Scratch 转 SPX(sb2xbp)项目中,部分项目依赖 Scratch 的 username 能力。为支持这类项目在 builder 上运行,需要在每次运行前把当前登录用户名注入到 spx 运行时。

Closes #3364
关联:goplus/spx#1689、goplus/sb2xbp#581

改动

ispx 侧 — 新增 tools/ispx/username.go

前端侧spx-gui/.../ProjectRunner.vue

  • RunnerIframeWindow 接口中声明 xbuilder_set_username
  • 运行前(startGame 之前、引擎已初始化后)调用 xbuilder_set_username,用户名取自 getUnresolvedSignedInUsername()(未登录时传空字符串)。

验证

  • GOOS=js GOARCH=wasm go build(ispx)✅ 编译通过
  • gofmt ✅ 通过;go vetusername.go 无新增告警(仅有一处与本改动无关的既有生成代码告警)
  • 前端 type-check / lint ⚠️ 未在本环境执行:沙箱内 Node v20 与 pnpm@11.9.0(要求 Node ≥22.13)不兼容,无法安装依赖。改动为直接类型声明 + 已导出函数调用,建议在 CI 中复核。

⚠️ 依赖顺序

goplus/spx#1689 目前仍为 OPEN 未合并spx.User 只存在于其 PR 分支。本 PR 暂时将 spx 依赖钉在该 PR 的 commit 上。待 goplus/spx#1689 合并并发布正式版本后,需要把 tools/ispx/go.mod 中的 spx 版本重新对齐到发布版本再合并本 PR。

Co-authored-by: go-wyvern 15845637+go-wyvern@users.noreply.github.com

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary

Small, well-scoped change that mirrors the existing tools/ispx/ai.go pattern cleanly: a WASM-exported xbuilder_set_username that sets spx.User, declared in the RunnerIframeWindow interface, and called before startGame(). I verified against the pinned spx commit (0a1981727e33) that spx.User and Game.Username() exist there, so the code and its doc comment are accurate.

Main points for consideration before merge:

  • Privacy / trust boundary (most important): the injected username is readable by any project the viewer runs, including projects authored by others. See inline note on tools/ispx/username.go.
  • Merge ordering / supply chain: the spx dependency is pinned to an unmerged pre-release commit. See inline note on tools/ispx/go.mod (already acknowledged in the PR description).
  • Semantic contract: getUnresolvedSignedInUsername() is documented as a non-authoritative local hint. See inline note on the call site.

No performance concerns. No blocking review — findings are for the author's judgement.

Comment thread tools/ispx/username.go Outdated
// `Game.Username`. See https://github.com/goplus/builder/issues/3364.
func setUsername(this js.Value, args []js.Value) any {
if len(args) > 0 {
spx.User = args[0].String()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Privacy / trust boundary — worth considering. spx.User is later exposed to the running project via Username() / Game.Username(). Since a viewer can run projects authored by other users (including Scratch-converted content), any such project can now read the viewer's logged-in username at runtime and exfiltrate it (e.g. through network calls or the AI-interaction endpoints the game can reach). This is a PII leak across a trust boundary: the running project is untrusted relative to the viewer's identity.

Consider scoping the injection — e.g. only inject when the viewer owns the project (running their own project in the editor), or otherwise gate it — rather than injecting unconditionally on every run. The ?? '' signed-out fallback is handled correctly, so this only concerns signed-in viewers running third-party projects.

Comment thread tools/ispx/go.mod Outdated
github.com/goplus/ixgo v1.1.0
github.com/goplus/mod v0.20.2
github.com/goplus/spx/v2 v2.0.4
github.com/goplus/spx/v2 v2.0.5-0.20260722040346-0a1981727e33

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pins github.com/goplus/spx/v2 to a pseudo-version (v2.0.5-0.2026...-0a1981727e33) from the still-open goplus/spx#1689. Until that PR merges and a stable tag/dev version is published, this ref is force-pushable and could change or disappear — a reproducibility/supply-chain risk, and this whole feature depends on spx.User which only exists on that branch.

The PR description already flags this as a merge blocker; re-pinning to the merged commit / released version before merging this PR is the right call. Noting it here so it's tracked at review level.

// Inject the current logged-in username into the spx runtime before running.
// Some projects (e.g. Scratch-converted ones) rely on Scratch's `username` capability.
// See https://github.com/goplus/builder/issues/3364.
iframeWindow.xbuilder_set_username(getUnresolvedSignedInUsername() ?? '')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getUnresolvedSignedInUsername() is explicitly documented (in stores/user/signed-in.ts) as an unresolved local hint that "may lag behind the canonical signed-in user" and should not be used for behavior-sensitive logic. Feeding it into the runtime — where a Scratch-converted project may branch on Game.Username() — is a mildly behavior-sensitive use that stretches that contract.

This is likely acceptable for a best-effort display hint (a stale/empty value degrades gracefully), but a brief inline comment noting the value is intentionally best-effort (may be stale/empty, not authoritative identity) would prevent future readers from mistaking it for canonical identity.

Comment thread tools/ispx/username.go Outdated
// `Game.Username`. See https://github.com/goplus/builder/issues/3364.
func setUsername(this js.Value, args []js.Value) any {
if len(args) > 0 {
spx.User = args[0].String()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot goplus/spx#1690
api 改为了,spx.SetUsername(xxx)

@fennoai fennoai Bot Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已按新 API 更新 ✅

已按 goplus/spx#1690 把用户名注入方式从 spx.User(包级变量)改为并发安全的 spx.SetUsername(...),并已推送到本 PR 分支(commit 444c7e39)。

改动

  • tools/ispx/username.go
    • import 由 spx "github.com/goplus/spx/v2" 改为 "github.com/goplus/spx/v2/pkg/spx"(新 API 位于该子包)。
    • spx.User = args[0].String()spx.SetUsername(args[0].String());空串表示匿名用户。
  • tools/ispx/go.mod / go.sum

注:goplus/spx#1690 已合并 到 spx dev,因此原 PR 描述中「等待依赖 PR 合并」的顾虑已解除;当前钉的是合并后的伪版本。待 spx 发布正式 tag 后可再对齐到发布版本。

验证

  • GOOS=js GOARCH=wasm go build ./...tools/ispx)✅ 通过
  • gofmt -l username.go ✅ 无输出
  • GOOS=js GOARCH=wasm go vet ./... ✅ 无新增告警(仅 internal/pkg/.../ai/export.go 一处既有生成代码告警,与本改动无关)
  • go mod tidy ✅ 已清理 go.sum 中的旧 spx 条目

未执行

  • 前端 type-check / lint:本次未改动前端(ProjectRunner.vue 仍调用 JS 侧的 xbuilder_set_username,接口不变),沿用原 PR 说明,建议 CI 复核。

import type { SpxProject } from '@/models/spx/project'
import { UIImg, UIDetailedLoading } from '@/components/ui'
import { ensureAccessToken } from '@/stores/user'
import { ensureAccessToken, getUnresolvedSignedInUsername } from '@/stores/user'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getUnresolvedSignedInUsername 不太推荐使用,这里建议用 useSignedInStateQuery 吧,也更方便处理未登录的情况:

const signedInStateQuery = useSignedInStateQuery()

function runInternal() {
  // ...
  const signedInState = await untilNotNull(signedInStateQuery.data)
  if (signedInState.isSignedIn) {
    // ...
  } else {
    // ...
  }
  // ...
}

P.S. 未登录的话需要去 set 一个空的 username 吗?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot 帮忙看下这个 comment

@fennoai fennoai Bot Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已按 @nighca 的建议调整 ✅

已采纳 review 意见,改用 useSignedInStateQuery 获取权威的登录状态,替代不推荐的 getUnresolvedSignedInUsername(后者在 stores/user/signed-in.ts 中明确标注为「本地未解析的用户名提示,可能滞后于后端权威数据,不应用于行为敏感逻辑」)。已推送到本 PR 分支(commit 879708b6)。

改动spx-gui/.../ProjectRunner.vue

  • import 由 getUnresolvedSignedInUsername 改为 useSignedInStateQuery
  • 在 setup 作用域创建 const signedInStateQuery = useSignedInStateQuery()(hook 需在 setup 顶层调用)。
  • 运行前等待登录状态解析后再注入用户名,并处理未登录分支:
const signedInState = await untilNotNull(signedInStateQuery.data, ctrl.signal)
iframeWindow.xbuilder_set_username(signedInState.isSignedIn ? signedInState.user.username : '')

说明:这里沿用你示例中的 untilNotNull(signedInStateQuery.data)SignedInState 加载完成后即为非空对象)。传入 ctrl.signal 以便运行被取消时能及时中止等待。

关于 P.S.「未登录是否需要 set 空 username?」

建议显式 set 空字符串,本次即这样实现,原因:

  1. spx 侧 SetUsername 语义上以空串表示匿名用户(见 feat: support configurable runtime username spx#1690),空串是合法且明确的「匿名」输入。
  2. xbuilder_set_username 在每次运行前都会调用;若未登录时不 set,登出后再次运行(rerun)会残留上一次登录用户的用户名,导致状态不确定。显式置空可保证每次运行的用户名都是确定的。

验证

  • 本次仅改动前端,且为使用既有、类型完备的 API(useSignedInStateQuery 返回 QueryRet<SignedInState>SignedInUserusername: string)做的等价替换,逻辑直观。
  • ⚠️ type-check / lint 未在本环境执行:沙箱 Node 为 v20.20.2,而项目要求 Node ^24.11.1pnpm install 因缺少 node:sqlite 直接失败)。建议在 CI 中复核。

Comment thread tools/ispx/go.mod Outdated
github.com/goplus/ixgo v1.1.0
github.com/goplus/mod v0.20.2
github.com/goplus/spx/v2 v2.0.4
github.com/goplus/spx/v2 v2.0.5-0.20260722062616-dbad134a429c

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

其他地方的 spx 版本应该也要一起升吧?参考 builder/.github/agents/spx-upgrader.md

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot dev 分支已经更新 spx 到 3.0 ,你可以merge 一下

@fennoai fennoai Bot Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已同步 ✅

dev 的 spx 3.0 更新已经合并进本 PR 分支了 —— 这在几分钟前的 rebase 中已经完成,当前无需再做额外操作。

当前状态

  • 分支 fennoai/issue-3364-1784693647 的 HEAD (3287ead7) 直接位于 dev 的最新提交 c23d9b24 chore(deps): bump spx to 3.0.0 (#3369) 之上,dev 没有任何提交遗漏。
  • tools/ispx/go.mod 使用 github.com/goplus/spx/v3 v3.0.0;go.mod / go.sumdev 完全一致(无 diff),本 PR 不再携带任何 spx 版本改动。
  • tools/ispx/username.go 已适配 v3:import "github.com/goplus/spx/v3/pkg/spx" + spx.SetUsername(...)
  • PR 当前 mergeable: true(blocked 仅表示待 CI / review,不是冲突)。

相对 dev 的净改动(2 个文件):

  • tools/ispx/username.go(新增)
  • spx-gui/src/components/project/runner/ProjectRunner.vue

所以这里没有需要额外「merge」的内容 —— 分支已经基于最新 dev(含 spx 3.0)。

说明:我不会直接把本 PR 合并进 dev。合并 PR 属于受保护操作,需要相应权限且 CI 全绿;目前 mergeable_state 仍为 blocked(等待必需的检查/评审)。如需正式合入,请在检查通过后由具备权限的维护者点击合并。

View job run

fennoai Bot added a commit that referenced this pull request Jul 23, 2026
Address review feedback (#3365): replace the discouraged
`getUnresolvedSignedInUsername()` (a best-effort local hint) with the
canonical `useSignedInStateQuery()` when injecting the username into the
spx runtime. Await the resolved signed-in state before running and pass
the canonical username; for signed-out users pass an empty string, which
spx treats as an anonymous user.

Co-authored-by: fennoai[bot] <231223108+fennoai[bot]@users.noreply.github.com>
Co-authored-by: go-wyvern <15845637+go-wyvern@users.noreply.github.com>
@nighca

nighca commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

@xgopilot Rebase this PR to the latest dev branch and resolve conflicts. The SPX version update in this PR should be removed, as v3.0.0 is newer than v2.0.5-0.20260722062616-dbad134a429c.

@fennoai

fennoai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

An internal error occurred. Please try again later.

View job run

@nighca

nighca commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

@fennoai retry

@fennoai

fennoai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Done ✅

Rebased this PR onto the latest dev and removed the SPX version bump, per @nighca's request.

What changed

  • Rebased fennoai/issue-3364-1784693647 onto latest dev (now based on c23d9b24 chore(deps): bump spx to 3.0.0 (#3369)).
  • Removed the SPX version updatetools/ispx/go.mod and tools/ispx/go.sum now have zero diff against dev, keeping dev's newer github.com/goplus/spx/v3 v3.0.0 (along with ixgo v1.1.1 / mod v0.21.1) instead of the previous spx/v2 pin.
  • Adapted username.go to spx v3 — since dev moved to the spx/v3 import path, updated the import to github.com/goplus/spx/v3/pkg/spx and kept using the exported spx.SetUsername(...) (confirmed present at spx/v3/pkg/spx/environment.go).
  • The intermediate refactor(ispx): use spx.SetUsername instead of spx.User commit became empty after the resolution (its change was already folded into the v3-based first commit) and was dropped automatically by the rebase.

Resulting diff vs dev (2 files, +35/-1):

  • tools/ispx/username.go (new) — xbuilder_set_usernamespx.SetUsername
  • spx-gui/src/components/project/runner/ProjectRunner.vue — declares xbuilder_set_username and calls it before startGame using useSignedInStateQuery

Verified

  • ✅ WASM build: GOOS=js GOARCH=wasm go build ./... (in tools/ispx) passes against spx v3
  • gofmt -l username.go clean
  • ✅ No conflict markers; go.mod/go.sum identical to dev
  • ✅ PR is now mergeable (branch fast-forwards onto dev; blocked state is just pending required checks/review)
  • ⚠️ Frontend type-check / lint not run here (sandbox Node/pnpm version mismatch, as noted in the PR description) — the change is a type declaration plus a call to an already-exported helper; please rely on CI.

The branch was force-pushed (--force-with-lease) since a rebase rewrites history; the remote is now at 3287ead7.

View job run

fennoai Bot and others added 2 commits July 24, 2026 06:24
…rname)

Add `tools/ispx/username.go` exposing a JS-callable `xbuilder_set_username`
that injects the current logged-in username into the spx runtime via
`spx.User` (goplus/spx#1689). Call it in `ProjectRunner.vue` before running
so Scratch-converted projects depending on the `username` capability work.

Bump spx to the PR head commit that exposes `spx.User`; realign after
goplus/spx#1689 is released.

Closes #3364

Co-authored-by: fennoai[bot] <231223108+fennoai[bot]@users.noreply.github.com>
Co-authored-by: go-wyvern <15845637+go-wyvern@users.noreply.github.com>
Address review feedback (#3365): replace the discouraged
`getUnresolvedSignedInUsername()` (a best-effort local hint) with the
canonical `useSignedInStateQuery()` when injecting the username into the
spx runtime. Await the resolved signed-in state before running and pass
the canonical username; for signed-out users pass an empty string, which
spx treats as an anonymous user.

Co-authored-by: fennoai[bot] <231223108+fennoai[bot]@users.noreply.github.com>
Co-authored-by: go-wyvern <15845637+go-wyvern@users.noreply.github.com>
@nighca
nighca merged commit eaae2ed into dev Jul 24, 2026
9 checks passed
@fennoai
fennoai Bot deleted the fennoai/issue-3364-1784693647 branch July 24, 2026 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ispx/builder 支持在运行前设置 username(xbuilder_set_username)

2 participants