From f36b90ebdb0c6f34fdc3744275a2ee1ac4dea1e4 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Tue, 26 May 2026 22:32:16 +0800 Subject: [PATCH 01/31] feat: switch mini program recharge to virtual payment --- .hermes/shared-memory/decision-log.md | 8 + .hermes/shared-memory/document-map.md | 1 + docs/README.md | 2 + ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 + ...【技术方案】微信虚拟支付接入-2026-05-26.md | 56 +++++ miniprogram/pages/wechat-pay/index.js | 91 +------- miniprogram/pages/wechat-pay/index.shared.js | 184 +++++++++++++++ miniprogram/pages/wechat-pay/index.test.js | 159 +++++++++++++ packages/shared/src/contracts/runtime.ts | 12 +- server-rs/crates/api-server/Cargo.toml | 2 +- server-rs/crates/api-server/src/config.rs | 56 +++++ .../crates/api-server/src/runtime_profile.rs | 220 +++++++++++++++++- .../crates/api-server/src/wechat_auth.rs | 1 + server-rs/crates/module-auth/src/domain.rs | 2 + server-rs/crates/module-auth/src/lib.rs | 11 + server-rs/crates/module-runtime/src/domain.rs | 1 + server-rs/crates/platform-auth/src/lib.rs | 5 + .../crates/shared-contracts/src/runtime.rs | 79 ++++++- .../RpgEntryHomeView.recharge.test.tsx | 140 ++++++++--- src/components/rpg-entry/RpgEntryHomeView.tsx | 18 +- src/services/payment/paymentPlatform.test.ts | 31 ++- src/services/payment/paymentPlatform.ts | 15 +- 22 files changed, 959 insertions(+), 137 deletions(-) create mode 100644 docs/【技术方案】微信虚拟支付接入-2026-05-26.md create mode 100644 miniprogram/pages/wechat-pay/index.shared.js create mode 100644 miniprogram/pages/wechat-pay/index.test.js diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 840846b4..68968483 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -16,6 +16,14 @@ --- +## 2026-05-26 微信小程序充值全面接入虚拟支付 + +- 背景:泥点和会员都属于小程序内由 Genarrative 控制的虚拟资产/权益,继续走普通小程序支付不符合微信虚拟支付接入口径。 +- 决策:小程序 WebView 内充值商品全部使用渠道 `wechat_mp_virtual` 并由 `miniprogram/pages/wechat-pay` 调用 `wx.requestVirtualPayment`;泥点使用 `short_series_coin`,会员使用 `short_series_goods`,会员 `signData` 必须带 `productId` 与 `goodsPrice`。后端保存微信小程序 `session_key`,仅用于生成 `signature`,不下发客户端。客户端 success 只作为支付页返回信号,最终到账仍由后端微信通知或查询确认后写订单。 +- 影响范围:`src/services/payment/paymentPlatform.ts`、`src/components/rpg-entry/RpgEntryHomeView.tsx`、`miniprogram/pages/wechat-pay/`、`server-rs/crates/api-server/src/runtime_profile.rs`、`server-rs/crates/shared-contracts/src/runtime.rs`、`packages/shared/src/contracts/runtime.ts`、微信登录态存储。 +- 验证方式:泥点和会员商品在小程序运行态都请求 `wechat_mp_virtual`;小程序页能按 payload 调用 `wx.requestVirtualPayment` / `wx.requestPayment`;`cargo check -p api-server --manifest-path server-rs/Cargo.toml` 与支付相关前端测试通过。 +- 关联文档:`docs/【技术方案】微信虚拟支付接入-2026-05-26.md`。 + ## 2026-05-25 抓大鹅发现页官方 demo 使用静态资源与本地运行态 - 背景:本轮抓大鹅资源管线已经生成完整 `level-scene`、背景、UI spritesheet、物品 spritesheet 和切片资源,需要放入发现页作为可试玩验证入口,但不应把一次性本地资源包装成后端正式作品。 diff --git a/.hermes/shared-memory/document-map.md b/.hermes/shared-memory/document-map.md index 512c5949..8cd29c75 100644 --- a/.hermes/shared-memory/document-map.md +++ b/.hermes/shared-memory/document-map.md @@ -12,6 +12,7 @@ | 后端、DDD、API、SpacetimeDB schema 和表目录 | `docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md` | | 创作入口、草稿架和玩法链路 | `docs/【玩法创作】平台入口与玩法链路-2026-05-15.md` | | 本地启动、验证、部署、埋点和运营查询 | `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md` | +| 微信小程序虚拟支付 | `docs/【技术方案】微信虚拟支付接入-2026-05-26.md` | | UI 像素资产与 9-slice 规范 | `UI_CODING_STANDARD.md` | ## 阅读顺序 diff --git a/docs/README.md b/docs/README.md index 39af032a..47f6ed8b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,6 +19,8 @@ 从文字需求生成高一致性美术素材流程抽象出的发明专利交底稿见 [【专利交底】一种极低成本快速生成高质量2D小游戏高一致性美术素材的解决方案-2026-05-25.md](./%E3%80%90%E4%B8%93%E5%88%A9%E4%BA%A4%E5%BA%95%E3%80%91%E4%B8%80%E7%A7%8D%E6%9E%81%E4%BD%8E%E6%88%90%E6%9C%AC%E5%BF%AB%E9%80%9F%E7%94%9F%E6%88%90%E9%AB%98%E8%B4%A8%E9%87%8F2D%E5%B0%8F%E6%B8%B8%E6%88%8F%E9%AB%98%E4%B8%80%E8%87%B4%E6%80%A7%E7%BE%8E%E6%9C%AF%E7%B4%A0%E6%9D%90%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-2026-05-25.md)。 +微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。 + 生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md);private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。 SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 62a24ea8..baa5cdd3 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -47,6 +47,8 @@ npm run dev:api-server 开发态 `npm run dev` 与 `npm run dev:api-server` 会默认注入 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true`,因此密码登录在本地开发环境可直接注册未知手机号账号;生产环境仍按 `api-server` 配置默认关闭该开关。 +微信小程序虚拟支付使用 `WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID`、`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY`、`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY` 和 `WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV` 配置。泥点充值在小程序 WebView 内走 `wechat_mp_virtual` / `wx.requestVirtualPayment`,会员仍走普通 `wechat_mp` / `wx.requestPayment`。旧登录快照若缺 `session_key`,需要用户在小程序内重新登录后再支付;客户端成功回调不是最终到账,仍以后端通知或查询确认订单为准。详细口径见 `docs/【技术方案】微信虚拟支付接入-2026-05-26.md`。 + 如果本地 `GET /api/creation-entry/config` 返回 `No such procedure`,或 `api-server` 日志出现 `no such table: puzzle_gallery_card_view` / `no such table: wooden_fish_gallery_card_view` 这类公开 view 缺失,通常是 `.env.local` 指向的 SpacetimeDB 库还没有发布当前 `spacetime-module`,或当前 CLI 身份无权发布该库。debug 构建的 `api-server` 会临时使用后端默认入口配置兜底,避免创作作品架整块消失;正式修复仍应切换到拥有目标库权限的 SpacetimeDB 身份后重新运行 `npm run dev` 完成发布,或用 gitignored 的 `spacetime.local.json` 指向可发布的本地库。 本地排查 schema 漂移时,先用当前 dev server 显式查询目标库,例如: diff --git a/docs/【技术方案】微信虚拟支付接入-2026-05-26.md b/docs/【技术方案】微信虚拟支付接入-2026-05-26.md new file mode 100644 index 00000000..afe1ff24 --- /dev/null +++ b/docs/【技术方案】微信虚拟支付接入-2026-05-26.md @@ -0,0 +1,56 @@ +# 微信虚拟支付接入 + +更新时间:`2026-05-26` + +## 接入口径 + +- 泥点充值在微信小程序 WebView 内走 `wechat_mp_virtual`,由小程序页调用 `wx.requestVirtualPayment` 的 `short_series_coin` 模式。 +- 会员商品在微信小程序 WebView 内同样走 `wechat_mp_virtual`,由小程序页调用 `wx.requestVirtualPayment` 的 `short_series_goods` 模式,并在 `signData` 内带 `productId` 与 `goodsPrice`。 +- H5 与桌面微信环境仍分别走 `wechat_h5` / `wechat_native`,不进入虚拟支付链路。 +- `session_key` 只保存在后端认证仓储内,用于计算虚拟支付用户态签名,不下发给前端。 +- 客户端支付成功回调只代表已拉起支付并返回成功;最终到账仍以后端微信通知或查询确认后写入订单为准。 + +## 关键文件 + +- 前端渠道选择:`src/services/payment/paymentPlatform.ts` +- 充值入口:`src/components/rpg-entry/RpgEntryHomeView.tsx` +- 小程序支付承接页:`miniprogram/pages/wechat-pay/index.shared.js` +- API 契约:`packages/shared/src/contracts/runtime.ts`、`server-rs/crates/shared-contracts/src/runtime.rs` +- 后端下单与签名:`server-rs/crates/api-server/src/runtime_profile.rs` +- 微信登录态保存:`server-rs/crates/platform-auth/src/lib.rs`、`server-rs/crates/module-auth/src/lib.rs` + +## 后端配置 + +生产接入虚拟支付至少需要: + +```bash +WECHAT_PAY_ENABLED=true +WECHAT_PAY_PROVIDER=real +WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID=<微信虚拟支付 offerId> +WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY=<现网 AppKey> +WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY=<沙箱 AppKey,可选> +WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV=0 +``` + +`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV=0` 表示现网,`1` 表示沙箱。后端会按 env 选择 AppKey,并生成: + +- `signData`:传给 `wx.requestVirtualPayment` 的订单数据。 +- `paySig`:`HMAC-SHA256(appKey, "requestVirtualPayment&" + signData)` 的小写 hex。 +- `signature`:`HMAC-SHA256(session_key, signData)` 的小写 hex。 +- 会员直购 `signData` 额外包含 `productId` 和 `goodsPrice`;`goodsPrice` 使用后端商品配置价,和微信后台道具价格校验保持一致。 + +## 验收命令 + +```bash +npm exec vitest run miniprogram/pages/wechat-pay/index.test.js src/services/payment/paymentPlatform.test.ts src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +cargo check -p api-server --manifest-path server-rs/Cargo.toml +cargo test -p shared-contracts --manifest-path server-rs/Cargo.toml create_profile_recharge_order_response_serializes_virtual_wechat_payloads +npm run typecheck +npm run check:encoding +``` + +## 注意事项 + +- 旧微信登录快照可能没有 `session_key`,用户需要在小程序内重新登录后再发起虚拟支付。 +- 小程序充值商品全部映射到虚拟支付;泥点使用 `short_series_coin`,会员使用 `short_series_goods`。 +- 小程序页必须保留普通支付与虚拟支付双分支,按 pay params 字段判断调用 `wx.requestPayment` 或 `wx.requestVirtualPayment`。 diff --git a/miniprogram/pages/wechat-pay/index.js b/miniprogram/pages/wechat-pay/index.js index 332849ca..ad188c92 100644 --- a/miniprogram/pages/wechat-pay/index.js +++ b/miniprogram/pages/wechat-pay/index.js @@ -1,90 +1,3 @@ -function parsePayParams(rawValue) { - try { - const params = JSON.parse(decodeURIComponent(String(rawValue || ''))); - if (!params || typeof params !== 'object') { - return null; - } - return params; - } catch (error) { - console.error('[wechat-pay] parse params failed', error); - return null; - } -} +const { createWechatPayPage } = require('./index.shared'); -function requestPayment(payParams) { - return new Promise((resolve) => { - wx.requestPayment({ - timeStamp: String(payParams.timeStamp || ''), - nonceStr: String(payParams.nonceStr || ''), - package: String(payParams.package || ''), - signType: payParams.signType || 'RSA', - paySign: String(payParams.paySign || ''), - success() { - resolve('success'); - }, - fail(error) { - const errMsg = error && error.errMsg ? error.errMsg : ''; - resolve(/cancel/i.test(errMsg) ? 'cancel' : 'fail'); - }, - }); - }); -} - -const PAY_RESULT_STORAGE_KEY = 'genarrative:wechat-pay-result'; - -function appendPayResult(url, requestId, status) { - const value = `${requestId}:${status}`; - const hashIndex = String(url || '').indexOf('#'); - const baseUrl = - hashIndex >= 0 ? String(url).slice(0, hashIndex) : String(url || ''); - const rawHash = hashIndex >= 0 ? String(url).slice(hashIndex + 1) : ''; - const nextHash = rawHash - .split('&') - .filter((part) => part && !part.startsWith('wx_pay_result=')) - .concat(`wx_pay_result=${encodeURIComponent(value)}`) - .join('&'); - return `${baseUrl}#${nextHash}`; -} - -function notifyPreviousWebView(requestId, status) { - const result = `${requestId}:${status}`; - wx.setStorageSync(PAY_RESULT_STORAGE_KEY, result); - const pages = getCurrentPages(); - const previousPage = pages.length >= 2 ? pages[pages.length - 2] : null; - if (previousPage && typeof previousPage.setData === 'function') { - previousPage.setData({ - webViewUrl: appendPayResult( - previousPage.data.webViewUrl, - requestId, - status, - ), - }); - } -} - -Page({ - data: { - title: '正在拉起支付', - errorMessage: '', - }, - - async onLoad(query) { - const requestId = String(query.requestId || ''); - const payParams = parsePayParams(query.payParams); - if (!requestId || !payParams) { - this.setData({ - title: '支付失败', - errorMessage: '缺少支付参数。', - }); - return; - } - - const status = await requestPayment(payParams); - notifyPreviousWebView(requestId, status); - wx.navigateBack(); - }, - - handleBack() { - wx.navigateBack(); - }, -}); +Page(createWechatPayPage()); diff --git a/miniprogram/pages/wechat-pay/index.shared.js b/miniprogram/pages/wechat-pay/index.shared.js new file mode 100644 index 00000000..cdf73eb3 --- /dev/null +++ b/miniprogram/pages/wechat-pay/index.shared.js @@ -0,0 +1,184 @@ +/* global wx, getCurrentPages */ + +function parsePayParams(rawValue) { + try { + const params = JSON.parse(decodeURIComponent(String(rawValue || ''))); + if (!params || typeof params !== 'object') { + return null; + } + return params; + } catch (error) { + console.error('[wechat-pay] parse params failed', error); + return null; + } +} + +function isVirtualPaymentParams(payParams) { + return ( + typeof payParams.mode === 'string' && + typeof payParams.signData === 'string' && + typeof payParams.paySig === 'string' && + typeof payParams.signature === 'string' + ); +} + +function safeCompareVersion(left, right) { + const leftParts = String(left || '') + .split('.') + .map((part) => Number(part) || 0); + const rightParts = String(right || '') + .split('.') + .map((part) => Number(part) || 0); + const length = Math.max(leftParts.length, rightParts.length); + for (let index = 0; index < length; index += 1) { + const leftValue = leftParts[index] || 0; + const rightValue = rightParts[index] || 0; + if (leftValue > rightValue) { + return 1; + } + if (leftValue < rightValue) { + return -1; + } + } + return 0; +} + +function canUseVirtualPayment() { + if (typeof wx === 'undefined') { + return false; + } + if (typeof wx.canIUse === 'function' && wx.canIUse('requestVirtualPayment')) { + return true; + } + + const version = + typeof wx.getSystemInfoSync === 'function' + ? wx.getSystemInfoSync()?.SDKVersion || '' + : ''; + return safeCompareVersion(version, '2.19.2') >= 0; +} + +function resolvePayStatus(error) { + const errMsg = error && error.errMsg ? error.errMsg : ''; + const errCode = Number(error && error.errCode); + return errCode === -2 || /cancel/i.test(errMsg) ? 'cancel' : 'fail'; +} + +function requestOrdinaryPayment(payParams) { + return new Promise((resolve) => { + wx.requestPayment({ + timeStamp: String(payParams.timeStamp || ''), + nonceStr: String(payParams.nonceStr || ''), + package: String(payParams.package || ''), + signType: payParams.signType || 'RSA', + paySign: String(payParams.paySign || ''), + success() { + resolve('success'); + }, + fail(error) { + resolve(resolvePayStatus(error)); + }, + }); + }); +} + +function requestVirtualPayment(payParams) { + return new Promise((resolve) => { + if (!canUseVirtualPayment() || typeof wx.requestVirtualPayment !== 'function') { + resolve('fail'); + return; + } + wx.requestVirtualPayment({ + mode: String(payParams.mode || ''), + signData: String(payParams.signData || ''), + paySig: String(payParams.paySig || ''), + signature: String(payParams.signature || ''), + success() { + resolve('success'); + }, + fail(error) { + resolve(resolvePayStatus(error)); + }, + }); + }); +} + +function requestWechatPayment(payParams) { + if (isVirtualPaymentParams(payParams)) { + return requestVirtualPayment(payParams); + } + return requestOrdinaryPayment(payParams); +} + +const PAY_RESULT_STORAGE_KEY = 'genarrative:wechat-pay-result'; + +function appendPayResult(url, requestId, status) { + const value = `${requestId}:${status}`; + const hashIndex = String(url || '').indexOf('#'); + const baseUrl = + hashIndex >= 0 ? String(url).slice(0, hashIndex) : String(url || ''); + const rawHash = hashIndex >= 0 ? String(url).slice(hashIndex + 1) : ''; + const nextHash = rawHash + .split('&') + .filter((part) => part && !part.startsWith('wx_pay_result=')) + .concat(`wx_pay_result=${encodeURIComponent(value)}`) + .join('&'); + return `${baseUrl}#${nextHash}`; +} + +function notifyPreviousWebView(requestId, status) { + const result = `${requestId}:${status}`; + wx.setStorageSync(PAY_RESULT_STORAGE_KEY, result); + const pages = getCurrentPages(); + const previousPage = pages.length >= 2 ? pages[pages.length - 2] : null; + if (previousPage && typeof previousPage.setData === 'function') { + previousPage.setData({ + webViewUrl: appendPayResult( + previousPage.data.webViewUrl, + requestId, + status, + ), + }); + } +} + +function createWechatPayPage(pageContext) { + return { + data: { + title: '正在拉起支付', + errorMessage: '', + }, + + async onLoad(query) { + const requestId = String(query.requestId || ''); + const payParams = parsePayParams(query.payParams); + if (!requestId || !payParams) { + const page = pageContext ?? this; + page.setData({ + title: '支付失败', + errorMessage: '缺少支付参数。', + }); + return; + } + + const status = await requestWechatPayment(payParams); + notifyPreviousWebView(requestId, status); + wx.navigateBack(); + }, + + handleBack() { + wx.navigateBack(); + }, + }; +} + +module.exports = { + canUseVirtualPayment, + PAY_RESULT_STORAGE_KEY, + appendPayResult, + createWechatPayPage, + parsePayParams, + safeCompareVersion, + requestWechatPayment, + requestVirtualPayment, +}; diff --git a/miniprogram/pages/wechat-pay/index.test.js b/miniprogram/pages/wechat-pay/index.test.js new file mode 100644 index 00000000..f4096260 --- /dev/null +++ b/miniprogram/pages/wechat-pay/index.test.js @@ -0,0 +1,159 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +import wechatPayBridge from './index.shared.js'; + +const { + appendPayResult, + createWechatPayPage, + parsePayParams, + requestWechatPayment, +} = wechatPayBridge; + +describe('wechat-pay mini program payment bridge', () => { + beforeEach(() => { + globalThis.wx = { + requestPayment: vi.fn(), + requestVirtualPayment: vi.fn(), + setStorageSync: vi.fn(), + navigateBack: vi.fn(), + }; + globalThis.getCurrentPages = vi.fn(() => []); + }); + + test('routes virtual payloads to wx.requestVirtualPayment', async () => { + globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => { + options.success?.({ errMsg: 'requestVirtualPayment:ok' }); + }); + const payParams = { + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","outTradeNo":"order-virtual-1","attach":"mud_points_60"}', + paySig: 'pay-sig', + signature: 'user-sig', + }; + + const status = await requestWechatPayment(payParams); + + expect(status).toBe('success'); + expect(globalThis.wx.requestVirtualPayment).toHaveBeenCalledWith({ + mode: 'short_series_coin', + signData: payParams.signData, + paySig: 'pay-sig', + signature: 'user-sig', + success: expect.any(Function), + fail: expect.any(Function), + }); + expect(globalThis.wx.requestPayment).not.toHaveBeenCalled(); + }); + + test('routes goods virtual payloads to wx.requestVirtualPayment', async () => { + globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => { + options.success?.({ errMsg: 'requestVirtualPayment:ok' }); + }); + const payParams = { + mode: 'short_series_goods', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","productId":"member_month","goodsPrice":2800,"outTradeNo":"order-goods-1","attach":"member_month"}', + paySig: 'pay-sig', + signature: 'user-sig', + }; + + const status = await requestWechatPayment(payParams); + + expect(status).toBe('success'); + expect(globalThis.wx.requestVirtualPayment).toHaveBeenCalledWith({ + mode: 'short_series_goods', + signData: payParams.signData, + paySig: 'pay-sig', + signature: 'user-sig', + success: expect.any(Function), + fail: expect.any(Function), + }); + expect(globalThis.wx.requestPayment).not.toHaveBeenCalled(); + }); + + test('keeps ordinary requestPayment payloads on wx.requestPayment', async () => { + globalThis.wx.requestPayment.mockImplementationOnce((options) => { + options.success?.(); + }); + + const status = await requestWechatPayment({ + timeStamp: '1777110165', + nonceStr: 'nonce', + package: 'prepay_id=wx-prepay', + signType: 'RSA', + paySign: 'signature', + }); + + expect(status).toBe('success'); + expect(globalThis.wx.requestPayment).toHaveBeenCalledWith({ + timeStamp: '1777110165', + nonceStr: 'nonce', + package: 'prepay_id=wx-prepay', + signType: 'RSA', + paySign: 'signature', + success: expect.any(Function), + fail: expect.any(Function), + }); + expect(globalThis.wx.requestVirtualPayment).not.toHaveBeenCalled(); + }); + + test('maps virtual payment cancel errCode to cancel result', async () => { + globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => { + options.fail?.({ errCode: -2, errMsg: 'requestVirtualPayment:fail cancel' }); + }); + + await expect( + requestWechatPayment({ + mode: 'short_series_coin', + signData: '{}', + paySig: 'pay-sig', + signature: 'user-sig', + }), + ).resolves.toBe('cancel'); + }); + + test('page notifies previous web-view after virtual payment', async () => { + const previousPage = { + data: { webViewUrl: 'https://web.test/#tab=profile' }, + setData: vi.fn(), + }; + globalThis.getCurrentPages = vi.fn(() => [{}, previousPage]); + globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => { + options.success?.({ errMsg: 'requestVirtualPayment:ok' }); + }); + const page = createWechatPayPage({ + setData: vi.fn(), + }); + + await page.onLoad({ + requestId: 'request-1', + payParams: encodeURIComponent( + JSON.stringify({ + mode: 'short_series_coin', + signData: '{}', + paySig: 'pay-sig', + signature: 'user-sig', + }), + ), + }); + + expect(globalThis.wx.setStorageSync).toHaveBeenCalledWith( + 'genarrative:wechat-pay-result', + 'request-1:success', + ); + expect(previousPage.setData).toHaveBeenCalledWith({ + webViewUrl: 'https://web.test/#tab=profile&wx_pay_result=request-1%3Asuccess', + }); + expect(globalThis.wx.navigateBack).toHaveBeenCalled(); + }); + + test('parsePayParams and appendPayResult keep existing behavior', () => { + expect(parsePayParams(encodeURIComponent('{"paySign":"sig"}'))).toEqual({ + paySign: 'sig', + }); + expect(appendPayResult('https://web.test/#old=1', 'req', 'fail')).toBe( + 'https://web.test/#old=1&wx_pay_result=req%3Afail', + ); + }); +}); diff --git a/packages/shared/src/contracts/runtime.ts b/packages/shared/src/contracts/runtime.ts index 784728f0..8158b592 100644 --- a/packages/shared/src/contracts/runtime.ts +++ b/packages/shared/src/contracts/runtime.ts @@ -147,6 +147,13 @@ export type WechatMiniProgramPayParams = { paySign: string; }; +export type WechatMiniProgramVirtualPayParams = { + mode: 'short_series_coin' | 'short_series_goods'; + signData: string; + paySig: string; + signature: string; +}; + export type WechatH5Payment = { h5Url: string; }; @@ -163,7 +170,10 @@ export type CreateProfileRechargeOrderRequest = { export type CreateProfileRechargeOrderResponse = { order: ProfileRechargeOrder; center: ProfileRechargeCenterResponse; - wechatMiniProgramPayParams?: WechatMiniProgramPayParams | null; + wechatMiniProgramPayParams?: + | WechatMiniProgramPayParams + | WechatMiniProgramVirtualPayParams + | null; wechatH5Payment?: WechatH5Payment | null; wechatNativePayment?: WechatNativePayment | null; }; diff --git a/server-rs/crates/api-server/Cargo.toml b/server-rs/crates/api-server/Cargo.toml index 2844c4da..052a8277 100644 --- a/server-rs/crates/api-server/Cargo.toml +++ b/server-rs/crates/api-server/Cargo.toml @@ -38,6 +38,7 @@ platform-image = { workspace = true } platform-llm = { workspace = true } platform-oss = { workspace = true } platform-speech = { workspace = true } +hmac = { workspace = true } ring = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } @@ -64,7 +65,6 @@ windows-sys = { workspace = true, features = ["Win32_Foundation", "Win32_System_ [dev-dependencies] base64 = { workspace = true } -hmac = { workspace = true } http-body-util = { workspace = true } reqwest = { workspace = true, features = ["json", "multipart", "rustls-tls"] } tower = { workspace = true, features = ["util"] } diff --git a/server-rs/crates/api-server/src/config.rs b/server-rs/crates/api-server/src/config.rs index 079f7b5a..433a67bd 100644 --- a/server-rs/crates/api-server/src/config.rs +++ b/server-rs/crates/api-server/src/config.rs @@ -96,6 +96,10 @@ pub struct AppConfig { pub wechat_pay_api_v3_key: Option, pub wechat_pay_notify_url: Option, pub wechat_pay_jsapi_endpoint: String, + pub wechat_mini_program_virtual_payment_offer_id: Option, + pub wechat_mini_program_virtual_payment_app_key: Option, + pub wechat_mini_program_virtual_payment_sandbox_app_key: Option, + pub wechat_mini_program_virtual_payment_env: u8, pub oss_bucket: Option, pub oss_endpoint: Option, pub oss_access_key_id: Option, @@ -240,6 +244,10 @@ impl Default for AppConfig { wechat_pay_notify_url: None, wechat_pay_jsapi_endpoint: "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi" .to_string(), + wechat_mini_program_virtual_payment_offer_id: None, + wechat_mini_program_virtual_payment_app_key: None, + wechat_mini_program_virtual_payment_sandbox_app_key: None, + wechat_mini_program_virtual_payment_env: 0, oss_bucket: None, oss_endpoint: None, oss_access_key_id: None, @@ -590,6 +598,18 @@ impl AppConfig { { config.wechat_pay_jsapi_endpoint = wechat_pay_jsapi_endpoint; } + config.wechat_mini_program_virtual_payment_offer_id = + read_first_non_empty_env(&["WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID"]); + config.wechat_mini_program_virtual_payment_app_key = + read_first_non_empty_env(&["WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY"]); + config.wechat_mini_program_virtual_payment_sandbox_app_key = + read_first_non_empty_env(&["WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY"]); + if let Some(env) = + read_first_u8_env(&["WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV"]) + && env <= 1 + { + config.wechat_mini_program_virtual_payment_env = env; + } config.oss_bucket = read_first_non_empty_env(&["ALIYUN_OSS_BUCKET"]); config.oss_endpoint = read_first_non_empty_env(&["ALIYUN_OSS_ENDPOINT"]); @@ -1379,6 +1399,10 @@ mod tests { std::env::remove_var("WECHAT_PAY_PLATFORM_SERIAL_NO"); std::env::remove_var("WECHAT_PAY_API_V3_KEY"); std::env::remove_var("WECHAT_PAY_NOTIFY_URL"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV"); std::env::set_var("WECHAT_PAY_ENABLED", "true"); std::env::set_var("WECHAT_PAY_PROVIDER", "real"); std::env::set_var("WECHAT_PAY_MCH_ID", "1900000109"); @@ -1394,6 +1418,19 @@ mod tests { "WECHAT_PAY_NOTIFY_URL", "https://api.example.com/api/profile/recharge/wechat/notify", ); + std::env::set_var( + "WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID", + "offer-001", + ); + std::env::set_var( + "WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY", + "app-key-001", + ); + std::env::set_var( + "WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY", + "sandbox-app-key-001", + ); + std::env::set_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV", "1"); } let config = AppConfig::from_env(); @@ -1416,6 +1453,21 @@ mod tests { config.wechat_pay_platform_serial_no.as_deref(), Some("platform-serial-001") ); + assert_eq!( + config.wechat_mini_program_virtual_payment_offer_id.as_deref(), + Some("offer-001") + ); + assert_eq!( + config.wechat_mini_program_virtual_payment_app_key.as_deref(), + Some("app-key-001") + ); + assert_eq!( + config + .wechat_mini_program_virtual_payment_sandbox_app_key + .as_deref(), + Some("sandbox-app-key-001") + ); + assert_eq!(config.wechat_mini_program_virtual_payment_env, 1); unsafe { std::env::remove_var("WECHAT_PAY_ENABLED"); @@ -1427,6 +1479,10 @@ mod tests { std::env::remove_var("WECHAT_PAY_PLATFORM_SERIAL_NO"); std::env::remove_var("WECHAT_PAY_API_V3_KEY"); std::env::remove_var("WECHAT_PAY_NOTIFY_URL"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY"); + std::env::remove_var("WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV"); } } diff --git a/server-rs/crates/api-server/src/runtime_profile.rs b/server-rs/crates/api-server/src/runtime_profile.rs index 345c2b89..d604bc18 100644 --- a/server-rs/crates/api-server/src/runtime_profile.rs +++ b/server-rs/crates/api-server/src/runtime_profile.rs @@ -8,6 +8,7 @@ use module_runtime::{ AnalyticsGranularity, PROFILE_RECHARGE_PAYMENT_CHANNEL_MOCK, PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_H5, PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM, + PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL, PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_NATIVE, RuntimeProfileFeedbackEvidenceRecord, RuntimeProfileFeedbackEvidenceSnapshot, RuntimeProfileFeedbackSubmissionRecord, RuntimeProfileInviteCodeRecord, RuntimeProfileMembershipBenefitRecord, @@ -23,6 +24,8 @@ use module_runtime::{ }; use serde::Deserialize; use serde_json::{Value, json}; +use hmac::{Hmac, Mac}; +use sha2::Sha256; use shared_contracts::runtime::{ ANALYTICS_GRANULARITY_DAY, ANALYTICS_GRANULARITY_MONTH, ANALYTICS_GRANULARITY_QUARTER, ANALYTICS_GRANULARITY_WEEK, ANALYTICS_GRANULARITY_YEAR, AdminDisableProfileRedeemCodeRequest, @@ -59,7 +62,8 @@ use shared_contracts::runtime::{ RedeemProfileReferralInviteCodeRequest, RedeemProfileReferralInviteCodeResponse, RedeemProfileRewardCodeRequest, RedeemProfileRewardCodeResponse, SubmitProfileFeedbackRequest, SubmitProfileFeedbackResponse, TRACKING_SCOPE_KIND_MODULE, TRACKING_SCOPE_KIND_SITE, - TRACKING_SCOPE_KIND_USER, TRACKING_SCOPE_KIND_WORK, + TRACKING_SCOPE_KIND_USER, TRACKING_SCOPE_KIND_WORK, WechatMiniProgramPaymentParamsResponse, + WechatMiniProgramVirtualPayParamsResponse, }; use shared_kernel::{offset_datetime_to_unix_micros, parse_rfc3339}; use spacetime_client::SpacetimeClientError; @@ -78,6 +82,8 @@ use crate::{ }, }; +type HmacSha256 = Hmac; + pub async fn get_profile_dashboard( State(state): State, Extension(request_context): Extension, @@ -231,7 +237,7 @@ pub async fn create_profile_recharge_order( let identity = resolve_wechat_identity_for_payment(&state, &order.user_id) .await .map_err(|error| runtime_profile_error_response(&request_context, error))?; - Some( + Some(WechatMiniProgramPaymentParamsResponse::Ordinary( state .wechat_pay_client() .create_mini_program_order(build_wechat_payment_request( @@ -244,6 +250,15 @@ pub async fn create_profile_recharge_order( .map_err(|error| { runtime_profile_error_response(&request_context, map_wechat_pay_error(error)) })?, + )) + } else if payment_channel == PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL { + let openid = resolve_wechat_identity_for_payment(&state, &order.user_id) + .await + .map_err(|error| runtime_profile_error_response(&request_context, error))?; + Some( + build_wechat_virtual_pay_params(&state, &order, &openid) + .map(WechatMiniProgramPaymentParamsResponse::Virtual) + .map_err(|error| runtime_profile_error_response(&request_context, error))?, ) } else { None @@ -1059,6 +1074,9 @@ fn validate_recharge_device_for_payment_channel( PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM => { claims.is_wechat_mini_program_device() } + PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL => { + claims.is_wechat_mini_program_device() + } PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_H5 => claims.is_mobile_wechat_browser_device(), PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_NATIVE => claims.is_desktop_wechat_browser_device(), _ => false, @@ -1106,6 +1124,7 @@ fn is_wechat_recharge_payment_channel(payment_channel: &str) -> bool { matches!( payment_channel, PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM + | PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL | PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_H5 | PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_NATIVE ) @@ -1148,6 +1167,127 @@ async fn resolve_wechat_identity_for_payment( .with_message("当前账号缺少微信小程序身份,请在小程序内重新登录后再支付")) } +fn build_wechat_virtual_pay_params( + state: &AppState, + order: &RuntimeProfileRechargeOrderRecord, + openid: &str, +) -> Result { + let identity = state + .wechat_auth_service() + .get_identity_by_user_id(&order.user_id) + .map_err(|error| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR) + .with_message(format!("读取微信身份失败:{error}")) + })? + .ok_or_else(|| { + AppError::from_status(StatusCode::BAD_REQUEST) + .with_message("当前账号缺少微信小程序身份,请在小程序内重新登录后再支付") + })?; + let session_key = identity.session_key.ok_or_else(|| { + AppError::from_status(StatusCode::BAD_REQUEST) + .with_message("当前微信登录态缺少 session_key,请重新登录后再试") + })?; + let product = module_runtime::runtime_profile_recharge_product_by_id(&order.product_id) + .ok_or_else(|| { + AppError::from_status(StatusCode::BAD_REQUEST).with_message("充值商品不存在") + })?; + let offer_id = required_wechat_virtual_payment_config( + state + .config + .wechat_mini_program_virtual_payment_offer_id + .as_deref(), + "微信虚拟支付 OfferId 未配置", + )?; + let mode = match product.kind { + RuntimeProfileRechargeProductKind::Points => "short_series_coin", + RuntimeProfileRechargeProductKind::Membership => "short_series_goods", + }; + let mut sign_data = serde_json::json!({ + "offerId": offer_id, + "buyQuantity": 1, + "env": state.config.wechat_mini_program_virtual_payment_env, + "currencyType": "CNY", + "outTradeNo": order.order_id, + "attach": serde_json::json!({ + "userId": order.user_id, + "productId": order.product_id, + "paymentChannel": order.payment_channel, + "openId": openid, + }).to_string(), + }); + if product.kind == RuntimeProfileRechargeProductKind::Membership { + sign_data["productId"] = json!(product.product_id); + sign_data["goodsPrice"] = json!(product.price_cents); + } + let sign_data = sign_data.to_string(); + let pay_sig = calc_wechat_virtual_payment_signature(state, &sign_data, false)?; + let signature = calc_wechat_virtual_payment_signature_with_key(&session_key, &sign_data)?; + + Ok(WechatMiniProgramVirtualPayParamsResponse { + mode: mode.to_string(), + sign_data, + pay_sig, + signature, + }) +} + +fn calc_wechat_virtual_payment_signature( + state: &AppState, + sign_data: &str, + use_sandbox_key: bool, +) -> Result { + let env = state.config.wechat_mini_program_virtual_payment_env; + let app_key = if use_sandbox_key || env == 1 { + state + .config + .wechat_mini_program_virtual_payment_sandbox_app_key + .as_deref() + .or(state.config.wechat_mini_program_virtual_payment_app_key.as_deref()) + } else { + state + .config + .wechat_mini_program_virtual_payment_app_key + .as_deref() + } + .ok_or_else(|| { + AppError::from_status(StatusCode::BAD_REQUEST) + .with_message("微信虚拟支付 AppKey 未配置") + })?; + calc_wechat_virtual_payment_signature_with_key(app_key, sign_data) +} + +fn required_wechat_virtual_payment_config<'a>( + value: Option<&'a str>, + message: &str, +) -> Result<&'a str, AppError> { + value + .map(str::trim) + .filter(|value| !value.is_empty()) + .ok_or_else(|| AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message(message)) +} + +fn calc_wechat_virtual_payment_signature_with_key( + key: &str, + sign_data: &str, +) -> Result { + let mut mac = HmacSha256::new_from_slice(key.as_bytes()).map_err(|_| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR) + .with_message("微信虚拟支付签名密钥初始化失败") + })?; + mac.update(format!("requestVirtualPayment&{sign_data}").as_bytes()); + Ok(to_lower_hex(mac.finalize().into_bytes().as_slice())) +} + +fn to_lower_hex(bytes: &[u8]) -> String { + const HEX: &[u8; 16] = b"0123456789abcdef"; + let mut output = String::with_capacity(bytes.len() * 2); + for &byte in bytes { + output.push(char::from(HEX[(byte >> 4) as usize])); + output.push(char::from(HEX[(byte & 0x0f) as usize])); + } + output +} + fn paid_at_micros_from_wechat_order(order: &WechatPayNotifyOrder) -> i64 { order .success_time @@ -1619,9 +1759,17 @@ fn build_profile_redeem_code_admin_response( #[cfg(test)] mod tests { - use module_runtime::RuntimeProfileWalletLedgerSourceType; + use module_auth::{ResolveWechatLoginInput, WechatIdentityProfile}; + use module_runtime::{ + PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL, + RuntimeProfileRechargeOrderRecord, RuntimeProfileRechargeOrderStatus, + RuntimeProfileRechargeProductKind, RuntimeProfileWalletLedgerSourceType, + }; - use super::{format_profile_wallet_ledger_source_type, normalize_admin_invite_code_metadata}; + use super::{ + build_wechat_virtual_pay_params, format_profile_wallet_ledger_source_type, + normalize_admin_invite_code_metadata, + }; use axum::{ body::Body, @@ -2082,6 +2230,70 @@ mod tests { ); } + #[tokio::test] + async fn wechat_virtual_pay_params_use_goods_mode_for_membership_products() { + let state = seed_authenticated_state_with_config(AppConfig { + wechat_mini_program_virtual_payment_offer_id: Some("offer-1".to_string()), + wechat_mini_program_virtual_payment_app_key: Some("app-key-1".to_string()), + wechat_mini_program_virtual_payment_env: 0, + ..fast_spacetime_timeout_config() + }) + .await; + let wechat_login = state + .wechat_auth_service() + .resolve_login(ResolveWechatLoginInput { + profile: WechatIdentityProfile { + provider_uid: "openid-user-00000001".to_string(), + provider_union_id: Some("union-user-00000001".to_string()), + display_name: Some("资料页用户".to_string()), + avatar_url: None, + session_key: Some("session-key-1".to_string()), + }, + }) + .await + .expect("wechat identity should seed"); + let user_id = wechat_login.user.id; + let order = RuntimeProfileRechargeOrderRecord { + order_id: "memberorder01".to_string(), + user_id: user_id.clone(), + product_id: "member_month".to_string(), + product_title: "月卡".to_string(), + kind: RuntimeProfileRechargeProductKind::Membership, + amount_cents: 2800, + status: RuntimeProfileRechargeOrderStatus::Pending, + payment_channel: PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL + .to_string(), + paid_at: None, + paid_at_micros: None, + provider_transaction_id: None, + created_at: "2026-05-26T10:00:00Z".to_string(), + created_at_micros: 1_779_756_000_000_000, + points_delta: 0, + membership_expires_at: None, + membership_expires_at_micros: None, + }; + + let params = build_wechat_virtual_pay_params(&state, &order, "openid-user-00000001") + .expect("membership virtual pay params should build"); + let sign_data: Value = + serde_json::from_str(¶ms.sign_data).expect("sign data should be valid json"); + let attach: Value = serde_json::from_str( + sign_data["attach"] + .as_str() + .expect("attach should be string json"), + ) + .expect("attach should decode"); + + assert_eq!(params.mode, "short_series_goods"); + assert_eq!(sign_data["offerId"], "offer-1"); + assert_eq!(sign_data["productId"], "member_month"); + assert_eq!(sign_data["goodsPrice"], 2800); + assert_eq!(sign_data["outTradeNo"], "memberorder01"); + assert_eq!(attach["paymentChannel"], "wechat_mp_virtual"); + assert!(!params.pay_sig.is_empty()); + assert!(!params.signature.is_empty()); + } + #[tokio::test] async fn profile_feedback_requires_authentication() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); diff --git a/server-rs/crates/api-server/src/wechat_auth.rs b/server-rs/crates/api-server/src/wechat_auth.rs index d7381253..d7dfc858 100644 --- a/server-rs/crates/api-server/src/wechat_auth.rs +++ b/server-rs/crates/api-server/src/wechat_auth.rs @@ -385,6 +385,7 @@ fn map_wechat_profile_to_domain( provider_union_id: profile.provider_union_id, display_name: profile.display_name, avatar_url: profile.avatar_url, + session_key: profile.session_key, } } diff --git a/server-rs/crates/module-auth/src/domain.rs b/server-rs/crates/module-auth/src/domain.rs index d8057f81..a7999183 100644 --- a/server-rs/crates/module-auth/src/domain.rs +++ b/server-rs/crates/module-auth/src/domain.rs @@ -116,6 +116,7 @@ pub struct WechatIdentityProfile { pub provider_union_id: Option, pub display_name: Option, pub avatar_url: Option, + pub session_key: Option, } /// 已绑定微信身份快照。 @@ -124,6 +125,7 @@ pub struct WechatIdentityRecord { pub user_id: String, pub provider_uid: String, pub provider_union_id: Option, + pub session_key: Option, } /// 微信授权 state 快照。 diff --git a/server-rs/crates/module-auth/src/lib.rs b/server-rs/crates/module-auth/src/lib.rs index 3d628ec1..0bbc7f00 100644 --- a/server-rs/crates/module-auth/src/lib.rs +++ b/server-rs/crates/module-auth/src/lib.rs @@ -97,6 +97,7 @@ struct StoredWechatIdentity { provider_union_id: Option, display_name: Option, avatar_url: Option, + session_key: Option, } #[derive(Clone, Debug)] @@ -1292,6 +1293,7 @@ impl InMemoryAuthStore { provider_union_id: normalize_optional_string(profile.provider_union_id), display_name: normalize_optional_string(profile.display_name), avatar_url, + session_key: normalize_optional_string(profile.session_key), }; if let Some(provider_union_id) = identity.provider_union_id.clone() { state @@ -1361,6 +1363,7 @@ impl InMemoryAuthStore { user_id: identity.user_id.clone(), provider_uid: identity.provider_uid.clone(), provider_union_id: identity.provider_union_id.clone(), + session_key: identity.session_key.clone(), })) } @@ -1377,6 +1380,7 @@ impl InMemoryAuthStore { let next_display_name = normalize_optional_string(profile.display_name); let next_avatar_url = normalize_optional_string(profile.avatar_url); let next_provider_union_id = normalize_optional_string(profile.provider_union_id); + let next_session_key = normalize_optional_string(profile.session_key); let next_provider_uid = normalize_required_string(&profile.provider_uid).unwrap_or_default(); { @@ -1398,6 +1402,9 @@ impl InMemoryAuthStore { identity.display_name = next_display_name.clone(); identity.avatar_url = next_avatar_url; identity.provider_union_id = next_provider_union_id.clone(); + if next_session_key.is_some() { + identity.session_key = next_session_key.clone(); + } state .wechat_identity_by_provider_uid .insert(next_provider_uid.clone(), identity); @@ -3193,6 +3200,7 @@ mod tests { provider_union_id: Some("wx-union-shared".to_string()), display_name: Some("微信旅人甲".to_string()), avatar_url: None, + session_key: None, }, }) .await @@ -3211,6 +3219,7 @@ mod tests { provider_union_id: Some("wx-union-shared".to_string()), display_name: Some("微信旅人乙".to_string()), avatar_url: None, + session_key: None, }, }) .await @@ -3258,6 +3267,7 @@ mod tests { provider_union_id: Some("wx-union-bind".to_string()), display_name: Some("待绑定微信用户".to_string()), avatar_url: None, + session_key: None, }, }) .await @@ -3303,6 +3313,7 @@ mod tests { provider_union_id: Some("wx-union-bind".to_string()), display_name: Some("已归并微信用户".to_string()), avatar_url: None, + session_key: None, }, }) .await diff --git a/server-rs/crates/module-runtime/src/domain.rs b/server-rs/crates/module-runtime/src/domain.rs index bc7dff76..68bf33bf 100644 --- a/server-rs/crates/module-runtime/src/domain.rs +++ b/server-rs/crates/module-runtime/src/domain.rs @@ -34,6 +34,7 @@ pub const SAVE_SNAPSHOT_VERSION: u32 = 2; pub const DEFAULT_SAVE_ARCHIVE_SUMMARY_TEXT: &str = "继续推进上一次保存的故事。"; pub const PROFILE_RECHARGE_PAYMENT_CHANNEL_MOCK: &str = "mock"; pub const PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM: &str = "wechat_mp"; +pub const PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL: &str = "wechat_mp_virtual"; pub const PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_H5: &str = "wechat_h5"; pub const PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_NATIVE: &str = "wechat_native"; pub const PROFILE_FEEDBACK_DESCRIPTION_MIN_CHARS: usize = 10; diff --git a/server-rs/crates/platform-auth/src/lib.rs b/server-rs/crates/platform-auth/src/lib.rs index 9e2a657a..4615ae59 100644 --- a/server-rs/crates/platform-auth/src/lib.rs +++ b/server-rs/crates/platform-auth/src/lib.rs @@ -225,6 +225,7 @@ pub struct WechatIdentityProfile { pub provider_union_id: Option, pub display_name: Option, pub avatar_url: Option, + pub session_key: Option, } #[derive(Clone, Debug)] @@ -359,6 +360,7 @@ struct WechatUserInfoResponse { struct WechatJsCodeSessionResponse { openid: Option, unionid: Option, + session_key: Option, errcode: Option, errmsg: Option, } @@ -834,6 +836,7 @@ impl MockWechatProvider { provider_union_id: self.mock_union_id.clone(), display_name: Some(self.mock_display_name.clone()), avatar_url: self.mock_avatar_url.clone(), + session_key: None, } } } @@ -975,6 +978,7 @@ impl RealWechatProvider { provider_union_id: user_info_payload.unionid.or(access_token_payload.unionid), display_name: user_info_payload.nickname, avatar_url: user_info_payload.headimgurl, + session_key: None, }) } @@ -1053,6 +1057,7 @@ impl RealWechatProvider { provider_union_id: payload.unionid, display_name: None, avatar_url: None, + session_key: payload.session_key, }) } diff --git a/server-rs/crates/shared-contracts/src/runtime.rs b/server-rs/crates/shared-contracts/src/runtime.rs index 2d2fc722..d88c07f8 100644 --- a/server-rs/crates/shared-contracts/src/runtime.rs +++ b/server-rs/crates/shared-contracts/src/runtime.rs @@ -245,6 +245,22 @@ pub struct WechatMiniProgramPayParamsResponse { pub pay_sign: String, } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct WechatMiniProgramVirtualPayParamsResponse { + pub mode: String, + pub sign_data: String, + pub pay_sig: String, + pub signature: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum WechatMiniProgramPaymentParamsResponse { + Ordinary(WechatMiniProgramPayParamsResponse), + Virtual(WechatMiniProgramVirtualPayParamsResponse), +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct WechatH5PaymentResponse { @@ -283,7 +299,7 @@ pub struct CreateProfileRechargeOrderResponse { pub order: ProfileRechargeOrderResponse, pub center: ProfileRechargeCenterResponse, #[serde(default)] - pub wechat_mini_program_pay_params: Option, + pub wechat_mini_program_pay_params: Option, #[serde(default)] pub wechat_h5_payment: Option, #[serde(default)] @@ -1451,6 +1467,67 @@ mod tests { ); } + #[test] + fn create_profile_recharge_order_response_serializes_virtual_wechat_payloads() { + let order = ProfileRechargeOrderResponse { + order_id: "rcgtest002".to_string(), + product_id: "member_month".to_string(), + product_title: "月卡".to_string(), + kind: "membership".to_string(), + amount_cents: 2800, + status: "pending".to_string(), + payment_channel: "wechat_mp_virtual".to_string(), + paid_at: None, + provider_transaction_id: None, + created_at: "2026-05-15T10:00:00Z".to_string(), + points_delta: 0, + membership_expires_at: Some("2026-06-15T10:00:00Z".to_string()), + }; + let center = ProfileRechargeCenterResponse { + wallet_balance: 0, + membership: ProfileMembershipResponse { + status: "normal".to_string(), + tier: "normal".to_string(), + started_at: None, + expires_at: None, + updated_at: None, + }, + point_products: vec![], + membership_products: vec![], + benefits: vec![], + latest_order: None, + has_points_recharged: false, + }; + let payload = serde_json::to_value(CreateProfileRechargeOrderResponse { + order, + center, + wechat_mini_program_pay_params: Some(WechatMiniProgramPaymentParamsResponse::Virtual( + WechatMiniProgramVirtualPayParamsResponse { + mode: "short_series_goods".to_string(), + sign_data: + "{\"offerId\":\"offer-1\",\"productId\":\"member_month\",\"goodsPrice\":2800}" + .to_string(), + pay_sig: "pay-sig".to_string(), + signature: "user-sig".to_string(), + }, + )), + wechat_h5_payment: None, + wechat_native_payment: None, + }) + .expect("payload should serialize"); + + assert_eq!( + payload["wechatMiniProgramPayParams"]["mode"], + json!("short_series_goods") + ); + assert_eq!( + payload["wechatMiniProgramPayParams"]["signData"], + json!("{\"offerId\":\"offer-1\",\"productId\":\"member_month\",\"goodsPrice\":2800}") + ); + assert_eq!(payload["wechatMiniProgramPayParams"]["paySig"], json!("pay-sig")); + assert_eq!(payload["wechatMiniProgramPayParams"]["signature"], json!("user-sig")); + } + #[test] fn profile_feedback_response_uses_camel_case_fields() { let payload = serde_json::to_value(SubmitProfileFeedbackResponse { diff --git a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx index f27b62c7..ebc0acb5 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx @@ -236,7 +236,7 @@ const { kind: 'points', amountCents: 600, status: 'paid', - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: '2026-04-25T10:01:00Z', providerTransactionId: 'wx-transaction-1', createdAt: '2026-04-25T10:00:00Z', @@ -275,7 +275,7 @@ const { kind: 'points', amountCents: 600, status: 'paid', - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', providerTransactionId: 'wx-transaction-1', createdAt: '2026-04-25T10:00:00Z', paidAt: '2026-04-25T10:01:00Z', @@ -1319,7 +1319,7 @@ test('profile recharge modal trusts per-product first bonus display after points expect(screen.getByText('60+60泥点')).toBeTruthy(); }); -test('profile recharge modal posts requestPayment params in mini program web-view', async () => { +test('profile recharge modal posts virtual payment params in mini program web-view', async () => { const user = userEvent.setup(); const onRechargeSuccess = vi.fn(); window.history.replaceState(null, '', '/?clientRuntime=wechat_mini_program'); @@ -1339,7 +1339,7 @@ test('profile recharge modal posts requestPayment params in mini program web-vie kind: 'points', amountCents: 600, status: 'pending' as const, - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: null as string | null, providerTransactionId: null, createdAt: '2026-04-25T10:00:00Z', @@ -1362,11 +1362,11 @@ test('profile recharge modal posts requestPayment params in mini program web-vie hasPointsRecharged: false, }, wechatMiniProgramPayParams: { - timeStamp: '1777110165', - nonceStr: 'nonce', - package: 'prepay_id=wx-prepay', - signType: 'RSA', - paySign: 'signature', + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","outTradeNo":"order-wechat-1","attach":"mud_points_60"}', + paySig: 'pay-sig', + signature: 'user-sig', }, }); @@ -1377,7 +1377,7 @@ test('profile recharge modal posts requestPayment params in mini program web-vie await waitFor(() => { expect(mockCreateRpgProfileRechargeOrder).toHaveBeenCalledWith( 'points_60', - 'wechat_mp', + 'wechat_mp_virtual', ); }); expect(navigateTo).toHaveBeenCalledWith({ @@ -1395,7 +1395,7 @@ test('profile recharge modal posts requestPayment params in mini program web-vie window.dispatchEvent(new HashChangeEvent('hashchange')); }); expect(navigateUrl).toContain('order-wechat-1'); - expect(decodeURIComponent(navigateUrl)).toContain('prepay_id=wx-prepay'); + expect(decodeURIComponent(navigateUrl)).toContain('short_series_coin'); expect(await screen.findByRole('dialog', { name: '支付成功' })).toBeTruthy(); expect(mockCreateRpgProfileRechargeOrder).not.toHaveBeenCalledWith( 'points_60', @@ -1409,6 +1409,82 @@ test('profile recharge modal posts requestPayment params in mini program web-vie expect(onRechargeSuccess).toHaveBeenCalledTimes(1); }); +test('profile recharge modal posts membership goods virtual payment params in mini program web-view', async () => { + const user = userEvent.setup(); + window.history.replaceState(null, '', '/?clientRuntime=wechat_mini_program'); + const navigateTo = vi.fn((options: { url: string; success?: () => void }) => { + options.success?.(); + }); + window.wx = { + miniProgram: { + navigateTo, + }, + }; + mockCreateRpgProfileRechargeOrder.mockResolvedValueOnce({ + order: { + orderId: 'order-member-virtual-1', + productId: 'member_month', + productTitle: '月卡', + kind: 'membership', + amountCents: 2800, + status: 'pending' as const, + paymentChannel: 'wechat_mp_virtual', + paidAt: null as string | null, + providerTransactionId: null, + createdAt: '2026-04-25T10:00:00Z', + pointsDelta: 0, + membershipExpiresAt: '2026-06-25T10:00:00Z', + }, + center: { + walletBalance: 0, + membership: { + status: 'normal', + tier: 'normal', + startedAt: null, + expiresAt: null, + updatedAt: null, + }, + pointProducts: [], + membershipProducts: [], + benefits: [], + latestOrder: null, + hasPointsRecharged: false, + }, + wechatMiniProgramPayParams: { + mode: 'short_series_goods', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","productId":"member_month","goodsPrice":2800,"outTradeNo":"order-member-virtual-1","attach":"member_month"}', + paySig: 'pay-sig', + signature: 'user-sig', + }, + }); + + renderProfileView(); + await openRechargeModal(user); + await user.click(screen.getByRole('button', { name: '会员卡' })); + await user.click(await screen.findByRole('button', { name: /月卡/u })); + + await waitFor(() => { + expect(mockCreateRpgProfileRechargeOrder).toHaveBeenCalledWith( + 'member_month', + 'wechat_mp_virtual', + ); + }); + const navigateUrl = navigateTo.mock.calls[0]?.[0].url ?? ''; + const requestId = new URL(`https://mini.test${navigateUrl}`).searchParams.get( + 'requestId', + ); + expect(requestId).toBeTruthy(); + const payParams = JSON.parse( + new URL(`https://mini.test${navigateUrl}`).searchParams.get('payParams') ?? '{}', + ); + const signData = JSON.parse(payParams.signData); + expect(payParams.mode).toBe('short_series_goods'); + expect(signData.productId).toBe('member_month'); + expect(signData.goodsPrice).toBe(2800); + expect(decodeURIComponent(navigateUrl)).toContain('"paySig":"pay-sig"'); +}); + test('profile recharge modal waits for paid confirmation before refreshing dashboard', async () => { const user = userEvent.setup(); const onRechargeSuccess = vi.fn(); @@ -1429,7 +1505,7 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb kind: 'points', amountCents: 600, status: 'pending' as const, - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: null as string | null, providerTransactionId: null, createdAt: '2026-04-25T10:00:00Z', @@ -1452,11 +1528,11 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb hasPointsRecharged: false, }, wechatMiniProgramPayParams: { - timeStamp: '1777110165', - nonceStr: 'nonce', - package: 'prepay_id=wx-prepay', - signType: 'RSA', - paySign: 'signature', + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","outTradeNo":"order-wechat-pending-then-paid","attach":"mud_points_60"}', + paySig: 'pay-sig', + signature: 'user-sig', }, }); mockConfirmWechatRpgProfileRechargeOrder @@ -1468,7 +1544,7 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb kind: 'points', amountCents: 600, status: 'pending' as const, - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: null, providerTransactionId: null, createdAt: '2026-04-25T10:00:00Z', @@ -1499,7 +1575,7 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb kind: 'points', amountCents: 600, status: 'paid' as const, - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: '2026-04-25T10:01:00Z', providerTransactionId: 'wx-transaction-2', createdAt: '2026-04-25T10:00:00Z', @@ -1563,7 +1639,7 @@ test('profile recharge modal loads wechat js sdk before mini program payment bri kind: 'points', amountCents: 600, status: 'pending' as const, - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: null as string | null, providerTransactionId: null, createdAt: '2026-04-25T10:00:00Z', @@ -1586,11 +1662,11 @@ test('profile recharge modal loads wechat js sdk before mini program payment bri hasPointsRecharged: false, }, wechatMiniProgramPayParams: { - timeStamp: '1777110165', - nonceStr: 'nonce', - package: 'prepay_id=wx-prepay', - signType: 'RSA', - paySign: 'signature', + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","outTradeNo":"order-wechat-sdk-1","attach":"mud_points_60"}', + paySig: 'pay-sig', + signature: 'user-sig', }, }); @@ -1649,7 +1725,7 @@ test('profile recharge modal releases submitting state after cancelled wechat pa kind: 'points', amountCents: 600, status: 'pending' as const, - paymentChannel: 'wechat_mp', + paymentChannel: 'wechat_mp_virtual', paidAt: null as string | null, providerTransactionId: null, createdAt: '2026-04-25T10:00:00Z', @@ -1672,11 +1748,11 @@ test('profile recharge modal releases submitting state after cancelled wechat pa hasPointsRecharged: false, }, wechatMiniProgramPayParams: { - timeStamp: '1777110165', - nonceStr: 'nonce', - package: 'prepay_id=wx-prepay-cancel', - signType: 'RSA', - paySign: 'signature', + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","outTradeNo":"order-wechat-cancel-1","attach":"mud_points_60"}', + paySig: 'pay-sig', + signature: 'user-sig', }, }); @@ -1688,7 +1764,7 @@ test('profile recharge modal releases submitting state after cancelled wechat pa await waitFor(() => { expect(mockCreateRpgProfileRechargeOrder).toHaveBeenCalledWith( 'points_60', - 'wechat_mp', + 'wechat_mp_virtual', ); }); expect( diff --git a/src/components/rpg-entry/RpgEntryHomeView.tsx b/src/components/rpg-entry/RpgEntryHomeView.tsx index ab466e98..636ff874 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.tsx @@ -76,6 +76,7 @@ import type { ProfileWalletLedgerResponse, RedeemProfileRewardCodeResponse, WechatMiniProgramPayParams, + WechatMiniProgramVirtualPayParams, WechatNativePayment, } from '../../../packages/shared/src/contracts/runtime'; import { isMatch3DDemoProfileId } from '../../data/match3dDemoGalleryCard'; @@ -89,10 +90,10 @@ import { } from '../../services/authService'; import { copyTextToClipboard } from '../../services/clipboard'; import { - resolveProfileRechargePaymentChannel, + resolveProfileRechargeProductPaymentChannel, shouldShowRechargeEntry, WECHAT_H5_PAYMENT_CHANNEL, - WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL, + WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL, WECHAT_NATIVE_PAYMENT_CHANNEL, } from '../../services/payment/paymentPlatform'; import { redirectToPaymentUrl } from '../../services/payment/paymentRedirect'; @@ -2740,7 +2741,11 @@ function loadWechatJsSdk() { } async function requestWechatMiniProgramPayment( - payload: WechatMiniProgramPayParams | null | undefined, + payload: + | WechatMiniProgramPayParams + | WechatMiniProgramVirtualPayParams + | null + | undefined, orderId: string, ): Promise { if (!payload) { @@ -4664,14 +4669,17 @@ export function RpgEntryHomeView({ return; } - const paymentChannel = resolveProfileRechargePaymentChannel(); + const paymentChannel = resolveProfileRechargeProductPaymentChannel( + { kind: product.kind }, + {}, + ); setSubmittingRechargeProductId(product.productId); setRechargeError(null); setRechargePaymentResult(null); setNativeWechatPayment(null); void createRpgProfileRechargeOrder(product.productId, paymentChannel) .then(async (response) => { - if (paymentChannel === WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL) { + if (paymentChannel === WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL) { pendingWechatRechargeOrderIdRef.current = response.order.orderId; await requestWechatMiniProgramPayment( response.wechatMiniProgramPayParams, diff --git a/src/services/payment/paymentPlatform.test.ts b/src/services/payment/paymentPlatform.test.ts index f26cf332..10f82284 100644 --- a/src/services/payment/paymentPlatform.test.ts +++ b/src/services/payment/paymentPlatform.test.ts @@ -2,20 +2,45 @@ import { describe, expect, test } from 'vitest'; import { resolveProfileRechargePaymentChannel, + resolveProfileRechargeProductPaymentChannel, shouldShowRechargeEntry, WECHAT_H5_PAYMENT_CHANNEL, - WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL, + WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL, WECHAT_NATIVE_PAYMENT_CHANNEL, } from './paymentPlatform'; describe('resolveProfileRechargePaymentChannel', () => { - test('小程序运行态选择 wechat_mp', () => { + test('小程序运行态基础通道选择 wechat_mp_virtual', () => { expect( resolveProfileRechargePaymentChannel({ location: { search: '?clientRuntime=wechat_mini_program' }, navigator: { userAgent: 'Mozilla/5.0 (iPhone)' }, }), - ).toBe(WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL); + ).toBe(WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL); + }); + + test('点数商品在小程序运行态选择 wechat_mp_virtual', () => { + expect( + resolveProfileRechargeProductPaymentChannel( + { kind: 'points' }, + { + location: { search: '?clientRuntime=wechat_mini_program' }, + navigator: { userAgent: 'Mozilla/5.0 (iPhone)' }, + }, + ), + ).toBe(WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL); + }); + + test('会员商品在小程序运行态也选择 wechat_mp_virtual', () => { + expect( + resolveProfileRechargeProductPaymentChannel( + { kind: 'membership' }, + { + location: { search: '?clientRuntime=wechat_mini_program' }, + navigator: { userAgent: 'Mozilla/5.0 (iPhone)' }, + }, + ), + ).toBe(WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL); }); test('移动网页选择 wechat_h5', () => { diff --git a/src/services/payment/paymentPlatform.ts b/src/services/payment/paymentPlatform.ts index 93b26b8a..28f15a27 100644 --- a/src/services/payment/paymentPlatform.ts +++ b/src/services/payment/paymentPlatform.ts @@ -1,13 +1,19 @@ export const WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL = 'wechat_mp'; +export const WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL = 'wechat_mp_virtual'; export const WECHAT_H5_PAYMENT_CHANNEL = 'wechat_h5'; export const WECHAT_NATIVE_PAYMENT_CHANNEL = 'wechat_native'; export const MOCK_PAYMENT_CHANNEL = 'mock'; export type ProfileRechargeWechatPaymentChannel = | typeof WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL + | typeof WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL | typeof WECHAT_H5_PAYMENT_CHANNEL | typeof WECHAT_NATIVE_PAYMENT_CHANNEL; +export type ProfileRechargeProductPaymentMode = { + kind: 'points' | 'membership'; +}; + type PaymentPlatformNavigator = Pick; export type PaymentPlatformContext = { @@ -45,7 +51,7 @@ export function resolveProfileRechargePaymentChannel( : null); if (isWechatMiniProgramRuntime(location)) { - return WECHAT_MINI_PROGRAM_PAYMENT_CHANNEL; + return WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL; } if (isMobileWebRuntime(navigatorLike, matchMedia)) { @@ -55,6 +61,13 @@ export function resolveProfileRechargePaymentChannel( return WECHAT_NATIVE_PAYMENT_CHANNEL; } +export function resolveProfileRechargeProductPaymentChannel( + _product: ProfileRechargeProductPaymentMode, + context: PaymentPlatformContext = {}, +): ProfileRechargeWechatPaymentChannel { + return resolveProfileRechargePaymentChannel(context); +} + export function isManualMockPaymentChannel(paymentChannel: string) { return paymentChannel.trim() === MOCK_PAYMENT_CHANNEL; } From 9c6fa103012217ba42f5d48e8a7b96f1d0741130 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Thu, 28 May 2026 00:41:06 +0800 Subject: [PATCH 02/31] fix wechat mini program virtual payment flow --- ...【技术方案】微信虚拟支付接入-2026-05-26.md | 6 +- miniprogram/pages/web-view/index.js | 40 ++++++++- miniprogram/pages/wechat-pay/index.shared.js | 66 +++++++++++---- miniprogram/pages/wechat-pay/index.test.js | 32 ++++--- scripts/miniprogram-web-view-auth.test.ts | 55 ++++++++++-- .../crates/api-server/src/runtime_profile.rs | 75 ++++++++++++++--- .../PlatformEntryFlowShellImpl.tsx | 3 +- .../RpgEntryHomeView.recharge.test.tsx | 84 ++++++++++++++++++- src/components/rpg-entry/RpgEntryHomeView.tsx | 30 ++++++- vitest.config.ts | 1 + 10 files changed, 335 insertions(+), 57 deletions(-) diff --git a/docs/【技术方案】微信虚拟支付接入-2026-05-26.md b/docs/【技术方案】微信虚拟支付接入-2026-05-26.md index afe1ff24..c5fdf9ed 100644 --- a/docs/【技术方案】微信虚拟支付接入-2026-05-26.md +++ b/docs/【技术方案】微信虚拟支付接入-2026-05-26.md @@ -9,6 +9,7 @@ - H5 与桌面微信环境仍分别走 `wechat_h5` / `wechat_native`,不进入虚拟支付链路。 - `session_key` 只保存在后端认证仓储内,用于计算虚拟支付用户态签名,不下发给前端。 - 客户端支付成功回调只代表已拉起支付并返回成功;最终到账仍以后端微信通知或查询确认后写入订单为准。 +- 小程序 WebView 默认进入时会静默调用 `wx.login` 刷新后端微信登录态,避免历史登录用户只有前端 JWT、后端缺少 `session_key` 时无法生成虚拟支付签名。 ## 关键文件 @@ -51,6 +52,9 @@ npm run check:encoding ## 注意事项 -- 旧微信登录快照可能没有 `session_key`,用户需要在小程序内重新登录后再发起虚拟支付。 +- 旧微信登录快照可能没有 `session_key`;小程序 WebView 会在普通进入时静默刷新一次微信登录态,刷新失败时仍允许匿名打开 WebView,但虚拟支付会继续由后端拦截并提示重新登录。 - 小程序充值商品全部映射到虚拟支付;泥点使用 `short_series_coin`,会员使用 `short_series_goods`。 +- 后台新增的会员类充值商品会直接把商品 `productId` 作为微信 `short_series_goods` 的道具 ID;例如微信后台道具 ID 为 `item01` 时,后台会员商品 `productId` 也应配置为 `item01`,且商品价格需要与微信后台道具价格一致。 - 小程序页必须保留普通支付与虚拟支付双分支,按 pay params 字段判断调用 `wx.requestPayment` 或 `wx.requestVirtualPayment`。 +- 小程序支付承接页回传 `wx_pay_result` 时必须携带 `requestId:status:orderId[:error]`,并同时写入上一页 hash 与本地 storage;WebView `onShow` 会立即检查一次、延迟二次检查一次,且同名 hash 参数必须替换,避免支付状态停留在处理中或重复处理。 +- 沙箱或基础库失败会把微信返回的 `errCode` / `errMsg` 透传到前端失败弹窗,便于区分微信后台道具、沙箱 AppKey、签名和基础库能力问题。 diff --git a/miniprogram/pages/web-view/index.js b/miniprogram/pages/web-view/index.js index c199300b..1f33e2cb 100644 --- a/miniprogram/pages/web-view/index.js +++ b/miniprogram/pages/web-view/index.js @@ -15,6 +15,7 @@ const CLIENT_INSTANCE_STORAGE_KEY = 'genarrative:mini-program-client-instance-id const PAY_RESULT_STORAGE_KEY = 'genarrative:wechat-pay-result'; const AUTH_RESULT_STORAGE_KEY = 'genarrative:mini-program-auth-result'; const AUTH_ACTION_LOGIN = 'login'; +const PAY_RESULT_RECHECK_DELAY_MS = 120; function isConfiguredEntryUrl(value) { const trimmed = String(value || '').trim(); @@ -45,6 +46,7 @@ function appendQuery(url, query) { } function appendHashParams(url, params) { + const nextKeys = new Set(Object.keys(params).filter((key) => params[key])); const pairs = Object.keys(params) .filter((key) => params[key]) .map( @@ -58,8 +60,18 @@ function appendHashParams(url, params) { const hashIndex = url.indexOf('#'); const baseUrl = hashIndex >= 0 ? url.slice(0, hashIndex) : url; const rawHash = hashIndex >= 0 ? url.slice(hashIndex + 1) : ''; - const separator = rawHash ? '&' : ''; - return `${baseUrl}#${rawHash}${separator}${pairs.join('&')}`; + const keptHashParts = rawHash.split('&').filter((part) => { + if (!part) { + return false; + } + const [rawKey = ''] = part.split('='); + try { + return !nextKeys.has(decodeURIComponent(rawKey)); + } catch (_error) { + return !nextKeys.has(rawKey); + } + }); + return `${baseUrl}#${keptHashParts.concat(pairs).join('&')}`; } function parseBooleanQueryFlag(value) { @@ -259,6 +271,18 @@ async function resolveAuthResult() { }; } +async function refreshMiniProgramSessionSilently() { + if (!isConfiguredApiBaseUrl(API_BASE_URL)) { + return null; + } + try { + return await resolveAuthResult(); + } catch (error) { + console.warn('[web-view] silent mini program login refresh failed', error); + return null; + } +} + Page({ data: { authResult: null, @@ -285,13 +309,14 @@ Page({ const forcedPhoneBinding = parseBooleanQueryFlag(query.phoneBindingRequired); const returnToPreviousPage = shouldReturnToPreviousPage(query); if (!shouldStartAuthFromQuery(query) && !forcedPhoneBinding) { + const authResult = await refreshMiniProgramSessionSilently(); this.setData({ - authResult: null, + authResult, errorMessage: '', loading: false, phoneBindingRequired: false, returnToPreviousPage: false, - webViewUrl: resolveWebViewUrl(null), + webViewUrl: resolveWebViewUrl(authResult), }); return; } @@ -362,6 +387,13 @@ Page({ }); } + this.consumePayResult(); + setTimeout(() => { + this.consumePayResult(); + }, PAY_RESULT_RECHECK_DELAY_MS); + }, + + consumePayResult() { const result = wx.getStorageSync(PAY_RESULT_STORAGE_KEY); if (result && this.data.webViewUrl) { wx.removeStorageSync(PAY_RESULT_STORAGE_KEY); diff --git a/miniprogram/pages/wechat-pay/index.shared.js b/miniprogram/pages/wechat-pay/index.shared.js index cdf73eb3..d35b3c7d 100644 --- a/miniprogram/pages/wechat-pay/index.shared.js +++ b/miniprogram/pages/wechat-pay/index.shared.js @@ -64,6 +64,23 @@ function resolvePayStatus(error) { return errCode === -2 || /cancel/i.test(errMsg) ? 'cancel' : 'fail'; } +function normalizePayError(error) { + if (!error) { + return ''; + } + if (typeof error === 'string') { + return error; + } + try { + return JSON.stringify({ + errCode: error.errCode, + errMsg: error.errMsg, + }); + } catch (_error) { + return String(error.errMsg || error); + } +} + function requestOrdinaryPayment(payParams) { return new Promise((resolve) => { wx.requestPayment({ @@ -73,10 +90,13 @@ function requestOrdinaryPayment(payParams) { signType: payParams.signType || 'RSA', paySign: String(payParams.paySign || ''), success() { - resolve('success'); + resolve({ status: 'success', errorMessage: '' }); }, fail(error) { - resolve(resolvePayStatus(error)); + resolve({ + status: resolvePayStatus(error), + errorMessage: normalizePayError(error), + }); }, }); }); @@ -85,7 +105,10 @@ function requestOrdinaryPayment(payParams) { function requestVirtualPayment(payParams) { return new Promise((resolve) => { if (!canUseVirtualPayment() || typeof wx.requestVirtualPayment !== 'function') { - resolve('fail'); + resolve({ + status: 'fail', + errorMessage: '当前微信基础库不支持 requestVirtualPayment', + }); return; } wx.requestVirtualPayment({ @@ -94,10 +117,13 @@ function requestVirtualPayment(payParams) { paySig: String(payParams.paySig || ''), signature: String(payParams.signature || ''), success() { - resolve('success'); + resolve({ status: 'success', errorMessage: '' }); }, fail(error) { - resolve(resolvePayStatus(error)); + resolve({ + status: resolvePayStatus(error), + errorMessage: normalizePayError(error), + }); }, }); }); @@ -112,8 +138,7 @@ function requestWechatPayment(payParams) { const PAY_RESULT_STORAGE_KEY = 'genarrative:wechat-pay-result'; -function appendPayResult(url, requestId, status) { - const value = `${requestId}:${status}`; +function appendPayResult(url, result) { const hashIndex = String(url || '').indexOf('#'); const baseUrl = hashIndex >= 0 ? String(url).slice(0, hashIndex) : String(url || ''); @@ -121,23 +146,27 @@ function appendPayResult(url, requestId, status) { const nextHash = rawHash .split('&') .filter((part) => part && !part.startsWith('wx_pay_result=')) - .concat(`wx_pay_result=${encodeURIComponent(value)}`) + .concat(`wx_pay_result=${encodeURIComponent(result)}`) .join('&'); return `${baseUrl}#${nextHash}`; } -function notifyPreviousWebView(requestId, status) { - const result = `${requestId}:${status}`; +function buildPayResultValue(requestId, orderId, payResult) { + const segments = [requestId, payResult.status, orderId || '']; + if (payResult.errorMessage) { + segments.push(encodeURIComponent(payResult.errorMessage)); + } + return segments.join(':'); +} + +function notifyPreviousWebView(requestId, orderId, payResult) { + const result = buildPayResultValue(requestId, orderId, payResult); wx.setStorageSync(PAY_RESULT_STORAGE_KEY, result); const pages = getCurrentPages(); const previousPage = pages.length >= 2 ? pages[pages.length - 2] : null; if (previousPage && typeof previousPage.setData === 'function') { previousPage.setData({ - webViewUrl: appendPayResult( - previousPage.data.webViewUrl, - requestId, - status, - ), + webViewUrl: appendPayResult(previousPage.data.webViewUrl, result), }); } } @@ -151,6 +180,7 @@ function createWechatPayPage(pageContext) { async onLoad(query) { const requestId = String(query.requestId || ''); + const orderId = String(query.orderId || ''); const payParams = parsePayParams(query.payParams); if (!requestId || !payParams) { const page = pageContext ?? this; @@ -161,8 +191,8 @@ function createWechatPayPage(pageContext) { return; } - const status = await requestWechatPayment(payParams); - notifyPreviousWebView(requestId, status); + const payResult = await requestWechatPayment(payParams); + notifyPreviousWebView(requestId, orderId, payResult); wx.navigateBack(); }, @@ -176,7 +206,9 @@ module.exports = { canUseVirtualPayment, PAY_RESULT_STORAGE_KEY, appendPayResult, + buildPayResultValue, createWechatPayPage, + normalizePayError, parsePayParams, safeCompareVersion, requestWechatPayment, diff --git a/miniprogram/pages/wechat-pay/index.test.js b/miniprogram/pages/wechat-pay/index.test.js index f4096260..e4520aa5 100644 --- a/miniprogram/pages/wechat-pay/index.test.js +++ b/miniprogram/pages/wechat-pay/index.test.js @@ -14,6 +14,7 @@ describe('wechat-pay mini program payment bridge', () => { globalThis.wx = { requestPayment: vi.fn(), requestVirtualPayment: vi.fn(), + getSystemInfoSync: vi.fn(() => ({ SDKVersion: '2.32.0' })), setStorageSync: vi.fn(), navigateBack: vi.fn(), }; @@ -32,9 +33,9 @@ describe('wechat-pay mini program payment bridge', () => { signature: 'user-sig', }; - const status = await requestWechatPayment(payParams); + const result = await requestWechatPayment(payParams); - expect(status).toBe('success'); + expect(result).toEqual({ status: 'success', errorMessage: '' }); expect(globalThis.wx.requestVirtualPayment).toHaveBeenCalledWith({ mode: 'short_series_coin', signData: payParams.signData, @@ -58,9 +59,9 @@ describe('wechat-pay mini program payment bridge', () => { signature: 'user-sig', }; - const status = await requestWechatPayment(payParams); + const result = await requestWechatPayment(payParams); - expect(status).toBe('success'); + expect(result).toEqual({ status: 'success', errorMessage: '' }); expect(globalThis.wx.requestVirtualPayment).toHaveBeenCalledWith({ mode: 'short_series_goods', signData: payParams.signData, @@ -77,7 +78,7 @@ describe('wechat-pay mini program payment bridge', () => { options.success?.(); }); - const status = await requestWechatPayment({ + const result = await requestWechatPayment({ timeStamp: '1777110165', nonceStr: 'nonce', package: 'prepay_id=wx-prepay', @@ -85,7 +86,7 @@ describe('wechat-pay mini program payment bridge', () => { paySign: 'signature', }); - expect(status).toBe('success'); + expect(result).toEqual({ status: 'success', errorMessage: '' }); expect(globalThis.wx.requestPayment).toHaveBeenCalledWith({ timeStamp: '1777110165', nonceStr: 'nonce', @@ -110,7 +111,13 @@ describe('wechat-pay mini program payment bridge', () => { paySig: 'pay-sig', signature: 'user-sig', }), - ).resolves.toBe('cancel'); + ).resolves.toEqual({ + status: 'cancel', + errorMessage: JSON.stringify({ + errCode: -2, + errMsg: 'requestVirtualPayment:fail cancel', + }), + }); }); test('page notifies previous web-view after virtual payment', async () => { @@ -118,7 +125,7 @@ describe('wechat-pay mini program payment bridge', () => { data: { webViewUrl: 'https://web.test/#tab=profile' }, setData: vi.fn(), }; - globalThis.getCurrentPages = vi.fn(() => [{}, previousPage]); + globalThis.getCurrentPages = vi.fn(() => [previousPage, {}]); globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => { options.success?.({ errMsg: 'requestVirtualPayment:ok' }); }); @@ -128,6 +135,7 @@ describe('wechat-pay mini program payment bridge', () => { await page.onLoad({ requestId: 'request-1', + orderId: 'order-1', payParams: encodeURIComponent( JSON.stringify({ mode: 'short_series_coin', @@ -140,10 +148,10 @@ describe('wechat-pay mini program payment bridge', () => { expect(globalThis.wx.setStorageSync).toHaveBeenCalledWith( 'genarrative:wechat-pay-result', - 'request-1:success', + 'request-1:success:order-1', ); expect(previousPage.setData).toHaveBeenCalledWith({ - webViewUrl: 'https://web.test/#tab=profile&wx_pay_result=request-1%3Asuccess', + webViewUrl: 'https://web.test/#tab=profile&wx_pay_result=request-1%3Asuccess%3Aorder-1', }); expect(globalThis.wx.navigateBack).toHaveBeenCalled(); }); @@ -152,8 +160,8 @@ describe('wechat-pay mini program payment bridge', () => { expect(parsePayParams(encodeURIComponent('{"paySign":"sig"}'))).toEqual({ paySign: 'sig', }); - expect(appendPayResult('https://web.test/#old=1', 'req', 'fail')).toBe( - 'https://web.test/#old=1&wx_pay_result=req%3Afail', + expect(appendPayResult('https://web.test/#old=1', 'req:fail:order-1')).toBe( + 'https://web.test/#old=1&wx_pay_result=req%3Afail%3Aorder-1', ); }); }); diff --git a/scripts/miniprogram-web-view-auth.test.ts b/scripts/miniprogram-web-view-auth.test.ts index 108d2a5f..388677e0 100644 --- a/scripts/miniprogram-web-view-auth.test.ts +++ b/scripts/miniprogram-web-view-auth.test.ts @@ -17,6 +17,8 @@ type MiniProgramPage = { data: Record; setData: (patch: Record) => void; onLoad: (query?: Record) => Promise; + onShow: () => void; + consumePayResult: () => void; }; function createWxMock() { @@ -44,6 +46,10 @@ function loadWebViewPage( Page(config: Record) { pageConfig = config; }, + setTimeout(callback: () => void) { + callback(); + return 1; + }, require(requestPath: string) { if (requestPath === '../../config') { return { @@ -85,22 +91,40 @@ describe('mini-program web-view auth page', () => { vi.clearAllMocks(); }); - test('默认进入时直接打开 web-view,不触发微信登录请求', async () => { + test('默认进入时刷新微信小程序登录态后打开 web-view', async () => { const wxMock = createWxMock(); + wxMock.login.mockImplementation(({ success }) => { + success({ code: 'wx-login-code' }); + }); + wxMock.request.mockImplementation(({ success }) => { + success({ + statusCode: 200, + data: { + token: 'jwt-active-wechat', + bindingStatus: 'active', + }, + }); + }); const page = loadWebViewPage(wxMock); await page.onLoad({}); - expect(wxMock.login).not.toHaveBeenCalled(); - expect(wxMock.request).not.toHaveBeenCalled(); + expect(wxMock.login).toHaveBeenCalledTimes(1); + expect(wxMock.request).toHaveBeenCalledWith( + expect.objectContaining({ + url: 'https://www.genarrative.world/api/auth/wechat/miniprogram-login', + method: 'POST', + data: { code: 'wx-login-code' }, + }), + ); expect(page.data.loading).toBe(false); expect(page.data.phoneBindingRequired).toBe(false); expect(page.data.webViewUrl).toBe( - 'https://www.genarrative.world/?clientType=mini_program&clientRuntime=wechat_mini_program', + 'https://www.genarrative.world/?clientType=mini_program&clientRuntime=wechat_mini_program#auth_provider=wechat&auth_token=jwt-active-wechat&auth_binding_status=active', ); }); - test('默认匿名进入 web-view 不依赖 API_BASE_URL 配置', async () => { + test('默认匿名进入 web-view 仍不依赖 API_BASE_URL 配置', async () => { const wxMock = createWxMock(); const page = loadWebViewPage(wxMock, { API_BASE_URL: '', @@ -116,6 +140,27 @@ describe('mini-program web-view auth page', () => { ); }); + test('onShow 二次检查支付结果并写回 web-view hash', () => { + const wxMock = createWxMock(); + wxMock.getStorageSync.mockImplementation((key) => + key === 'genarrative:wechat-pay-result' + ? 'request-1:success:order-1' + : '', + ); + const page = loadWebViewPage(wxMock); + page.data.webViewUrl = + 'https://www.genarrative.world/?clientType=mini_program#tab=profile'; + + page.onShow(); + + expect(wxMock.removeStorageSync).toHaveBeenCalledWith( + 'genarrative:wechat-pay-result', + ); + expect(page.data.webViewUrl).toBe( + 'https://www.genarrative.world/?clientType=mini_program#tab=profile&wx_pay_result=request-1%3Asuccess%3Aorder-1', + ); + }); + test('H5 请求登录时才启动微信小程序登录并进入手机号授权态', async () => { const wxMock = createWxMock(); wxMock.login.mockImplementation(({ success }) => { diff --git a/server-rs/crates/api-server/src/runtime_profile.rs b/server-rs/crates/api-server/src/runtime_profile.rs index d604bc18..effe4f8d 100644 --- a/server-rs/crates/api-server/src/runtime_profile.rs +++ b/server-rs/crates/api-server/src/runtime_profile.rs @@ -4,6 +4,7 @@ use axum::{ http::{HeaderMap, StatusCode}, response::Response, }; +use hmac::{Hmac, Mac}; use module_runtime::{ AnalyticsGranularity, PROFILE_RECHARGE_PAYMENT_CHANNEL_MOCK, PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_H5, @@ -24,7 +25,6 @@ use module_runtime::{ }; use serde::Deserialize; use serde_json::{Value, json}; -use hmac::{Hmac, Mac}; use sha2::Sha256; use shared_contracts::runtime::{ ANALYTICS_GRANULARITY_DAY, ANALYTICS_GRANULARITY_MONTH, ANALYTICS_GRANULARITY_QUARTER, @@ -1187,10 +1187,6 @@ fn build_wechat_virtual_pay_params( AppError::from_status(StatusCode::BAD_REQUEST) .with_message("当前微信登录态缺少 session_key,请重新登录后再试") })?; - let product = module_runtime::runtime_profile_recharge_product_by_id(&order.product_id) - .ok_or_else(|| { - AppError::from_status(StatusCode::BAD_REQUEST).with_message("充值商品不存在") - })?; let offer_id = required_wechat_virtual_payment_config( state .config @@ -1198,7 +1194,7 @@ fn build_wechat_virtual_pay_params( .as_deref(), "微信虚拟支付 OfferId 未配置", )?; - let mode = match product.kind { + let mode = match order.kind { RuntimeProfileRechargeProductKind::Points => "short_series_coin", RuntimeProfileRechargeProductKind::Membership => "short_series_goods", }; @@ -1215,9 +1211,9 @@ fn build_wechat_virtual_pay_params( "openId": openid, }).to_string(), }); - if product.kind == RuntimeProfileRechargeProductKind::Membership { - sign_data["productId"] = json!(product.product_id); - sign_data["goodsPrice"] = json!(product.price_cents); + if order.kind == RuntimeProfileRechargeProductKind::Membership { + sign_data["productId"] = json!(order.product_id); + sign_data["goodsPrice"] = json!(order.amount_cents); } let sign_data = sign_data.to_string(); let pay_sig = calc_wechat_virtual_payment_signature(state, &sign_data, false)?; @@ -1242,7 +1238,10 @@ fn calc_wechat_virtual_payment_signature( .config .wechat_mini_program_virtual_payment_sandbox_app_key .as_deref() - .or(state.config.wechat_mini_program_virtual_payment_app_key.as_deref()) + .or(state + .config + .wechat_mini_program_virtual_payment_app_key + .as_deref()) } else { state .config @@ -1250,8 +1249,7 @@ fn calc_wechat_virtual_payment_signature( .as_deref() } .ok_or_else(|| { - AppError::from_status(StatusCode::BAD_REQUEST) - .with_message("微信虚拟支付 AppKey 未配置") + AppError::from_status(StatusCode::BAD_REQUEST).with_message("微信虚拟支付 AppKey 未配置") })?; calc_wechat_virtual_payment_signature_with_key(app_key, sign_data) } @@ -2294,6 +2292,59 @@ mod tests { assert!(!params.signature.is_empty()); } + #[tokio::test] + async fn wechat_virtual_pay_params_accept_admin_membership_product_ids() { + let state = seed_authenticated_state_with_config(AppConfig { + wechat_mini_program_virtual_payment_offer_id: Some("offer-1".to_string()), + wechat_mini_program_virtual_payment_app_key: Some("app-key-1".to_string()), + wechat_mini_program_virtual_payment_env: 0, + ..fast_spacetime_timeout_config() + }) + .await; + let wechat_login = state + .wechat_auth_service() + .resolve_login(ResolveWechatLoginInput { + profile: WechatIdentityProfile { + provider_uid: "openid-user-item01".to_string(), + provider_union_id: Some("union-user-item01".to_string()), + display_name: Some("资料页用户".to_string()), + avatar_url: None, + session_key: Some("session-key-item01".to_string()), + }, + }) + .await + .expect("wechat identity should seed"); + let order = RuntimeProfileRechargeOrderRecord { + order_id: "item01order01".to_string(), + user_id: wechat_login.user.id, + product_id: "item01".to_string(), + product_title: "测试道具".to_string(), + kind: RuntimeProfileRechargeProductKind::Membership, + amount_cents: 100, + status: RuntimeProfileRechargeOrderStatus::Pending, + payment_channel: PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL + .to_string(), + paid_at: None, + paid_at_micros: None, + provider_transaction_id: None, + created_at: "2026-05-27T10:00:00Z".to_string(), + created_at_micros: 1_779_842_400_000_000, + points_delta: 0, + membership_expires_at: None, + membership_expires_at_micros: None, + }; + + let params = build_wechat_virtual_pay_params(&state, &order, "openid-user-item01") + .expect("custom membership virtual pay params should build"); + let sign_data: Value = + serde_json::from_str(¶ms.sign_data).expect("sign data should be valid json"); + + assert_eq!(params.mode, "short_series_goods"); + assert_eq!(sign_data["productId"], "item01"); + assert_eq!(sign_data["goodsPrice"], 100); + assert_eq!(sign_data["outTradeNo"], "item01order01"); + } + #[tokio::test] async fn profile_feedback_requires_authentication() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); diff --git a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx index 48a1278c..301342ea 100644 --- a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx +++ b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx @@ -2081,7 +2081,7 @@ function pickDraftCompletionDialogSourceId( function buildDraftCompletionDialogSource( kind: CreationWorkShelfKind, ids: Array, -) { +): string { const sourceId = pickDraftCompletionDialogSourceId(ids); switch (kind) { case 'rpg': @@ -2103,6 +2103,7 @@ function buildDraftCompletionDialogSource( case 'baby-object-match': return formatPlatformTaskCompletionSource('宝贝识物草稿', sourceId); } + return formatPlatformTaskCompletionSource('创作草稿', sourceId); } function createMiniGameDraftGenerationStateForRestoredDraft( diff --git a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx index 4c226935..4fbd15a3 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx @@ -1417,8 +1417,9 @@ test('profile recharge modal posts virtual payment params in mini program web-vi 'requestId', ); expect(requestId).toBeTruthy(); + expect(screen.getByRole('dialog', { name: '正在支付' })).toBeTruthy(); act(() => { - window.location.hash = `wx_pay_result=${requestId}:success`; + window.location.hash = `wx_pay_result=${requestId}:success:order-wechat-1`; window.dispatchEvent(new HashChangeEvent('hashchange')); }); expect(navigateUrl).toContain('order-wechat-1'); @@ -1512,6 +1513,87 @@ test('profile recharge modal posts membership goods virtual payment params in mi expect(decodeURIComponent(navigateUrl)).toContain('"paySig":"pay-sig"'); }); +test('profile recharge modal releases submitting state and shows virtual payment failure detail', async () => { + const user = userEvent.setup(); + window.history.replaceState(null, '', '/?clientRuntime=wechat_mini_program'); + const navigateTo = vi.fn((options: { url: string; success?: () => void }) => { + options.success?.(); + }); + window.wx = { + miniProgram: { + navigateTo, + }, + }; + mockCreateRpgProfileRechargeOrder.mockResolvedValueOnce({ + order: { + orderId: 'order-wechat-sandbox-fail', + productId: 'points_60', + productTitle: '60泥点', + kind: 'points', + amountCents: 600, + status: 'pending' as const, + paymentChannel: 'wechat_mp_virtual', + paidAt: null as string | null, + providerTransactionId: null, + createdAt: '2026-04-25T10:00:00Z', + pointsDelta: 0, + membershipExpiresAt: null, + }, + center: { + walletBalance: 0, + membership: { + status: 'normal', + tier: 'normal', + startedAt: null, + expiresAt: null, + updatedAt: null, + }, + pointProducts: [], + membershipProducts: [], + benefits: [], + latestOrder: null, + hasPointsRecharged: false, + }, + wechatMiniProgramPayParams: { + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":1,"currencyType":"CNY","outTradeNo":"order-wechat-sandbox-fail","attach":"mud_points_60"}', + paySig: 'sandbox-pay-sig', + signature: 'user-sig', + }, + }); + + renderProfileView(); + await openRechargeModal(user); + const buyButton = await screen.findByRole('button', { name: /60泥点/u }); + await user.click(buyButton); + + const navigateUrl = navigateTo.mock.calls[0]?.[0].url ?? ''; + const requestId = new URL(`https://mini.test${navigateUrl}`).searchParams.get( + 'requestId', + ); + expect(requestId).toBeTruthy(); + act(() => { + window.location.hash = `wx_pay_result=${requestId}:fail:order-wechat-sandbox-fail:${encodeURIComponent('{"errCode":-1,"errMsg":"requestVirtualPayment:fail sandbox"}')}`; + window.dispatchEvent(new HashChangeEvent('hashchange')); + }); + + expect( + await screen.findByRole('dialog', { name: '支付未完成' }), + ).toBeTruthy(); + expect( + screen.getByText(/requestVirtualPayment:fail sandbox/u), + ).toBeTruthy(); + await waitFor(() => { + expect( + within(screen.getByRole('button', { name: /60泥点/u })).getByText( + '购买', + { selector: 'span' }, + ), + ).toBeTruthy(); + }); +}); + test('profile recharge modal waits for paid confirmation before refreshing dashboard', async () => { const user = userEvent.setup(); const onRechargeSuccess = vi.fn(); diff --git a/src/components/rpg-entry/RpgEntryHomeView.tsx b/src/components/rpg-entry/RpgEntryHomeView.tsx index ba2b26f9..8bb452ad 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.tsx @@ -329,6 +329,7 @@ type WechatPayResult = { requestId: string; orderId: string | null; status: WechatMiniProgramPaymentStatus; + errorMessage: string | null; }; type RechargePaymentResultKind = 'success' | 'pending' | 'cancel' | 'failed'; type RechargePaymentResult = { @@ -2681,22 +2682,34 @@ function readWechatPayResultFromHash(): WechatPayResult | null { return null; } - const [requestId = '', rawStatus = ''] = result.split(':'); - const orderId = requestId + const [requestId = '', rawStatus = '', explicitOrderId = '', ...rawErrors] = + result.split(':'); + const inferredOrderId = requestId .replace(/^wechat_pay_/, '') .replace(/_\d+$/, '') .trim(); + const orderId = explicitOrderId.trim() || inferredOrderId; const status = rawStatus === 'success' ? 'success' : rawStatus === 'cancel' ? 'cancel' : 'fail'; + let errorMessage: string | null = null; + const rawError = rawErrors.join(':'); + if (rawError) { + try { + errorMessage = decodeURIComponent(rawError); + } catch (_error) { + errorMessage = rawError; + } + } return { requestId, orderId: orderId || null, status, + errorMessage, }; } @@ -4586,6 +4599,7 @@ export function RpgEntryHomeView({ return; } + setSubmittingRechargeProductId(null); if (payResult.status === 'success') { setRechargePaymentResult({ kind: 'pending', @@ -4635,10 +4649,13 @@ export function RpgEntryHomeView({ }); refreshRechargeState(); } else { + const detail = payResult.errorMessage + ? `微信返回:${payResult.errorMessage}` + : '微信支付没有完成,本次不会入账。'; setRechargePaymentResult({ kind: 'failed', title: '支付未完成', - message: '微信支付没有完成,本次不会入账。', + message: detail, }); refreshRechargeState(); } @@ -4679,11 +4696,16 @@ export function RpgEntryHomeView({ .then(async (response) => { if (paymentChannel === WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL) { pendingWechatRechargeOrderIdRef.current = response.order.orderId; + setRechargeCenter(response.center); + setRechargePaymentResult({ + kind: 'pending', + title: '正在支付', + message: '请在微信小程序支付页完成支付,返回后会自动刷新状态。', + }); await requestWechatMiniProgramPayment( response.wechatMiniProgramPayParams, response.order.orderId, ); - setRechargeCenter(response.center); return; } if (paymentChannel === WECHAT_H5_PAYMENT_CHANNEL) { diff --git a/vitest.config.ts b/vitest.config.ts index 9a44f493..87ae74b8 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -9,6 +9,7 @@ export default defineConfig({ 'src/**/*.test.tsx', 'apps/admin-web/src/**/*.test.ts', 'apps/admin-web/src/**/*.test.tsx', + 'miniprogram/**/*.test.js', 'scripts/**/*.test.ts', 'packages/shared/src/**/*.test.ts', ], From 40ef89aeb59a59186acaa34ac87d56ee0f7375c8 Mon Sep 17 00:00:00 2001 From: kdletters Date: Fri, 29 May 2026 21:02:54 +0000 Subject: [PATCH 03/31] chore: upgrade spacetimedb and stabilize dev startup --- .hermes/shared-memory/project-overview.md | 4 +- apps/admin-web/vite.config.ts | 11 ++++ deploy/container/README.md | 2 +- deploy/container/docker-compose.loadtest.yml | 2 +- ...】server-rs与SpacetimeDB数据契约-2026-05-15.md | 2 + ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 +- scripts/dev.test.ts | 8 +-- server-rs/Cargo.lock | 64 +++++++++---------- server-rs/Cargo.toml | 6 +- .../spacetime-client/src/module_bindings.rs | 14 ++-- .../module_bindings/accept_quest_reducer.rs | 16 ++--- .../acknowledge_quest_completion_reducer.rs | 16 ++--- ...n_disable_profile_redeem_code_procedure.rs | 16 ++--- ...n_disable_profile_task_config_procedure.rs | 16 ++--- ...min_list_profile_invite_codes_procedure.rs | 16 ++--- ...ist_profile_recharge_products_procedure.rs | 16 ++--- ...min_list_profile_redeem_codes_procedure.rs | 16 ++--- ...min_list_profile_task_configs_procedure.rs | 16 ++--- .../admin_list_work_visibility_procedure.rs | 16 ++--- .../admin_update_work_visibility_procedure.rs | 16 ++--- ...in_upsert_profile_invite_code_procedure.rs | 16 ++--- ...sert_profile_recharge_product_procedure.rs | 16 ++--- ...in_upsert_profile_redeem_code_procedure.rs | 16 ++--- ...in_upsert_profile_task_config_procedure.rs | 16 ++--- .../advance_puzzle_next_level_procedure.rs | 16 ++--- ...pend_ai_text_chunk_and_return_procedure.rs | 16 ++--- ...l_novel_runtime_history_entry_procedure.rs | 16 ++--- ...ssion_ledger_entry_and_return_procedure.rs | 16 ++--- ...hapter_progression_ledger_entry_reducer.rs | 16 ++--- .../apply_inventory_mutation_reducer.rs | 16 ++--- .../apply_quest_signal_reducer.rs | 16 ++--- ...i_result_reference_and_return_procedure.rs | 16 ++--- ...e_database_migration_operator_procedure.rs | 16 ++--- ...egin_story_session_and_return_procedure.rs | 16 ++--- .../begin_story_session_reducer.rs | 16 ++--- ...t_object_to_entity_and_return_procedure.rs | 16 ++--- .../bind_asset_object_to_entity_reducer.rs | 16 ++--- .../cancel_ai_task_and_return_procedure.rs | 16 ++--- .../checkpoint_wooden_fish_run_procedure.rs | 16 ++--- ...rofile_task_reward_and_return_procedure.rs | 16 ++--- ...m_puzzle_work_point_incentive_procedure.rs | 16 ++--- ...abase_migration_import_chunks_procedure.rs | 16 ++--- ...orm_browse_history_and_return_procedure.rs | 16 ++--- .../click_match_3_d_item_procedure.rs | 16 ++--- .../compile_big_fish_draft_procedure.rs | 16 ++--- ...ustom_world_published_profile_procedure.rs | 16 ++--- .../compile_jump_hop_draft_procedure.rs | 16 ++--- .../compile_match_3_d_draft_procedure.rs | 16 ++--- .../compile_puzzle_agent_draft_procedure.rs | 16 ++--- .../compile_square_hole_draft_procedure.rs | 16 ++--- ...ile_visual_novel_work_profile_procedure.rs | 16 ++--- .../compile_wooden_fish_draft_procedure.rs | 16 ++--- .../complete_ai_stage_and_return_procedure.rs | 16 ++--- .../complete_ai_task_and_return_procedure.rs | 16 ++--- ...nfirm_asset_object_and_return_procedure.rs | 16 ++--- .../confirm_asset_object_reducer.rs | 16 ++--- ...file_wallet_points_and_return_procedure.rs | 16 ++--- .../continue_story_and_return_procedure.rs | 16 ++--- .../module_bindings/continue_story_reducer.rs | 16 ++--- .../create_ai_task_and_return_procedure.rs | 16 ++--- .../module_bindings/create_ai_task_reducer.rs | 16 ++--- .../create_bark_battle_draft_procedure.rs | 16 ++--- ...reate_battle_state_and_return_procedure.rs | 16 ++--- .../create_battle_state_reducer.rs | 16 ++--- .../create_big_fish_session_procedure.rs | 16 ++--- ...te_custom_world_agent_session_procedure.rs | 16 ++--- ...create_jump_hop_agent_session_procedure.rs | 16 ++--- ...reate_match_3_d_agent_session_procedure.rs | 16 ++--- ...ile_recharge_order_and_return_procedure.rs | 16 ++--- .../create_puzzle_agent_session_procedure.rs | 16 ++--- ...ate_square_hole_agent_session_procedure.rs | 16 ++--- ...te_visual_novel_agent_session_procedure.rs | 16 ++--- ...ate_wooden_fish_agent_session_procedure.rs | 16 ++--- .../delete_big_fish_work_procedure.rs | 16 ++--- ...te_custom_world_agent_session_procedure.rs | 16 ++--- ...stom_world_profile_and_return_procedure.rs | 16 ++--- .../delete_match_3_d_work_procedure.rs | 16 ++--- .../delete_puzzle_work_procedure.rs | 16 ++--- ...e_runtime_snapshot_and_return_procedure.rs | 16 ++--- .../delete_square_hole_work_procedure.rs | 16 ++--- .../delete_visual_novel_work_procedure.rs | 16 ++--- .../drag_puzzle_piece_or_group_procedure.rs | 16 ++--- .../drop_square_hole_shape_procedure.rs | 16 ++--- ...alytics_date_dimension_for_date_reducer.rs | 16 ++--- ...ute_custom_world_agent_action_procedure.rs | 16 ++--- ...th_store_snapshot_from_tables_procedure.rs | 16 ++--- ...rt_database_migration_to_file_procedure.rs | 16 ++--- .../fail_ai_task_and_return_procedure.rs | 16 ++--- ...e_big_fish_agent_message_turn_procedure.rs | 16 ++--- ...stom_world_agent_message_turn_procedure.rs | 16 ++--- ..._match_3_d_agent_message_turn_procedure.rs | 16 ++--- ...ize_puzzle_agent_message_turn_procedure.rs | 16 ++--- ...quare_hole_agent_message_turn_procedure.rs | 16 ++--- ...sual_novel_agent_message_turn_procedure.rs | 16 ++--- .../finish_bark_battle_run_procedure.rs | 16 ++--- .../finish_match_3_d_time_up_procedure.rs | 16 ++--- .../finish_square_hole_time_up_procedure.rs | 16 ++--- .../finish_wooden_fish_run_procedure.rs | 16 ++--- .../generate_big_fish_asset_procedure.rs | 16 ++--- .../get_bark_battle_run_procedure.rs | 16 ++--- ...et_bark_battle_runtime_config_procedure.rs | 16 ++--- .../get_battle_state_procedure.rs | 16 ++--- .../get_big_fish_run_procedure.rs | 16 ++--- .../get_big_fish_session_procedure.rs | 16 ++--- .../get_chapter_progression_procedure.rs | 16 ++--- .../get_creation_entry_config_procedure.rs | 16 ++--- ...ustom_world_agent_card_detail_procedure.rs | 16 ++--- ..._custom_world_agent_operation_procedure.rs | 16 ++--- ...et_custom_world_agent_session_procedure.rs | 16 ++--- ..._world_gallery_detail_by_code_procedure.rs | 16 ++--- ...t_custom_world_gallery_detail_procedure.rs | 16 ++--- ...t_custom_world_library_detail_procedure.rs | 16 ++--- .../get_jump_hop_agent_session_procedure.rs | 16 ++--- .../get_jump_hop_run_procedure.rs | 16 ++--- .../get_jump_hop_work_profile_procedure.rs | 16 ++--- .../get_match_3_d_agent_session_procedure.rs | 16 ++--- .../get_match_3_d_run_procedure.rs | 16 ++--- .../get_match_3_d_work_detail_procedure.rs | 16 ++--- ...player_progression_or_default_procedure.rs | 16 ++--- .../get_profile_dashboard_procedure.rs | 16 ++--- .../get_profile_play_stats_procedure.rs | 16 ++--- .../get_profile_recharge_center_procedure.rs | 16 ++--- ...ile_recharge_order_and_return_procedure.rs | 16 ++--- ...rofile_referral_invite_center_procedure.rs | 16 ++--- .../get_profile_task_center_procedure.rs | 16 ++--- .../get_puzzle_agent_session_procedure.rs | 16 ++--- .../get_puzzle_gallery_detail_procedure.rs | 16 ++--- .../get_puzzle_run_procedure.rs | 16 ++--- .../get_puzzle_work_detail_procedure.rs | 16 ++--- .../get_runtime_inventory_state_procedure.rs | 16 ++--- ...et_runtime_setting_or_default_procedure.rs | 16 ++--- .../get_runtime_snapshot_procedure.rs | 16 ++--- ...get_square_hole_agent_session_procedure.rs | 16 ++--- .../get_square_hole_run_procedure.rs | 16 ++--- .../get_square_hole_work_detail_procedure.rs | 16 ++--- .../get_story_session_state_procedure.rs | 16 ++--- ...et_visual_novel_agent_session_procedure.rs | 16 ++--- .../get_visual_novel_run_procedure.rs | 16 ++--- .../get_visual_novel_work_detail_procedure.rs | 16 ++--- ...get_wooden_fish_agent_session_procedure.rs | 16 ++--- .../get_wooden_fish_run_procedure.rs | 16 ++--- .../get_wooden_fish_work_profile_procedure.rs | 16 ++--- ...er_registration_wallet_reward_procedure.rs | 16 ++--- ...ression_experience_and_return_procedure.rs | 16 ++--- ...t_player_progression_experience_reducer.rs | 16 ++--- ...port_auth_store_snapshot_json_procedure.rs | 16 ++--- ...atabase_migration_from_chunks_procedure.rs | 16 ++--- ..._database_migration_from_file_procedure.rs | 16 ++--- ...ation_incremental_from_chunks_procedure.rs | 16 ++--- ...gration_incremental_from_file_procedure.rs | 16 ++--- .../jump_hop_jump_procedure.rs | 16 ++--- ...list_asset_history_and_return_procedure.rs | 16 ++--- .../list_big_fish_works_procedure.rs | 16 ++--- ..._custom_world_gallery_entries_procedure.rs | 16 ++--- .../list_custom_world_profiles_procedure.rs | 16 ++--- .../list_custom_world_works_procedure.rs | 16 ++--- .../list_jump_hop_works_procedure.rs | 16 ++--- .../list_match_3_d_works_procedure.rs | 16 ++--- .../list_platform_browse_history_procedure.rs | 16 ++--- .../list_profile_save_archives_procedure.rs | 16 ++--- .../list_profile_wallet_ledger_procedure.rs | 16 ++--- .../list_puzzle_gallery_procedure.rs | 16 ++--- .../list_puzzle_works_procedure.rs | 16 ++--- .../list_square_hole_works_procedure.rs | 16 ++--- ..._visual_novel_runtime_history_procedure.rs | 16 ++--- .../list_visual_novel_works_procedure.rs | 16 ++--- .../list_wooden_fish_works_procedure.rs | 16 ++--- ...echarge_order_paid_and_return_procedure.rs | 16 ++--- ...uzzle_draft_generation_failed_procedure.rs | 16 ++--- .../public_work_play_daily_stat_table.rs | 2 +- .../publish_bark_battle_work_procedure.rs | 16 ++--- .../publish_big_fish_game_procedure.rs | 16 ++--- ...stom_world_profile_and_return_procedure.rs | 16 ++--- .../publish_custom_world_profile_reducer.rs | 16 ++--- .../publish_custom_world_world_procedure.rs | 16 ++--- .../publish_jump_hop_work_procedure.rs | 16 ++--- .../publish_match_3_d_work_procedure.rs | 16 ++--- .../publish_puzzle_work_procedure.rs | 16 ++--- .../publish_square_hole_work_procedure.rs | 16 ++--- .../publish_visual_novel_work_procedure.rs | 16 ++--- .../publish_wooden_fish_work_procedure.rs | 16 ++--- ...tabase_migration_import_chunk_procedure.rs | 16 ++--- .../query_analytics_metric_procedure.rs | 16 ++--- .../record_big_fish_like_procedure.rs | 16 ++--- .../record_big_fish_play_procedure.rs | 16 ++--- ...ord_custom_world_profile_like_procedure.rs | 16 ++--- ...ord_custom_world_profile_play_procedure.rs | 16 ++--- ...gin_tracking_event_and_return_procedure.rs | 16 ++--- .../record_puzzle_work_like_procedure.rs | 16 ++--- ...ord_tracking_event_and_return_procedure.rs | 16 ++--- ...rd_tracking_events_and_return_procedure.rs | 16 ++--- ...rd_visual_novel_runtime_event_procedure.rs | 16 ++--- ..._profile_referral_invite_code_procedure.rs | 16 ++--- .../redeem_profile_reward_code_procedure.rs | 16 ++--- ...file_wallet_points_and_return_procedure.rs | 16 ++--- .../remix_big_fish_work_procedure.rs | 16 ++--- .../remix_custom_world_profile_procedure.rs | 16 ++--- .../remix_puzzle_work_procedure.rs | 16 ++--- ...olve_combat_action_and_return_procedure.rs | 16 ++--- .../resolve_combat_action_reducer.rs | 16 ++--- ...battle_interaction_and_return_procedure.rs | 16 ++--- ...ve_npc_interaction_and_return_procedure.rs | 16 ++--- .../resolve_npc_interaction_reducer.rs | 16 ++--- ..._npc_social_action_and_return_procedure.rs | 16 ++--- .../resolve_npc_social_action_reducer.rs | 16 ++--- ...easure_interaction_and_return_procedure.rs | 16 ++--- .../resolve_treasure_interaction_reducer.rs | 16 ++--- .../restart_jump_hop_run_procedure.rs | 16 ++--- .../restart_match_3_d_run_procedure.rs | 16 ++--- .../restart_square_hole_run_procedure.rs | 16 ++--- ...ofile_save_archive_and_return_procedure.rs | 16 ++--- ...e_database_migration_operator_procedure.rs | 16 ++--- .../save_puzzle_form_draft_procedure.rs | 16 ++--- .../save_puzzle_generated_images_procedure.rs | 16 ++--- .../save_puzzle_ui_background_procedure.rs | 16 ++--- .../seed_analytics_date_dimensions_reducer.rs | 16 ++--- .../select_puzzle_cover_image_procedure.rs | 16 ++--- .../square_hole_agent_message_table.rs | 2 +- .../square_hole_agent_session_table.rs | 2 +- .../module_bindings/start_ai_task_reducer.rs | 16 ++--- .../start_ai_task_stage_reducer.rs | 16 ++--- .../start_bark_battle_run_procedure.rs | 16 ++--- .../start_big_fish_run_procedure.rs | 16 ++--- .../start_jump_hop_run_procedure.rs | 16 ++--- .../start_match_3_d_run_procedure.rs | 16 ++--- .../start_puzzle_run_procedure.rs | 16 ++--- .../start_square_hole_run_procedure.rs | 16 ++--- .../start_visual_novel_run_procedure.rs | 16 ++--- .../start_wooden_fish_run_procedure.rs | 16 ++--- .../stop_match_3_d_run_procedure.rs | 16 ++--- .../stop_square_hole_run_procedure.rs | 16 ++--- .../submit_big_fish_input_procedure.rs | 16 ++--- .../submit_big_fish_message_procedure.rs | 16 ++--- ...it_custom_world_agent_message_procedure.rs | 16 ++--- ...ubmit_match_3_d_agent_message_procedure.rs | 16 ++--- ...t_profile_feedback_and_return_procedure.rs | 16 ++--- .../submit_puzzle_agent_message_procedure.rs | 16 ++--- ...bmit_puzzle_leaderboard_entry_procedure.rs | 16 ++--- ...mit_square_hole_agent_message_procedure.rs | 16 ++--- ...it_visual_novel_agent_message_procedure.rs | 16 ++--- .../swap_puzzle_pieces_procedure.rs | 16 ++--- .../module_bindings/turn_in_quest_reducer.rs | 16 ++--- ...stom_world_profile_and_return_procedure.rs | 16 ++--- .../unpublish_custom_world_profile_reducer.rs | 16 ++--- ...date_bark_battle_draft_config_procedure.rs | 16 ++--- .../update_jump_hop_work_procedure.rs | 16 ++--- .../update_match_3_d_work_procedure.rs | 16 ++--- .../update_puzzle_run_pause_procedure.rs | 16 ++--- .../update_puzzle_work_procedure.rs | 16 ++--- .../update_square_hole_work_procedure.rs | 16 ++--- .../update_visual_novel_work_procedure.rs | 16 ++--- .../update_wooden_fish_work_procedure.rs | 16 ++--- ...hapter_progression_and_return_procedure.rs | 16 ++--- .../upsert_chapter_progression_reducer.rs | 16 ++--- ...rt_creation_entry_type_config_procedure.rs | 16 ++--- ...orld_agent_operation_progress_procedure.rs | 16 ++--- ...stom_world_profile_and_return_procedure.rs | 16 ++--- .../upsert_custom_world_profile_reducer.rs | 16 ++--- .../upsert_npc_state_and_return_procedure.rs | 16 ++--- .../upsert_npc_state_reducer.rs | 16 ++--- ...orm_browse_history_and_return_procedure.rs | 16 ++--- ...rt_runtime_setting_and_return_procedure.rs | 16 ++--- ...t_runtime_snapshot_and_return_procedure.rs | 16 ++--- ...ert_visual_novel_run_snapshot_procedure.rs | 16 ++--- .../use_puzzle_runtime_prop_procedure.rs | 16 ++--- .../visual_novel_gallery_view_table.rs | 2 +- .../visual_novel_work_profile_table.rs | 2 +- .../wooden_fish_agent_session_table.rs | 2 +- vite.config.ts | 3 + 269 files changed, 2038 insertions(+), 2124 deletions(-) diff --git a/.hermes/shared-memory/project-overview.md b/.hermes/shared-memory/project-overview.md index 45ffc1e4..f1503f39 100644 --- a/.hermes/shared-memory/project-overview.md +++ b/.hermes/shared-memory/project-overview.md @@ -1,6 +1,6 @@ # Genarrative 项目共享概览 -更新时间:`2026-05-15` +更新时间:`2026-05-29` ## 一句话定位 @@ -33,6 +33,8 @@ Genarrative / 陶泥儿是一个 AI 原生互动内容与小游戏平台,把 A server-rs + Axum + SpacetimeDB ``` +当前 SpacetimeDB crate、SDK、CLI / standalone、生成 bindings 和容器压测镜像统一按 `2.3.0` 对齐。 + 职责边界: - `api-server`:HTTP / SSE / BFF 门面和外部副作用编排。 diff --git a/apps/admin-web/vite.config.ts b/apps/admin-web/vite.config.ts index 0635b2a1..74f1567b 100644 --- a/apps/admin-web/vite.config.ts +++ b/apps/admin-web/vite.config.ts @@ -16,6 +16,14 @@ export default defineConfig(({mode}) => { env.GENARRATIVE_API_TARGET || `http://127.0.0.1:${env.GENARRATIVE_API_PORT || '3100'}`; const base = env.ADMIN_WEB_BASE || '/admin/'; + const ignoredWatchGlobs = [ + '**/.git/**', + '**/.worktrees/**', + '**/dist/**', + '**/node_modules/**', + '**/server-rs/**', + '**/server-rs/target/**', + ]; return { root: adminWebRoot, @@ -23,6 +31,9 @@ export default defineConfig(({mode}) => { base, plugins: [react()], server: { + watch: { + ignored: ignoredWatchGlobs, + }, proxy: { '/admin/api': { target: apiTarget, diff --git a/deploy/container/README.md b/deploy/container/README.md index b9338457..8aa80fc7 100644 --- a/deploy/container/README.md +++ b/deploy/container/README.md @@ -55,7 +55,7 @@ Linux Docker Engine 若要从宿主机 CLI 连到容器内服务,直接用 `ht ## 构建工具链 -`api-server` 容器镜像只构建 Linux release API 二进制,不构建 `spacetime-module`。当前 `api-server -> spacetime-client -> spacetimedb-sdk 2.2.0` 依赖链要求 Rust 1.93,因此 `deploy/container/api-server.Dockerfile` 的 Rust builder 固定为 `rust:1.93-bookworm`。如果本机 Docker Hub 拉取失败,可以先在本机准备同名本地 builder 镜像,但不要把临时 bootstrap 容器或私有 registry 凭据写入仓库。 +`api-server` 容器镜像只构建 Linux release API 二进制,不构建 `spacetime-module`。当前 `api-server -> spacetime-client -> spacetimedb-sdk 2.3.0` 依赖链要求 Rust 1.93,因此 `deploy/container/api-server.Dockerfile` 的 Rust builder 固定为 `rust:1.93-bookworm`。如果本机 Docker Hub 拉取失败,可以先在本机准备同名本地 builder 镜像,但不要把临时 bootstrap 容器或私有 registry 凭据写入仓库。 ## 启动与验证 diff --git a/deploy/container/docker-compose.loadtest.yml b/deploy/container/docker-compose.loadtest.yml index f21832db..28b1f357 100644 --- a/deploy/container/docker-compose.loadtest.yml +++ b/deploy/container/docker-compose.loadtest.yml @@ -2,7 +2,7 @@ name: genarrative-container-loadtest services: spacetimedb: - image: clockworklabs/spacetime:v2.2.0 + image: clockworklabs/spacetime:v2.3.0 user: root command: [ diff --git a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md index 12609ae9..edf312bd 100644 --- a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md +++ b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md @@ -16,6 +16,8 @@ server-rs + Axum + SpacetimeDB `server-rs/Cargo.toml` 是 workspace 事实源。默认构建成员为 `crates/api-server`;第三方依赖版本和 workspace 内 crate path 统一放在 `[workspace.dependencies]`。 +SpacetimeDB 版本口径:当前 Rust crate `spacetimedb`、`spacetimedb-sdk`、`spacetimedb-lib` 统一锁定 `2.3.0`;本地 `spacetime` CLI / standalone、生成的 `spacetime-client` bindings 和容器压测镜像也必须与 `2.3.0` 对齐,避免 BSATN / procedure result 反序列化错配。 + 当前主要 crate: - HTTP 服务:`api-server`。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index befe256c..c7d2c9a7 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -59,7 +59,7 @@ spacetime sql "SELECT * FROM puzzle_gallery_card_view LIMIT 1" --serv 本地 `npm run dev:spacetime` 发布模块时必须显式忽略仓库根目录的 `spacetime.json`,由脚本固定追加 `--no-config` 并使用命令参数里传入的数据库名和 `--server http://127.0.0.1:3101`。否则 CLI 可能把发布目标改写到配置文件里的其他数据库,导致 `dev:spacetime` 启动后又因发布失败自动退出,浏览器随后会在 `ws://127.0.0.1:3101/v1/database/.../subscribe` 看到连接拒绝。 -本地 `spacetime` CLI / standalone 版本必须和 `server-rs/Cargo.toml` 里锁定的 `spacetimedb` 版本一致。若版本错配,procedure 返回值可能在宿主侧触发 `Failed to BSATN deserialize procedure return value`,api-server 最终表现为敲木鱼等创作动作的 `SpacetimeDB procedure 调用超时`。排障时先运行 `spacetime --version`,再对照 `server-rs/Cargo.toml` 的 `spacetimedb = "..."`;需要切版本时执行 `spacetime version install && spacetime version use `,然后重新启动 `npm run dev:spacetime`。当前 `scripts/dev.mjs` 会在启动和复用本地 SpacetimeDB 前写入并校验 `dev-spacetime-tool-version`,避免把旧 standalone 继续带进新一轮创作。 +本地 `spacetime` CLI / standalone 版本必须和 `server-rs/Cargo.toml` 里锁定的 `spacetimedb` 版本一致;当前统一版本为 `2.3.0`。若版本错配,procedure 返回值可能在宿主侧触发 `Failed to BSATN deserialize procedure return value`,api-server 最终表现为敲木鱼等创作动作的 `SpacetimeDB procedure 调用超时`。排障时先运行 `spacetime --version`,再对照 `server-rs/Cargo.toml` 的 `spacetimedb = "..."`;需要切版本时执行 `spacetime version install && spacetime version use `,然后重新启动 `npm run dev:spacetime`。当前 `scripts/dev.mjs` 会在启动和复用本地 SpacetimeDB 前写入并校验 `dev-spacetime-tool-version`,避免把旧 standalone 继续带进新一轮创作。 本地 `.env`、`.env.local` 或 `.env.secrets.local` 修改后必须重启 `api-server` 才会生效;若已经通过 `npm run dev` 启动完整联调,可在该终端输入 `rs api-server`。排查 RPG / 拼图 / 抓大鹅等 VectorEngine 生图链路时,确认 `VECTOR_ENGINE_BASE_URL`、`VECTOR_ENGINE_API_KEY` 和 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS` 只在本地或服务器密钥文件中配置,不能写入 Git。VectorEngine `gpt-image-2` 图片协议、URL / base64 响应解析、远端图片下载和 provider 侧结构化日志在 `server-rs/crates/platform-image`;`api-server` 只做配置、玩法编排、OSS / asset 持久化、计费和失败审计落库。开局 CG 故事板、首图、背景和图集都属于长耗时图片请求;后端默认会把 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS` 下限收口到 `1000000`,旧进程仍可能沿用重启前的短超时。若开局 CG 故事板在 `send()` 阶段失败且日志显示 `SendRequest`,先看同一 request_id 的 `request_body_bytes`、`reference_data_url_bytes`、`sourceChain` 和 `rootSource`;当前开局 CG 会把角色图与首幕背景图压到单边 768 的 JPEG 后再作为 generations `image` 数组发送,`/v1/images/generations` 使用默认 HTTP 协商,只有 multipart `/v1/images/edits` 单独强制 HTTP/1.1。 diff --git a/scripts/dev.test.ts b/scripts/dev.test.ts index 341cde80..2870d0de 100644 --- a/scripts/dev.test.ts +++ b/scripts/dev.test.ts @@ -252,18 +252,18 @@ describe('dev scheduler watch routing', () => { describe('dev scheduler spacetime refresh', () => { test('解析 spacetime --version 输出里的 tool version', () => { const version = parseSpacetimeToolVersion(` -A new version of SpacetimeDB is available: v2.2.0 (current: v2.1.0) -spacetimedb tool version 2.2.0; spacetimedb-lib version 2.2.0; +A new version of SpacetimeDB is available: v2.3.0 (current: v2.2.0) +spacetimedb tool version 2.3.0; spacetimedb-lib version 2.3.0; `); - expect(version).toBe('2.2.0'); + expect(version).toBe('2.3.0'); }); test('本机 spacetime 版本和 workspace 锁定版本不一致时直接报清楚', () => { expect(() => assertSpacetimeToolVersionMatchesWorkspace({ toolVersion: '2.1.0', - workspaceVersion: '2.2.0', + workspaceVersion: '2.3.0', }), ).toThrow('procedure 返回值 BSATN 反序列化失败'); }); diff --git a/server-rs/Cargo.lock b/server-rs/Cargo.lock index becd7daa..1001bbb3 100644 --- a/server-rs/Cargo.lock +++ b/server-rs/Cargo.lock @@ -1267,7 +1267,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2552,7 +2552,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2 0.5.10", "thiserror 2.0.18", "tokio", "tracing", @@ -2589,7 +2589,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2 0.5.10", "tracing", "windows-sys 0.52.0", ] @@ -3370,9 +3370,9 @@ dependencies = [ [[package]] name = "spacetimedb" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1306cc3a9ed9c89f43b263614a529357cc53a067e3d06c1cbb485e3b577b118b" +checksum = "62aa9a940d32178e4afa7a14c9bbda76685d71d5487798905e0139b807182092" dependencies = [ "anyhow", "bytemuck", @@ -3393,9 +3393,9 @@ dependencies = [ [[package]] name = "spacetimedb-bindings-macro" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51567ec01cd323438a00c134c16f26ffcde5f9dbe6a42a52e54578285bf49d73" +checksum = "5feb5d55f04f3209764d9b94949226708a4a8578e92ac5c32abfd31dbdfc928c" dependencies = [ "heck 0.4.1", "humantime", @@ -3407,18 +3407,18 @@ dependencies = [ [[package]] name = "spacetimedb-bindings-sys" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b40fa1bea26664085febe2b4455568c8b47dea2cb0245406b27e30963df2ba1" +checksum = "28f9c900c9371fd7e84d34b8cb2bf90562060dc2473ae9c44e970d4026e7d7d9" dependencies = [ "spacetimedb-primitives", ] [[package]] name = "spacetimedb-client-api-messages" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc9eeb20a555bad07029cbee4efe3a305cb5c1e40e21a07cbbbbed16a106014" +checksum = "349296ad43e6ecdced74ad8b3fd2c6abbdbb40cdbd06ac329c0726c6b911fa73" dependencies = [ "bytes", "bytestring", @@ -3438,9 +3438,9 @@ dependencies = [ [[package]] name = "spacetimedb-data-structures" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748fd5850a757823c5b8948065d9e4dc5092968a051aa3f34f170e91d95e493b" +checksum = "8b86ed7c567d723378a405317e30413293cc0bc9e2aac2f7843580d744b43c31" dependencies = [ "ahash", "crossbeam-queue", @@ -3453,9 +3453,9 @@ dependencies = [ [[package]] name = "spacetimedb-lib" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5612611d09d358f535438275d2a0d6a5e2fa56fa583dcfdbeddd623974df1d5e" +checksum = "a15a98adf6f030e8188df4b038e140a54771e6eeb50ad05a6c3e46939b8de853" dependencies = [ "anyhow", "bitflags 2.11.1", @@ -3477,9 +3477,9 @@ dependencies = [ [[package]] name = "spacetimedb-memory-usage" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3a0d08fc5d8688a47e3ffcb803275519663b7ea1fba7ad25e608182de4ec6d" +checksum = "c68aa8ed30c15a1d665bf3a8c689955508ce75ca784068ec0232b4cdd511b4c8" dependencies = [ "decorum", "ethnum", @@ -3487,9 +3487,9 @@ dependencies = [ [[package]] name = "spacetimedb-metrics" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2d647201339aa17ba438a07463e96ed64ba214fb0c182588e262b055efa7f3" +checksum = "f8455b0a92dd632757f7e7c22d5e438aa33da5f48d14483e5ee79dfc5468a4db" dependencies = [ "arrayvec", "itertools", @@ -3499,9 +3499,9 @@ dependencies = [ [[package]] name = "spacetimedb-primitives" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b668b51e7318207ae7eebcd4cae0c5d43bf713e7f229ac309ea2614a486ffde" +checksum = "b20cc4bf97377f1dce9e75b2f6ce94bc5c7c2a243040a7a2016ac5cdb002793d" dependencies = [ "bitflags 2.11.1", "either", @@ -3513,18 +3513,18 @@ dependencies = [ [[package]] name = "spacetimedb-query-builder" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0186b1a2b3bf25bdd0f2676b61801fd754013ca6a58e1e24cc5148945388bc9d" +checksum = "afa17878dbc23b4bfc06a45165c7afd34c8d29bba6dfde81625840c11380abce" dependencies = [ "spacetimedb-lib", ] [[package]] name = "spacetimedb-sats" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11780ed69f178bf3784b7599da5171450e4b7ac6fd66b79e2e1861c867cef1a6" +checksum = "74216db354eab5cefad9572a350654761495968478e83e51ef2c530cdf6cb1d4" dependencies = [ "anyhow", "arrayvec", @@ -3555,9 +3555,9 @@ dependencies = [ [[package]] name = "spacetimedb-schema" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4e9f8aa596e0e7034f0c8b3649d3fa3cc7bde340761519c3a3c60f10ec8888" +checksum = "ff3ff36f901f6875907ff1df2b610fc396937b88f6793dfa04b0d9f298d74946" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -3586,9 +3586,9 @@ dependencies = [ [[package]] name = "spacetimedb-sdk" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e82f20034b8aaeaa081871b07895aab45be1f0fc35e114ab64ae8e7e5c1a54" +checksum = "26897e31aa58acd6cd0bcf12cf56a4ecd0cb4fc48053478626729e868f042e54" dependencies = [ "anymap3", "base64 0.21.7", @@ -3618,9 +3618,9 @@ dependencies = [ [[package]] name = "spacetimedb-sql-parser" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5c77a2d4e3f42ede59598c56cb81a0fe54fd1974e2707f7140d1d5f41d08a7" +checksum = "19428d4ddc8cf1eb34e58715ed512820ee9a3de187a89f88f80e18e914a086ae" dependencies = [ "derive_more", "spacetimedb-lib", @@ -4516,7 +4516,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] diff --git a/server-rs/Cargo.toml b/server-rs/Cargo.toml index 84e0da98..336b63a0 100644 --- a/server-rs/Cargo.toml +++ b/server-rs/Cargo.toml @@ -111,9 +111,9 @@ serde_json = "1" serde_urlencoded = "0.7" sha2 = "0.10" socket2 = "0.6" -spacetimedb = "2.2.0" -spacetimedb-sdk = "2.2.0" -spacetimedb-lib = { version = "2.2.0", default-features = false } +spacetimedb = "2.3.0" +spacetimedb-sdk = "2.3.0" +spacetimedb-lib = { version = "2.3.0", default-features = false } time = "0.3" tokio = "1" tokio-stream = "0.1" diff --git a/server-rs/crates/spacetime-client/src/module_bindings.rs b/server-rs/crates/spacetime-client/src/module_bindings.rs index e153434f..bcd66689 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.2.0 (commit eb11e2f5c41dce6979715ad407996270d61329f6). +// This was generated using spacetimedb cli version 2.3.0 (commit aa73d1c35b4b346b98eeba10a3d756b4ae72162f). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; @@ -4995,19 +4995,19 @@ impl __sdk::SubscriptionHandle for SubscriptionHandle { /// either a [`DbConnection`] or an [`EventContext`] and operate on either. pub trait RemoteDbContext: __sdk::DbContext< - DbView = RemoteTables, - Reducers = RemoteReducers, - SubscriptionBuilder = __sdk::SubscriptionBuilder, - > + DbView = RemoteTables, + Reducers = RemoteReducers, + SubscriptionBuilder = __sdk::SubscriptionBuilder, +> { } impl< - Ctx: __sdk::DbContext< + Ctx: __sdk::DbContext< DbView = RemoteTables, Reducers = RemoteReducers, SubscriptionBuilder = __sdk::SubscriptionBuilder, >, -> RemoteDbContext for Ctx + > RemoteDbContext for Ctx { } diff --git a/server-rs/crates/spacetime-client/src/module_bindings/accept_quest_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/accept_quest_reducer.rs index 61e6b9c5..dfebf903 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/accept_quest_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/accept_quest_reducer.rs @@ -47,11 +47,9 @@ pub trait accept_quest { &self, input: QuestRecordInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl accept_quest for super::RemoteReducers { &self, input: QuestRecordInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(AcceptQuestArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_quest_completion_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_quest_completion_reducer.rs index b1419fb7..6ae2fd10 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_quest_completion_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/acknowledge_quest_completion_reducer.rs @@ -47,11 +47,9 @@ pub trait acknowledge_quest_completion { &self, input: QuestCompletionAckInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl acknowledge_quest_completion for super::RemoteReducers { &self, input: QuestCompletionAckInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(AcknowledgeQuestCompletionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs index 9865ace5..bbdaab4f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_redeem_code_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_disable_profile_redeem_code { input: RuntimeProfileRedeemCodeAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_disable_profile_redeem_code for super::RemoteProcedures { input: RuntimeProfileRedeemCodeAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs index 0417bd2e..c968f950 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_disable_profile_task_config_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_disable_profile_task_config { input: RuntimeProfileTaskConfigAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_disable_profile_task_config for super::RemoteProcedures { input: RuntimeProfileTaskConfigAdminDisableInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs index 96d2350f..cdfa27d9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_invite_codes_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_profile_invite_codes { input: RuntimeProfileInviteCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_profile_invite_codes for super::RemoteProcedures { input: RuntimeProfileInviteCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs index a1deed88..e84d4ec6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_recharge_products_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_list_profile_recharge_products { input: RuntimeProfileRechargeProductAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_list_profile_recharge_products for super::RemoteProcedures { input: RuntimeProfileRechargeProductAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeProductAdminListProcedureResult>( "admin_list_profile_recharge_products", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs index c7d6a78e..2c9b9dd7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_redeem_codes_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_profile_redeem_codes { input: RuntimeProfileRedeemCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_profile_redeem_codes for super::RemoteProcedures { input: RuntimeProfileRedeemCodeAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs index a152116d..88ca28d5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_profile_task_configs_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_profile_task_configs { input: RuntimeProfileTaskConfigAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_profile_task_configs for super::RemoteProcedures { input: RuntimeProfileTaskConfigAdminListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_work_visibility_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_work_visibility_procedure.rs index df222e41..72028b5e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_list_work_visibility_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_list_work_visibility_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_list_work_visibility { input: AdminWorkVisibilityListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_list_work_visibility for super::RemoteProcedures { input: AdminWorkVisibilityListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminWorkVisibilityListProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_update_work_visibility_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_update_work_visibility_procedure.rs index 4a88c084..bbc85a89 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_update_work_visibility_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_update_work_visibility_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_update_work_visibility { input: AdminWorkVisibilityUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_update_work_visibility for super::RemoteProcedures { input: AdminWorkVisibilityUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AdminWorkVisibilityProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs index 2411092d..3601be97 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_invite_code_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_upsert_profile_invite_code { input: RuntimeProfileInviteCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_upsert_profile_invite_code for super::RemoteProcedures { input: RuntimeProfileInviteCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs index 83941b83..e3f42278 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_recharge_product_procedure.rs @@ -34,10 +34,10 @@ pub trait admin_upsert_profile_recharge_product { input: RuntimeProfileRechargeProductAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl admin_upsert_profile_recharge_product for super::RemoteProcedures { input: RuntimeProfileRechargeProductAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeProductAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs index 9c7ae92f..7e918220 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_redeem_code_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_upsert_profile_redeem_code { input: RuntimeProfileRedeemCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_upsert_profile_redeem_code for super::RemoteProcedures { input: RuntimeProfileRedeemCodeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs index b441a808..a3d3e11a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/admin_upsert_profile_task_config_procedure.rs @@ -31,10 +31,10 @@ pub trait admin_upsert_profile_task_config { input: RuntimeProfileTaskConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl admin_upsert_profile_task_config for super::RemoteProcedures { input: RuntimeProfileTaskConfigAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/advance_puzzle_next_level_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/advance_puzzle_next_level_procedure.rs index 7cb4f8f4..6d3e9f79 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/advance_puzzle_next_level_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/advance_puzzle_next_level_procedure.rs @@ -31,10 +31,10 @@ pub trait advance_puzzle_next_level { input: PuzzleRunNextLevelInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl advance_puzzle_next_level for super::RemoteProcedures { input: PuzzleRunNextLevelInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs index 191e2ea7..11323392 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/append_ai_text_chunk_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait append_ai_text_chunk_and_return { input: AiTextChunkAppendInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl append_ai_text_chunk_and_return for super::RemoteProcedures { input: AiTextChunkAppendInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/append_visual_novel_runtime_history_entry_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/append_visual_novel_runtime_history_entry_procedure.rs index ad1099d0..4686ba5c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/append_visual_novel_runtime_history_entry_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/append_visual_novel_runtime_history_entry_procedure.rs @@ -34,10 +34,10 @@ pub trait append_visual_novel_runtime_history_entry { input: VisualNovelRuntimeHistoryAppendInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl append_visual_novel_runtime_history_entry for super::RemoteProcedures { input: VisualNovelRuntimeHistoryAppendInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelHistoryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_and_return_procedure.rs index 4a949906..bba4c841 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait apply_chapter_progression_ledger_entry_and_return { input: ChapterProgressionLedgerInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl apply_chapter_progression_ledger_entry_and_return for super::RemoteProcedur input: ChapterProgressionLedgerInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ChapterProgressionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_reducer.rs index 44596083..98f821ef 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/apply_chapter_progression_ledger_entry_reducer.rs @@ -50,11 +50,9 @@ pub trait apply_chapter_progression_ledger_entry { &self, input: ChapterProgressionLedgerInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl apply_chapter_progression_ledger_entry for super::RemoteReducers { &self, input: ChapterProgressionLedgerInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp.invoke_reducer_with_callback( ApplyChapterProgressionLedgerEntryArgs { input }, diff --git a/server-rs/crates/spacetime-client/src/module_bindings/apply_inventory_mutation_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/apply_inventory_mutation_reducer.rs index d9b4240d..91f7d2c0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/apply_inventory_mutation_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/apply_inventory_mutation_reducer.rs @@ -47,11 +47,9 @@ pub trait apply_inventory_mutation { &self, input: InventoryMutationInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl apply_inventory_mutation for super::RemoteReducers { &self, input: InventoryMutationInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ApplyInventoryMutationArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/apply_quest_signal_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/apply_quest_signal_reducer.rs index 6b4c310b..afb452b5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/apply_quest_signal_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/apply_quest_signal_reducer.rs @@ -47,11 +47,9 @@ pub trait apply_quest_signal { &self, input: QuestSignalApplyInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl apply_quest_signal for super::RemoteReducers { &self, input: QuestSignalApplyInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ApplyQuestSignalArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs index 94d41850..2f3edbe2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/attach_ai_result_reference_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait attach_ai_result_reference_and_return { input: AiResultReferenceInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl attach_ai_result_reference_and_return for super::RemoteProcedures { input: AiResultReferenceInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs index ac77f7e8..b5885022 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/authorize_database_migration_operator_procedure.rs @@ -34,10 +34,10 @@ pub trait authorize_database_migration_operator { input: DatabaseMigrationAuthorizeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl authorize_database_migration_operator for super::RemoteProcedures { input: DatabaseMigrationAuthorizeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationOperatorProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_and_return_procedure.rs index 304b2e0c..eef3de0f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait begin_story_session_and_return { input: StorySessionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl begin_story_session_and_return for super::RemoteProcedures { input: StorySessionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, StorySessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_reducer.rs index 22bc4add..6a082f41 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/begin_story_session_reducer.rs @@ -47,11 +47,9 @@ pub trait begin_story_session { &self, input: StorySessionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl begin_story_session for super::RemoteReducers { &self, input: StorySessionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(BeginStorySessionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs index 78c80aee..b709d5c2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait bind_asset_object_to_entity_and_return { input: AssetEntityBindingInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl bind_asset_object_to_entity_and_return for super::RemoteProcedures { input: AssetEntityBindingInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetEntityBindingProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs index caf48b26..b20bc5b2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/bind_asset_object_to_entity_reducer.rs @@ -47,11 +47,9 @@ pub trait bind_asset_object_to_entity { &self, input: AssetEntityBindingInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl bind_asset_object_to_entity for super::RemoteReducers { &self, input: AssetEntityBindingInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(BindAssetObjectToEntityArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs index 0c5dc3eb..b239e060 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/cancel_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait cancel_ai_task_and_return { input: AiTaskCancelInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl cancel_ai_task_and_return for super::RemoteProcedures { input: AiTaskCancelInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/checkpoint_wooden_fish_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/checkpoint_wooden_fish_run_procedure.rs index 5bd5a45c..51aa864f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/checkpoint_wooden_fish_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/checkpoint_wooden_fish_run_procedure.rs @@ -31,10 +31,10 @@ pub trait checkpoint_wooden_fish_run { input: WoodenFishRunCheckpointInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl checkpoint_wooden_fish_run for super::RemoteProcedures { input: WoodenFishRunCheckpointInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs index ea501070..5a386f3c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/claim_profile_task_reward_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait claim_profile_task_reward_and_return { input: RuntimeProfileTaskClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl claim_profile_task_reward_and_return for super::RemoteProcedures { input: RuntimeProfileTaskClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskClaimProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/claim_puzzle_work_point_incentive_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/claim_puzzle_work_point_incentive_procedure.rs index 1d787222..f7ac8d75 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/claim_puzzle_work_point_incentive_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/claim_puzzle_work_point_incentive_procedure.rs @@ -31,10 +31,10 @@ pub trait claim_puzzle_work_point_incentive { input: PuzzleWorkPointIncentiveClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl claim_puzzle_work_point_incentive for super::RemoteProcedures { input: PuzzleWorkPointIncentiveClaimInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs index d05fcdf2..51146e99 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/clear_database_migration_import_chunks_procedure.rs @@ -34,10 +34,10 @@ pub trait clear_database_migration_import_chunks { input: DatabaseMigrationImportChunksClearInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl clear_database_migration_import_chunks for super::RemoteProcedures { input: DatabaseMigrationImportChunksClearInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/clear_platform_browse_history_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/clear_platform_browse_history_and_return_procedure.rs index c8ba8d49..2e623845 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/clear_platform_browse_history_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/clear_platform_browse_history_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait clear_platform_browse_history_and_return { input: RuntimeBrowseHistoryClearInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl clear_platform_browse_history_and_return for super::RemoteProcedures { input: RuntimeBrowseHistoryClearInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeBrowseHistoryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/click_match_3_d_item_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/click_match_3_d_item_procedure.rs index 278845ba..6070a62d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/click_match_3_d_item_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/click_match_3_d_item_procedure.rs @@ -31,10 +31,10 @@ pub trait click_match_3_d_item { input: Match3DRunClickInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl click_match_3_d_item for super::RemoteProcedures { input: Match3DRunClickInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DClickItemProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_big_fish_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_big_fish_draft_procedure.rs index bafe95a6..6eea6571 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_big_fish_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_big_fish_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_big_fish_draft { input: BigFishDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_big_fish_draft for super::RemoteProcedures { input: BigFishDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_custom_world_published_profile_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_custom_world_published_profile_procedure.rs index 67706fab..aefbe602 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_custom_world_published_profile_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_custom_world_published_profile_procedure.rs @@ -34,10 +34,10 @@ pub trait compile_custom_world_published_profile { input: CustomWorldPublishedProfileCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl compile_custom_world_published_profile for super::RemoteProcedures { input: CustomWorldPublishedProfileCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldPublishedProfileCompileResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_jump_hop_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_jump_hop_draft_procedure.rs index f0479afa..fe89daba 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_jump_hop_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_jump_hop_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_jump_hop_draft { input: JumpHopDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_jump_hop_draft for super::RemoteProcedures { input: JumpHopDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_match_3_d_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_match_3_d_draft_procedure.rs index 1a7a97ed..d6db0787 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_match_3_d_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_match_3_d_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_match_3_d_draft { input: Match3DDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_match_3_d_draft for super::RemoteProcedures { input: Match3DDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_puzzle_agent_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_puzzle_agent_draft_procedure.rs index 177c0c40..7badcdae 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_puzzle_agent_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_puzzle_agent_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_puzzle_agent_draft { input: PuzzleDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_puzzle_agent_draft for super::RemoteProcedures { input: PuzzleDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_square_hole_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_square_hole_draft_procedure.rs index 0b715fc4..ee6766b0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_square_hole_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_square_hole_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_square_hole_draft { input: SquareHoleDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_square_hole_draft for super::RemoteProcedures { input: SquareHoleDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_visual_novel_work_profile_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_visual_novel_work_profile_procedure.rs index e6d5f25b..457f9809 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_visual_novel_work_profile_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_visual_novel_work_profile_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_visual_novel_work_profile { input: VisualNovelWorkCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_visual_novel_work_profile for super::RemoteProcedures { input: VisualNovelWorkCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/compile_wooden_fish_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/compile_wooden_fish_draft_procedure.rs index 61c7b013..99e98ca8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/compile_wooden_fish_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/compile_wooden_fish_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait compile_wooden_fish_draft { input: WoodenFishDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl compile_wooden_fish_draft for super::RemoteProcedures { input: WoodenFishDraftCompileInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs index e59ab8f0..51375935 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_stage_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait complete_ai_stage_and_return { input: AiStageCompletionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl complete_ai_stage_and_return for super::RemoteProcedures { input: AiStageCompletionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs index ca7eab9f..040af639 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/complete_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait complete_ai_task_and_return { input: AiTaskFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl complete_ai_task_and_return for super::RemoteProcedures { input: AiTaskFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs index cc65f744..0b4f26b2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait confirm_asset_object_and_return { input: AssetObjectUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl confirm_asset_object_and_return for super::RemoteProcedures { input: AssetObjectUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetObjectProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs index f5edb63a..183c2efa 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/confirm_asset_object_reducer.rs @@ -47,11 +47,9 @@ pub trait confirm_asset_object { &self, input: AssetObjectUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl confirm_asset_object for super::RemoteReducers { &self, input: AssetObjectUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ConfirmAssetObjectArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs index 11394b66..3d3e47a2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/consume_profile_wallet_points_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait consume_profile_wallet_points_and_return { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl consume_profile_wallet_points_and_return for super::RemoteProcedures { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/continue_story_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/continue_story_and_return_procedure.rs index 1c2b51d8..0d58ec1b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/continue_story_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/continue_story_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait continue_story_and_return { input: StoryContinueInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl continue_story_and_return for super::RemoteProcedures { input: StoryContinueInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, StorySessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/continue_story_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/continue_story_reducer.rs index fb35bd1f..4117cfae 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/continue_story_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/continue_story_reducer.rs @@ -47,11 +47,9 @@ pub trait continue_story { &self, input: StoryContinueInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl continue_story for super::RemoteReducers { &self, input: StoryContinueInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ContinueStoryArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs index a2f40fd0..20d8ceee 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_ai_task_and_return { input: AiTaskCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_ai_task_and_return for super::RemoteProcedures { input: AiTaskCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs index b87207f0..213f28e5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_ai_task_reducer.rs @@ -47,11 +47,9 @@ pub trait create_ai_task { &self, input: AiTaskCreateInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl create_ai_task for super::RemoteReducers { &self, input: AiTaskCreateInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(CreateAiTaskArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_bark_battle_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_bark_battle_draft_procedure.rs index 87e104b6..dbc6f317 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_bark_battle_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_bark_battle_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait create_bark_battle_draft { input: BarkBattleDraftCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_bark_battle_draft for super::RemoteProcedures { input: BarkBattleDraftCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_and_return_procedure.rs index c028ba4e..ef11107a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait create_battle_state_and_return { input: BattleStateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_battle_state_and_return for super::RemoteProcedures { input: BattleStateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BattleStateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_reducer.rs index 7f34eab2..1072f8a5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_battle_state_reducer.rs @@ -47,11 +47,9 @@ pub trait create_battle_state { &self, input: BattleStateInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl create_battle_state for super::RemoteReducers { &self, input: BattleStateInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(CreateBattleStateArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_big_fish_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_big_fish_session_procedure.rs index 6e48521a..bc67436e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_big_fish_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_big_fish_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_big_fish_session { input: BigFishSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_big_fish_session for super::RemoteProcedures { input: BigFishSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_custom_world_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_custom_world_agent_session_procedure.rs index 96a21162..6a08bcc7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_custom_world_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_custom_world_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_custom_world_agent_session { input: CustomWorldAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_custom_world_agent_session for super::RemoteProcedures { input: CustomWorldAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_jump_hop_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_jump_hop_agent_session_procedure.rs index 6bfce7c5..e4eeb904 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_jump_hop_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_jump_hop_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_jump_hop_agent_session { input: JumpHopAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_jump_hop_agent_session for super::RemoteProcedures { input: JumpHopAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_match_3_d_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_match_3_d_agent_session_procedure.rs index 717ef728..c482c9c6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_match_3_d_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_match_3_d_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_match_3_d_agent_session { input: Match3DAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_match_3_d_agent_session for super::RemoteProcedures { input: Match3DAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs index 1c53f6ae..893fbdf6 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_profile_recharge_order_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait create_profile_recharge_order_and_return { input: RuntimeProfileRechargeOrderCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl create_profile_recharge_order_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_puzzle_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_puzzle_agent_session_procedure.rs index 62b77081..9460692b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_puzzle_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_puzzle_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_puzzle_agent_session { input: PuzzleAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_puzzle_agent_session for super::RemoteProcedures { input: PuzzleAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_square_hole_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_square_hole_agent_session_procedure.rs index d58dbfa6..cd5403a5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_square_hole_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_square_hole_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_square_hole_agent_session { input: SquareHoleAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_square_hole_agent_session for super::RemoteProcedures { input: SquareHoleAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_visual_novel_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_visual_novel_agent_session_procedure.rs index c42cc766..ef82cfc1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_visual_novel_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_visual_novel_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_visual_novel_agent_session { input: VisualNovelAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_visual_novel_agent_session for super::RemoteProcedures { input: VisualNovelAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/create_wooden_fish_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/create_wooden_fish_agent_session_procedure.rs index ec6bec0d..aabcde5c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/create_wooden_fish_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/create_wooden_fish_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait create_wooden_fish_agent_session { input: WoodenFishAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl create_wooden_fish_agent_session for super::RemoteProcedures { input: WoodenFishAgentSessionCreateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_big_fish_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_big_fish_work_procedure.rs index d2be83ac..51cc224f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_big_fish_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_big_fish_work_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_big_fish_work { input: BigFishWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_big_fish_work for super::RemoteProcedures { input: BigFishWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_agent_session_procedure.rs index 39887830..27341561 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_custom_world_agent_session { input: CustomWorldAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_custom_world_agent_session for super::RemoteProcedures { input: CustomWorldAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldWorksListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_profile_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_profile_and_return_procedure.rs index 5dc9da2f..246d4d00 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_profile_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_custom_world_profile_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_custom_world_profile_and_return { input: CustomWorldProfileDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_custom_world_profile_and_return for super::RemoteProcedures { input: CustomWorldProfileDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldProfileListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_match_3_d_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_match_3_d_work_procedure.rs index c87cd16a..c26b2dc8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_match_3_d_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_match_3_d_work_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_match_3_d_work { input: Match3DWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_match_3_d_work for super::RemoteProcedures { input: Match3DWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_puzzle_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_puzzle_work_procedure.rs index fc8152c5..5b7e5375 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_puzzle_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_puzzle_work_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_puzzle_work { input: PuzzleWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_puzzle_work for super::RemoteProcedures { input: PuzzleWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_runtime_snapshot_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_runtime_snapshot_and_return_procedure.rs index 9173255a..6373a19b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_runtime_snapshot_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_runtime_snapshot_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_runtime_snapshot_and_return { input: RuntimeSnapshotDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_runtime_snapshot_and_return for super::RemoteProcedures { input: RuntimeSnapshotDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSnapshotProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_square_hole_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_square_hole_work_procedure.rs index 3a8db794..3469c314 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_square_hole_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_square_hole_work_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_square_hole_work { input: SquareHoleWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_square_hole_work for super::RemoteProcedures { input: SquareHoleWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/delete_visual_novel_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/delete_visual_novel_work_procedure.rs index eac6ceac..61ed9904 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/delete_visual_novel_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/delete_visual_novel_work_procedure.rs @@ -31,10 +31,10 @@ pub trait delete_visual_novel_work { input: VisualNovelWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl delete_visual_novel_work for super::RemoteProcedures { input: VisualNovelWorkDeleteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/drag_puzzle_piece_or_group_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/drag_puzzle_piece_or_group_procedure.rs index 1207f7b5..daad89bd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/drag_puzzle_piece_or_group_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/drag_puzzle_piece_or_group_procedure.rs @@ -31,10 +31,10 @@ pub trait drag_puzzle_piece_or_group { input: PuzzleRunDragInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl drag_puzzle_piece_or_group for super::RemoteProcedures { input: PuzzleRunDragInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/drop_square_hole_shape_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/drop_square_hole_shape_procedure.rs index 4056e06a..91d6bb61 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/drop_square_hole_shape_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/drop_square_hole_shape_procedure.rs @@ -31,10 +31,10 @@ pub trait drop_square_hole_shape { input: SquareHoleRunDropInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl drop_square_hole_shape for super::RemoteProcedures { input: SquareHoleRunDropInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleDropShapeProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs index a6ea3098..30b9ba35 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/ensure_analytics_date_dimension_for_date_reducer.rs @@ -50,11 +50,9 @@ pub trait ensure_analytics_date_dimension_for_date { &self, input: AnalyticsDateDimensionEnsureInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl ensure_analytics_date_dimension_for_date for super::RemoteReducers { &self, input: AnalyticsDateDimensionEnsureInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp.invoke_reducer_with_callback( EnsureAnalyticsDateDimensionForDateArgs { input }, diff --git a/server-rs/crates/spacetime-client/src/module_bindings/execute_custom_world_agent_action_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/execute_custom_world_agent_action_procedure.rs index c1008466..e778877c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/execute_custom_world_agent_action_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/execute_custom_world_agent_action_procedure.rs @@ -31,10 +31,10 @@ pub trait execute_custom_world_agent_action { input: CustomWorldAgentActionExecuteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl execute_custom_world_agent_action for super::RemoteProcedures { input: CustomWorldAgentActionExecuteInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentActionExecuteResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs index 9e8059fa..9f8842ad 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs @@ -27,10 +27,10 @@ pub trait export_auth_store_snapshot_from_tables { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl export_auth_store_snapshot_from_tables for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AuthStoreSnapshotProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs index d850737b..3dfe18f8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/export_database_migration_to_file_procedure.rs @@ -31,10 +31,10 @@ pub trait export_database_migration_to_file { input: DatabaseMigrationExportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl export_database_migration_to_file for super::RemoteProcedures { input: DatabaseMigrationExportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs index 3194799b..46090a01 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/fail_ai_task_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait fail_ai_task_and_return { input: AiTaskFailureInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl fail_ai_task_and_return for super::RemoteProcedures { input: AiTaskFailureInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AiTaskProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finalize_big_fish_agent_message_turn_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finalize_big_fish_agent_message_turn_procedure.rs index a2dd9fd5..9f5c8e7a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finalize_big_fish_agent_message_turn_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finalize_big_fish_agent_message_turn_procedure.rs @@ -31,10 +31,10 @@ pub trait finalize_big_fish_agent_message_turn { input: BigFishMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finalize_big_fish_agent_message_turn for super::RemoteProcedures { input: BigFishMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finalize_custom_world_agent_message_turn_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finalize_custom_world_agent_message_turn_procedure.rs index f670f9b6..fad75a7b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finalize_custom_world_agent_message_turn_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finalize_custom_world_agent_message_turn_procedure.rs @@ -34,10 +34,10 @@ pub trait finalize_custom_world_agent_message_turn { input: CustomWorldAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl finalize_custom_world_agent_message_turn for super::RemoteProcedures { input: CustomWorldAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentOperationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finalize_match_3_d_agent_message_turn_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finalize_match_3_d_agent_message_turn_procedure.rs index ea0ec225..9d51ab95 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finalize_match_3_d_agent_message_turn_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finalize_match_3_d_agent_message_turn_procedure.rs @@ -31,10 +31,10 @@ pub trait finalize_match_3_d_agent_message_turn { input: Match3DAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finalize_match_3_d_agent_message_turn for super::RemoteProcedures { input: Match3DAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finalize_puzzle_agent_message_turn_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finalize_puzzle_agent_message_turn_procedure.rs index 7f06aafa..0014d394 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finalize_puzzle_agent_message_turn_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finalize_puzzle_agent_message_turn_procedure.rs @@ -31,10 +31,10 @@ pub trait finalize_puzzle_agent_message_turn { input: PuzzleAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finalize_puzzle_agent_message_turn for super::RemoteProcedures { input: PuzzleAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finalize_square_hole_agent_message_turn_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finalize_square_hole_agent_message_turn_procedure.rs index 350f160d..75808f10 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finalize_square_hole_agent_message_turn_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finalize_square_hole_agent_message_turn_procedure.rs @@ -31,10 +31,10 @@ pub trait finalize_square_hole_agent_message_turn { input: SquareHoleAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finalize_square_hole_agent_message_turn for super::RemoteProcedures { input: SquareHoleAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finalize_visual_novel_agent_message_turn_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finalize_visual_novel_agent_message_turn_procedure.rs index 08b47560..5305f8e8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finalize_visual_novel_agent_message_turn_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finalize_visual_novel_agent_message_turn_procedure.rs @@ -34,10 +34,10 @@ pub trait finalize_visual_novel_agent_message_turn { input: VisualNovelAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl finalize_visual_novel_agent_message_turn for super::RemoteProcedures { input: VisualNovelAgentMessageFinalizeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finish_bark_battle_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finish_bark_battle_run_procedure.rs index 28fc7ef3..8eeaf0c1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finish_bark_battle_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finish_bark_battle_run_procedure.rs @@ -31,10 +31,10 @@ pub trait finish_bark_battle_run { input: BarkBattleRunFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finish_bark_battle_run for super::RemoteProcedures { input: BarkBattleRunFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finish_match_3_d_time_up_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finish_match_3_d_time_up_procedure.rs index bd849631..0d68dbd9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finish_match_3_d_time_up_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finish_match_3_d_time_up_procedure.rs @@ -31,10 +31,10 @@ pub trait finish_match_3_d_time_up { input: Match3DRunTimeUpInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finish_match_3_d_time_up for super::RemoteProcedures { input: Match3DRunTimeUpInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finish_square_hole_time_up_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finish_square_hole_time_up_procedure.rs index 3ca46a0d..f3b5ffc3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finish_square_hole_time_up_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finish_square_hole_time_up_procedure.rs @@ -31,10 +31,10 @@ pub trait finish_square_hole_time_up { input: SquareHoleRunTimeUpInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finish_square_hole_time_up for super::RemoteProcedures { input: SquareHoleRunTimeUpInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/finish_wooden_fish_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/finish_wooden_fish_run_procedure.rs index 30e452e1..240541fb 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/finish_wooden_fish_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/finish_wooden_fish_run_procedure.rs @@ -31,10 +31,10 @@ pub trait finish_wooden_fish_run { input: WoodenFishRunFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl finish_wooden_fish_run for super::RemoteProcedures { input: WoodenFishRunFinishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/generate_big_fish_asset_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/generate_big_fish_asset_procedure.rs index 144c5d40..1a87c951 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/generate_big_fish_asset_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/generate_big_fish_asset_procedure.rs @@ -31,10 +31,10 @@ pub trait generate_big_fish_asset { input: BigFishAssetGenerateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl generate_big_fish_asset for super::RemoteProcedures { input: BigFishAssetGenerateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_run_procedure.rs index bec98ca8..87c3f82a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_bark_battle_run { input: BarkBattleRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_bark_battle_run for super::RemoteProcedures { input: BarkBattleRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_runtime_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_runtime_config_procedure.rs index 6e4364f2..f163d3b3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_runtime_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_bark_battle_runtime_config_procedure.rs @@ -31,10 +31,10 @@ pub trait get_bark_battle_runtime_config { input: BarkBattleRuntimeConfigGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_bark_battle_runtime_config for super::RemoteProcedures { input: BarkBattleRuntimeConfigGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_battle_state_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_battle_state_procedure.rs index 0fcc276c..a737fbdf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_battle_state_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_battle_state_procedure.rs @@ -31,10 +31,10 @@ pub trait get_battle_state { input: BattleStateQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_battle_state for super::RemoteProcedures { input: BattleStateQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BattleStateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_run_procedure.rs index 9a601ff2..867a6759 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_big_fish_run { input: BigFishRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_big_fish_run for super::RemoteProcedures { input: BigFishRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_session_procedure.rs index 7f52f94b..0b0d78f1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_big_fish_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_big_fish_session { input: BigFishSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_big_fish_session for super::RemoteProcedures { input: BigFishSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_chapter_progression_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_chapter_progression_procedure.rs index 18f9ae27..eef158dc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_chapter_progression_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_chapter_progression_procedure.rs @@ -31,10 +31,10 @@ pub trait get_chapter_progression { input: ChapterProgressionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_chapter_progression for super::RemoteProcedures { input: ChapterProgressionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ChapterProgressionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_creation_entry_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_creation_entry_config_procedure.rs index 8a3a38dd..eb840cdc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_creation_entry_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_creation_entry_config_procedure.rs @@ -27,10 +27,10 @@ pub trait get_creation_entry_config { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl get_creation_entry_config for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CreationEntryConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_card_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_card_detail_procedure.rs index e1034345..11a90329 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_card_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_card_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_custom_world_agent_card_detail { input: CustomWorldAgentCardDetailGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_custom_world_agent_card_detail for super::RemoteProcedures { input: CustomWorldAgentCardDetailGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldDraftCardDetailResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_operation_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_operation_procedure.rs index cce1dbb5..1c4ffd6a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_operation_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_operation_procedure.rs @@ -31,10 +31,10 @@ pub trait get_custom_world_agent_operation { input: CustomWorldAgentOperationGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_custom_world_agent_operation for super::RemoteProcedures { input: CustomWorldAgentOperationGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentOperationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_session_procedure.rs index f4b678e9..212987e4 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_custom_world_agent_session { input: CustomWorldAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_custom_world_agent_session for super::RemoteProcedures { input: CustomWorldAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_by_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_by_code_procedure.rs index a387cbaf..24768c43 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_by_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_by_code_procedure.rs @@ -31,10 +31,10 @@ pub trait get_custom_world_gallery_detail_by_code { input: CustomWorldGalleryDetailByCodeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_custom_world_gallery_detail_by_code for super::RemoteProcedures { input: CustomWorldGalleryDetailByCodeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_procedure.rs index d0e029ff..f5127dcf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_gallery_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_custom_world_gallery_detail { input: CustomWorldGalleryDetailInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_custom_world_gallery_detail for super::RemoteProcedures { input: CustomWorldGalleryDetailInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_library_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_library_detail_procedure.rs index 82bd1c3c..ab99274a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_library_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_custom_world_library_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_custom_world_library_detail { input: CustomWorldLibraryDetailInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_custom_world_library_detail for super::RemoteProcedures { input: CustomWorldLibraryDetailInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_agent_session_procedure.rs index 482aa1a5..fde5cf93 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_jump_hop_agent_session { input: JumpHopAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_jump_hop_agent_session for super::RemoteProcedures { input: JumpHopAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_run_procedure.rs index 5c301da7..9f641d0f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_jump_hop_run { input: JumpHopRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_jump_hop_run for super::RemoteProcedures { input: JumpHopRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_work_profile_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_work_profile_procedure.rs index fd1fbd3e..62515a28 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_work_profile_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_jump_hop_work_profile_procedure.rs @@ -31,10 +31,10 @@ pub trait get_jump_hop_work_profile { input: JumpHopWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_jump_hop_work_profile for super::RemoteProcedures { input: JumpHopWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_agent_session_procedure.rs index 574012d9..62d093b5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_match_3_d_agent_session { input: Match3DAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_match_3_d_agent_session for super::RemoteProcedures { input: Match3DAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_run_procedure.rs index 0a472230..033e620c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_match_3_d_run { input: Match3DRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_match_3_d_run for super::RemoteProcedures { input: Match3DRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_work_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_work_detail_procedure.rs index 0ea9f495..5a74982b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_work_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_match_3_d_work_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_match_3_d_work_detail { input: Match3DWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_match_3_d_work_detail for super::RemoteProcedures { input: Match3DWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_player_progression_or_default_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_player_progression_or_default_procedure.rs index 38a1525a..97c139fb 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_player_progression_or_default_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_player_progression_or_default_procedure.rs @@ -31,10 +31,10 @@ pub trait get_player_progression_or_default { input: PlayerProgressionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_player_progression_or_default for super::RemoteProcedures { input: PlayerProgressionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PlayerProgressionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs index 6c48fafb..38200b75 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_dashboard_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_dashboard { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_dashboard for super::RemoteProcedures { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileDashboardProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_play_stats_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_play_stats_procedure.rs index 088f4812..2ad47ed2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_play_stats_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_play_stats_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_play_stats { input: RuntimeProfilePlayStatsGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_play_stats for super::RemoteProcedures { input: RuntimeProfilePlayStatsGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfilePlayStatsProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs index 3e42f3d5..bf070c9c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_center_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_recharge_center { input: RuntimeProfileRechargeCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_recharge_center for super::RemoteProcedures { input: RuntimeProfileRechargeCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs index f187bc6f..437f0048 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_recharge_order_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_recharge_order_and_return { input: RuntimeProfileRechargeOrderGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_recharge_order_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs index c7221484..2b3dcdad 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_referral_invite_center_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_referral_invite_center { input: RuntimeReferralInviteCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_referral_invite_center for super::RemoteProcedures { input: RuntimeReferralInviteCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeReferralInviteCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs index 0aa83260..105a4f98 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_profile_task_center_procedure.rs @@ -31,10 +31,10 @@ pub trait get_profile_task_center { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_profile_task_center for super::RemoteProcedures { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileTaskCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_agent_session_procedure.rs index 8aa5a78f..97929382 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_puzzle_agent_session { input: PuzzleAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_puzzle_agent_session for super::RemoteProcedures { input: PuzzleAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_gallery_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_gallery_detail_procedure.rs index 85b70081..a1471eb3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_gallery_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_gallery_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_puzzle_gallery_detail { input: PuzzleWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_puzzle_gallery_detail for super::RemoteProcedures { input: PuzzleWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_run_procedure.rs index d09fc285..2db5ab66 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_puzzle_run { input: PuzzleRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_puzzle_run for super::RemoteProcedures { input: PuzzleRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_work_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_work_detail_procedure.rs index 0d6c4f70..d36c7417 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_work_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_puzzle_work_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_puzzle_work_detail { input: PuzzleWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_puzzle_work_detail for super::RemoteProcedures { input: PuzzleWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_inventory_state_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_inventory_state_procedure.rs index c8dfefac..abbf4f20 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_inventory_state_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_inventory_state_procedure.rs @@ -31,10 +31,10 @@ pub trait get_runtime_inventory_state { input: RuntimeInventoryStateQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_runtime_inventory_state for super::RemoteProcedures { input: RuntimeInventoryStateQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeInventoryStateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs index 4ca8b03e..261caed1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_setting_or_default_procedure.rs @@ -31,10 +31,10 @@ pub trait get_runtime_setting_or_default { input: RuntimeSettingGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_runtime_setting_or_default for super::RemoteProcedures { input: RuntimeSettingGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSettingProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_snapshot_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_snapshot_procedure.rs index 7f9feb4f..989fa40e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_snapshot_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_runtime_snapshot_procedure.rs @@ -31,10 +31,10 @@ pub trait get_runtime_snapshot { input: RuntimeSnapshotGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_runtime_snapshot for super::RemoteProcedures { input: RuntimeSnapshotGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSnapshotProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_agent_session_procedure.rs index 1db6459e..46a17280 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_square_hole_agent_session { input: SquareHoleAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_square_hole_agent_session for super::RemoteProcedures { input: SquareHoleAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_run_procedure.rs index 5082e790..6dabdb92 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_square_hole_run { input: SquareHoleRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_square_hole_run for super::RemoteProcedures { input: SquareHoleRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_work_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_work_detail_procedure.rs index 67a16a07..78812cf7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_work_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_square_hole_work_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_square_hole_work_detail { input: SquareHoleWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_square_hole_work_detail for super::RemoteProcedures { input: SquareHoleWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_story_session_state_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_story_session_state_procedure.rs index 44b48ada..7e566dc9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_story_session_state_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_story_session_state_procedure.rs @@ -31,10 +31,10 @@ pub trait get_story_session_state { input: StorySessionStateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_story_session_state for super::RemoteProcedures { input: StorySessionStateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, StorySessionStateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_agent_session_procedure.rs index a4b4b6d1..7b50fd29 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_visual_novel_agent_session { input: VisualNovelAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_visual_novel_agent_session for super::RemoteProcedures { input: VisualNovelAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_run_procedure.rs index 86bdff38..702737fd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_visual_novel_run { input: VisualNovelRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_visual_novel_run for super::RemoteProcedures { input: VisualNovelRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_work_detail_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_work_detail_procedure.rs index 64864f29..373121fc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_work_detail_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_visual_novel_work_detail_procedure.rs @@ -31,10 +31,10 @@ pub trait get_visual_novel_work_detail { input: VisualNovelWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_visual_novel_work_detail for super::RemoteProcedures { input: VisualNovelWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_agent_session_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_agent_session_procedure.rs index e0b80d0e..8d198353 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_agent_session_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_agent_session_procedure.rs @@ -31,10 +31,10 @@ pub trait get_wooden_fish_agent_session { input: WoodenFishAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_wooden_fish_agent_session for super::RemoteProcedures { input: WoodenFishAgentSessionGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_run_procedure.rs index 8a0e145a..bb381e48 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_run_procedure.rs @@ -31,10 +31,10 @@ pub trait get_wooden_fish_run { input: WoodenFishRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_wooden_fish_run for super::RemoteProcedures { input: WoodenFishRunGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_work_profile_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_work_profile_procedure.rs index 44f67362..1621290a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_work_profile_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/get_wooden_fish_work_profile_procedure.rs @@ -31,10 +31,10 @@ pub trait get_wooden_fish_work_profile { input: WoodenFishWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl get_wooden_fish_work_profile for super::RemoteProcedures { input: WoodenFishWorkGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs index 71e48151..c1d7b6de 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/grant_new_user_registration_wallet_reward_procedure.rs @@ -31,10 +31,10 @@ pub trait grant_new_user_registration_wallet_reward { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl grant_new_user_registration_wallet_reward for super::RemoteProcedures { input: RuntimeProfileDashboardGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_and_return_procedure.rs index a3f2aa9e..4c67da63 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait grant_player_progression_experience_and_return { input: PlayerProgressionGrantInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl grant_player_progression_experience_and_return for super::RemoteProcedures input: PlayerProgressionGrantInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PlayerProgressionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_reducer.rs index bd07115e..83b48cf7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/grant_player_progression_experience_reducer.rs @@ -50,11 +50,9 @@ pub trait grant_player_progression_experience { &self, input: PlayerProgressionGrantInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl grant_player_progression_experience for super::RemoteReducers { &self, input: PlayerProgressionGrantInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(GrantPlayerProgressionExperienceArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_json_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_json_procedure.rs index 3cd6d71f..68171d4d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_json_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_json_procedure.rs @@ -31,10 +31,10 @@ pub trait import_auth_store_snapshot_json { input: AuthStoreSnapshotUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_auth_store_snapshot_json for super::RemoteProcedures { input: AuthStoreSnapshotUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AuthStoreSnapshotImportProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs index 080dda54..73157480 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_chunks_procedure.rs @@ -31,10 +31,10 @@ pub trait import_database_migration_from_chunks { input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_database_migration_from_chunks for super::RemoteProcedures { input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs index 2ce4ee2a..7b2322ee 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_from_file_procedure.rs @@ -31,10 +31,10 @@ pub trait import_database_migration_from_file { input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_database_migration_from_file for super::RemoteProcedures { input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs index bbe49357..51ff565c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_chunks_procedure.rs @@ -34,10 +34,10 @@ pub trait import_database_migration_incremental_from_chunks { input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl import_database_migration_incremental_from_chunks for super::RemoteProcedur input: DatabaseMigrationImportChunksInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs index f911c87f..2fc31804 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_database_migration_incremental_from_file_procedure.rs @@ -31,10 +31,10 @@ pub trait import_database_migration_incremental_from_file { input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl import_database_migration_incremental_from_file for super::RemoteProcedures input: DatabaseMigrationImportInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_jump_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_jump_procedure.rs index 1535f96f..19cfbec9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_jump_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/jump_hop_jump_procedure.rs @@ -31,10 +31,10 @@ pub trait jump_hop_jump { input: JumpHopRunJumpInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl jump_hop_jump for super::RemoteProcedures { input: JumpHopRunJumpInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs index ea689b10..bcc2a742 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_asset_history_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait list_asset_history_and_return { input: AssetHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_asset_history_and_return for super::RemoteProcedures { input: AssetHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AssetHistoryListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_big_fish_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_big_fish_works_procedure.rs index 45ba04af..8e4c21ba 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_big_fish_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_big_fish_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_big_fish_works { input: BigFishWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_big_fish_works for super::RemoteProcedures { input: BigFishWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_gallery_entries_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_gallery_entries_procedure.rs index 01f6cb0c..63ee059f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_gallery_entries_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_gallery_entries_procedure.rs @@ -27,10 +27,10 @@ pub trait list_custom_world_gallery_entries { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl list_custom_world_gallery_entries for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldGalleryListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_profiles_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_profiles_procedure.rs index c42ce2c6..f8834945 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_profiles_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_profiles_procedure.rs @@ -31,10 +31,10 @@ pub trait list_custom_world_profiles { input: CustomWorldProfileListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_custom_world_profiles for super::RemoteProcedures { input: CustomWorldProfileListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldProfileListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_works_procedure.rs index 77f48ba6..d469f660 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_custom_world_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_custom_world_works { input: CustomWorldWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_custom_world_works for super::RemoteProcedures { input: CustomWorldWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldWorksListResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_jump_hop_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_jump_hop_works_procedure.rs index 18b5cce5..96d931c3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_jump_hop_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_jump_hop_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_jump_hop_works { input: JumpHopWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_jump_hop_works for super::RemoteProcedures { input: JumpHopWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_match_3_d_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_match_3_d_works_procedure.rs index c593e848..b1477034 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_match_3_d_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_match_3_d_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_match_3_d_works { input: Match3DWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_match_3_d_works for super::RemoteProcedures { input: Match3DWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_platform_browse_history_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_platform_browse_history_procedure.rs index 00176656..0d368a99 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_platform_browse_history_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_platform_browse_history_procedure.rs @@ -31,10 +31,10 @@ pub trait list_platform_browse_history { input: RuntimeBrowseHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_platform_browse_history for super::RemoteProcedures { input: RuntimeBrowseHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeBrowseHistoryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_save_archives_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_save_archives_procedure.rs index 1c7176cf..31c214bb 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_save_archives_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_save_archives_procedure.rs @@ -31,10 +31,10 @@ pub trait list_profile_save_archives { input: RuntimeProfileSaveArchiveListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_profile_save_archives for super::RemoteProcedures { input: RuntimeProfileSaveArchiveListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileSaveArchiveProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs index d51f0df2..23496701 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_profile_wallet_ledger_procedure.rs @@ -31,10 +31,10 @@ pub trait list_profile_wallet_ledger { input: RuntimeProfileWalletLedgerListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_profile_wallet_ledger for super::RemoteProcedures { input: RuntimeProfileWalletLedgerListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletLedgerProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_gallery_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_gallery_procedure.rs index e62fd064..553b8e08 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_gallery_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_gallery_procedure.rs @@ -27,10 +27,10 @@ pub trait list_puzzle_gallery { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -39,10 +39,10 @@ impl list_puzzle_gallery for super::RemoteProcedures { &self, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_works_procedure.rs index 1da004e9..844d16df 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_puzzle_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_puzzle_works { input: PuzzleWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_puzzle_works for super::RemoteProcedures { input: PuzzleWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_square_hole_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_square_hole_works_procedure.rs index 1c706a8c..0052c502 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_square_hole_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_square_hole_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_square_hole_works { input: SquareHoleWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_square_hole_works for super::RemoteProcedures { input: SquareHoleWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_runtime_history_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_runtime_history_procedure.rs index fdc06a22..680a8455 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_runtime_history_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_runtime_history_procedure.rs @@ -31,10 +31,10 @@ pub trait list_visual_novel_runtime_history { input: VisualNovelRuntimeHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_visual_novel_runtime_history for super::RemoteProcedures { input: VisualNovelRuntimeHistoryListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelHistoryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_works_procedure.rs index 1920ee79..be9b9a29 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_visual_novel_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_visual_novel_works { input: VisualNovelWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_visual_novel_works for super::RemoteProcedures { input: VisualNovelWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/list_wooden_fish_works_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/list_wooden_fish_works_procedure.rs index d449ff80..87695a8e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/list_wooden_fish_works_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/list_wooden_fish_works_procedure.rs @@ -31,10 +31,10 @@ pub trait list_wooden_fish_works { input: WoodenFishWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl list_wooden_fish_works for super::RemoteProcedures { input: WoodenFishWorksListInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs index f412f184..09ba81c7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mark_profile_recharge_order_paid_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait mark_profile_recharge_order_paid_and_return { input: RuntimeProfileRechargeOrderPaidInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl mark_profile_recharge_order_paid_and_return for super::RemoteProcedures { input: RuntimeProfileRechargeOrderPaidInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mark_puzzle_draft_generation_failed_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/mark_puzzle_draft_generation_failed_procedure.rs index ae073d5c..954b7ddc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mark_puzzle_draft_generation_failed_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mark_puzzle_draft_generation_failed_procedure.rs @@ -31,10 +31,10 @@ pub trait mark_puzzle_draft_generation_failed { input: PuzzleDraftCompileFailureInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl mark_puzzle_draft_generation_failed for super::RemoteProcedures { input: PuzzleDraftCompileFailureInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs index d0c84769..8c95aaa8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/public_work_play_daily_stat_table.rs @@ -153,7 +153,7 @@ pub trait public_work_play_daily_statQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `PublicWorkPlayDailyStat`. fn public_work_play_daily_stat(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl public_work_play_daily_statQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_bark_battle_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_bark_battle_work_procedure.rs index 87884f54..9ea9f0db 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_bark_battle_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_bark_battle_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_bark_battle_work { input: BarkBattleWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_bark_battle_work for super::RemoteProcedures { input: BarkBattleWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_big_fish_game_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_big_fish_game_procedure.rs index d4507ad8..e8007288 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_big_fish_game_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_big_fish_game_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_big_fish_game { input: BigFishPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_big_fish_game for super::RemoteProcedures { input: BigFishPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_and_return_procedure.rs index d5741922..e5434aca 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_custom_world_profile_and_return { input: CustomWorldProfilePublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_custom_world_profile_and_return for super::RemoteProcedures { input: CustomWorldProfilePublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_reducer.rs index 2e2f71f6..84e6b339 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_profile_reducer.rs @@ -50,11 +50,9 @@ pub trait publish_custom_world_profile { &self, input: CustomWorldProfilePublishInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl publish_custom_world_profile for super::RemoteReducers { &self, input: CustomWorldProfilePublishInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(PublishCustomWorldProfileArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_world_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_world_procedure.rs index 42c76aad..1eb935a2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_world_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_custom_world_world_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_custom_world_world { input: CustomWorldPublishWorldInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_custom_world_world for super::RemoteProcedures { input: CustomWorldPublishWorldInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldPublishWorldResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_jump_hop_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_jump_hop_work_procedure.rs index 926aed9b..a87bb278 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_jump_hop_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_jump_hop_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_jump_hop_work { input: JumpHopWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_jump_hop_work for super::RemoteProcedures { input: JumpHopWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_match_3_d_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_match_3_d_work_procedure.rs index db0c7efe..65bd160e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_match_3_d_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_match_3_d_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_match_3_d_work { input: Match3DWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_match_3_d_work for super::RemoteProcedures { input: Match3DWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_puzzle_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_puzzle_work_procedure.rs index 932b66d6..288b44a5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_puzzle_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_puzzle_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_puzzle_work { input: PuzzlePublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_puzzle_work for super::RemoteProcedures { input: PuzzlePublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_square_hole_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_square_hole_work_procedure.rs index ad4e944e..f0c2be48 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_square_hole_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_square_hole_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_square_hole_work { input: SquareHoleWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_square_hole_work for super::RemoteProcedures { input: SquareHoleWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_visual_novel_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_visual_novel_work_procedure.rs index 91c7eabd..7ddf731b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_visual_novel_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_visual_novel_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_visual_novel_work { input: VisualNovelWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_visual_novel_work for super::RemoteProcedures { input: VisualNovelWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/publish_wooden_fish_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/publish_wooden_fish_work_procedure.rs index f370ace6..5dd6555c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/publish_wooden_fish_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/publish_wooden_fish_work_procedure.rs @@ -31,10 +31,10 @@ pub trait publish_wooden_fish_work { input: WoodenFishWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl publish_wooden_fish_work for super::RemoteProcedures { input: WoodenFishWorkPublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs index f3776bfd..597b2511 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/put_database_migration_import_chunk_procedure.rs @@ -31,10 +31,10 @@ pub trait put_database_migration_import_chunk { input: DatabaseMigrationImportChunkInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl put_database_migration_import_chunk for super::RemoteProcedures { input: DatabaseMigrationImportChunkInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs index 7973f546..adc25bfa 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/query_analytics_metric_procedure.rs @@ -31,10 +31,10 @@ pub trait query_analytics_metric { input: AnalyticsMetricQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl query_analytics_metric for super::RemoteProcedures { input: AnalyticsMetricQueryInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, AnalyticsMetricQueryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_like_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_like_procedure.rs index 536aa47d..0429a9f7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_like_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_like_procedure.rs @@ -31,10 +31,10 @@ pub trait record_big_fish_like { input: BigFishWorkLikeRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_big_fish_like for super::RemoteProcedures { input: BigFishWorkLikeRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_play_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_play_procedure.rs index 8cf35b2b..f4cfaa6b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_play_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_big_fish_play_procedure.rs @@ -31,10 +31,10 @@ pub trait record_big_fish_play { input: BigFishPlayRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_big_fish_play for super::RemoteProcedures { input: BigFishPlayRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishWorksProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_like_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_like_procedure.rs index 1cd0aaad..6ac81dd9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_like_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_like_procedure.rs @@ -31,10 +31,10 @@ pub trait record_custom_world_profile_like { input: CustomWorldProfileLikeRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_custom_world_profile_like for super::RemoteProcedures { input: CustomWorldProfileLikeRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_play_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_play_procedure.rs index 2534ee30..f803e277 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_play_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_custom_world_profile_play_procedure.rs @@ -31,10 +31,10 @@ pub trait record_custom_world_profile_play { input: CustomWorldProfilePlayRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_custom_world_profile_play for super::RemoteProcedures { input: CustomWorldProfilePlayRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs index c131f3ba..9365d335 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_daily_login_tracking_event_and_return_procedure.rs @@ -34,10 +34,10 @@ pub trait record_daily_login_tracking_event_and_return { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl record_daily_login_tracking_event_and_return for super::RemoteProcedures { input: RuntimeProfileTaskCenterGetInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeTrackingEventProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_puzzle_work_like_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_puzzle_work_like_procedure.rs index fa55cf09..78dce7f8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_puzzle_work_like_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_puzzle_work_like_procedure.rs @@ -31,10 +31,10 @@ pub trait record_puzzle_work_like { input: PuzzleWorkLikeRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_puzzle_work_like for super::RemoteProcedures { input: PuzzleWorkLikeRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs index c09132c0..01361ec7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_event_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait record_tracking_event_and_return { input: RuntimeTrackingEventInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_tracking_event_and_return for super::RemoteProcedures { input: RuntimeTrackingEventInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeTrackingEventProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs index 428e378f..ba28d1a8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_tracking_events_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait record_tracking_events_and_return { inputs: Vec, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_tracking_events_and_return for super::RemoteProcedures { inputs: Vec, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeTrackingEventBatchProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/record_visual_novel_runtime_event_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/record_visual_novel_runtime_event_procedure.rs index 39f3a431..8c8db759 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/record_visual_novel_runtime_event_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/record_visual_novel_runtime_event_procedure.rs @@ -31,10 +31,10 @@ pub trait record_visual_novel_runtime_event { input: VisualNovelRuntimeEventRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl record_visual_novel_runtime_event for super::RemoteProcedures { input: VisualNovelRuntimeEventRecordInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelRuntimeEventProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs index efebd26a..44354acd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_referral_invite_code_procedure.rs @@ -31,10 +31,10 @@ pub trait redeem_profile_referral_invite_code { input: RuntimeReferralRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl redeem_profile_referral_invite_code for super::RemoteProcedures { input: RuntimeReferralRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeReferralRedeemProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs index 38fc64f5..4d048a49 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/redeem_profile_reward_code_procedure.rs @@ -31,10 +31,10 @@ pub trait redeem_profile_reward_code { input: RuntimeProfileRewardCodeRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl redeem_profile_reward_code for super::RemoteProcedures { input: RuntimeProfileRewardCodeRedeemInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileRewardCodeRedeemProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs index a4bbd378..fb86172c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/refund_profile_wallet_points_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait refund_profile_wallet_points_and_return { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl refund_profile_wallet_points_and_return for super::RemoteProcedures { input: RuntimeProfileWalletAdjustmentInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/remix_big_fish_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/remix_big_fish_work_procedure.rs index ff7d1486..7f58adb3 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/remix_big_fish_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/remix_big_fish_work_procedure.rs @@ -31,10 +31,10 @@ pub trait remix_big_fish_work { input: BigFishWorkRemixInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl remix_big_fish_work for super::RemoteProcedures { input: BigFishWorkRemixInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/remix_custom_world_profile_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/remix_custom_world_profile_procedure.rs index 8cd29b12..93f74383 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/remix_custom_world_profile_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/remix_custom_world_profile_procedure.rs @@ -31,10 +31,10 @@ pub trait remix_custom_world_profile { input: CustomWorldProfileRemixInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl remix_custom_world_profile for super::RemoteProcedures { input: CustomWorldProfileRemixInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/remix_puzzle_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/remix_puzzle_work_procedure.rs index d2548069..da91b334 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/remix_puzzle_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/remix_puzzle_work_procedure.rs @@ -31,10 +31,10 @@ pub trait remix_puzzle_work { input: PuzzleWorkRemixInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl remix_puzzle_work for super::RemoteProcedures { input: PuzzleWorkRemixInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_and_return_procedure.rs index 7d6fbfd1..ac8aa07d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resolve_combat_action_and_return { input: ResolveCombatActionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resolve_combat_action_and_return for super::RemoteProcedures { input: ResolveCombatActionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ResolveCombatActionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_reducer.rs index 8398db8c..41340e2f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_combat_action_reducer.rs @@ -47,11 +47,9 @@ pub trait resolve_combat_action { &self, input: ResolveCombatActionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl resolve_combat_action for super::RemoteReducers { &self, input: ResolveCombatActionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ResolveCombatActionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_battle_interaction_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_battle_interaction_and_return_procedure.rs index 268483bf..ff4cca29 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_battle_interaction_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_battle_interaction_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resolve_npc_battle_interaction_and_return { input: ResolveNpcBattleInteractionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resolve_npc_battle_interaction_and_return for super::RemoteProcedures { input: ResolveNpcBattleInteractionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, NpcBattleInteractionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_and_return_procedure.rs index 4604fc30..aaba3d9c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resolve_npc_interaction_and_return { input: ResolveNpcInteractionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resolve_npc_interaction_and_return for super::RemoteProcedures { input: ResolveNpcInteractionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, NpcInteractionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_reducer.rs index 352f5a93..52d213b5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_interaction_reducer.rs @@ -47,11 +47,9 @@ pub trait resolve_npc_interaction { &self, input: ResolveNpcInteractionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl resolve_npc_interaction for super::RemoteReducers { &self, input: ResolveNpcInteractionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ResolveNpcInteractionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_and_return_procedure.rs index 65b1690e..c1425649 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resolve_npc_social_action_and_return { input: ResolveNpcSocialActionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resolve_npc_social_action_and_return for super::RemoteProcedures { input: ResolveNpcSocialActionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, NpcStateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_reducer.rs index 9b326931..28e5ce36 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_npc_social_action_reducer.rs @@ -47,11 +47,9 @@ pub trait resolve_npc_social_action { &self, input: ResolveNpcSocialActionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl resolve_npc_social_action for super::RemoteReducers { &self, input: ResolveNpcSocialActionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ResolveNpcSocialActionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_and_return_procedure.rs index 0b8f6bad..a224c122 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resolve_treasure_interaction_and_return { input: TreasureResolveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resolve_treasure_interaction_and_return for super::RemoteProcedures { input: TreasureResolveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, TreasureRecordProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_reducer.rs index 221ac39d..942b377a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resolve_treasure_interaction_reducer.rs @@ -47,11 +47,9 @@ pub trait resolve_treasure_interaction { &self, input: TreasureResolveInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl resolve_treasure_interaction for super::RemoteReducers { &self, input: TreasureResolveInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(ResolveTreasureInteractionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/restart_jump_hop_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/restart_jump_hop_run_procedure.rs index cde6daca..f88b059c 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/restart_jump_hop_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/restart_jump_hop_run_procedure.rs @@ -31,10 +31,10 @@ pub trait restart_jump_hop_run { input: JumpHopRunRestartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl restart_jump_hop_run for super::RemoteProcedures { input: JumpHopRunRestartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/restart_match_3_d_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/restart_match_3_d_run_procedure.rs index 76c74037..add954d4 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/restart_match_3_d_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/restart_match_3_d_run_procedure.rs @@ -31,10 +31,10 @@ pub trait restart_match_3_d_run { input: Match3DRunRestartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl restart_match_3_d_run for super::RemoteProcedures { input: Match3DRunRestartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/restart_square_hole_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/restart_square_hole_run_procedure.rs index df72d4d3..fe07f147 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/restart_square_hole_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/restart_square_hole_run_procedure.rs @@ -31,10 +31,10 @@ pub trait restart_square_hole_run { input: SquareHoleRunRestartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl restart_square_hole_run for super::RemoteProcedures { input: SquareHoleRunRestartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/resume_profile_save_archive_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/resume_profile_save_archive_and_return_procedure.rs index 73e6d668..957c105f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/resume_profile_save_archive_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/resume_profile_save_archive_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait resume_profile_save_archive_and_return { input: RuntimeProfileSaveArchiveResumeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl resume_profile_save_archive_and_return for super::RemoteProcedures { input: RuntimeProfileSaveArchiveResumeInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileSaveArchiveProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs index fe032926..feb5086e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/revoke_database_migration_operator_procedure.rs @@ -31,10 +31,10 @@ pub trait revoke_database_migration_operator { input: DatabaseMigrationRevokeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl revoke_database_migration_operator for super::RemoteProcedures { input: DatabaseMigrationRevokeOperatorInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, DatabaseMigrationOperatorProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_form_draft_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_form_draft_procedure.rs index 13aff9a3..bd13cb5f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_form_draft_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_form_draft_procedure.rs @@ -31,10 +31,10 @@ pub trait save_puzzle_form_draft { input: PuzzleFormDraftSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_puzzle_form_draft for super::RemoteProcedures { input: PuzzleFormDraftSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_generated_images_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_generated_images_procedure.rs index 870d6d51..85d17456 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_generated_images_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_generated_images_procedure.rs @@ -31,10 +31,10 @@ pub trait save_puzzle_generated_images { input: PuzzleGeneratedImagesSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_puzzle_generated_images for super::RemoteProcedures { input: PuzzleGeneratedImagesSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_ui_background_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_ui_background_procedure.rs index 49750c17..80fa6304 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_ui_background_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/save_puzzle_ui_background_procedure.rs @@ -31,10 +31,10 @@ pub trait save_puzzle_ui_background { input: PuzzleUiBackgroundSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl save_puzzle_ui_background for super::RemoteProcedures { input: PuzzleUiBackgroundSaveInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs index 29d3b91d..6e2ac3ad 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/seed_analytics_date_dimensions_reducer.rs @@ -50,11 +50,9 @@ pub trait seed_analytics_date_dimensions { &self, input: AnalyticsDateDimensionSeedInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl seed_analytics_date_dimensions for super::RemoteReducers { &self, input: AnalyticsDateDimensionSeedInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(SeedAnalyticsDateDimensionsArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/select_puzzle_cover_image_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/select_puzzle_cover_image_procedure.rs index fd4dd93c..9dde8aaa 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/select_puzzle_cover_image_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/select_puzzle_cover_image_procedure.rs @@ -31,10 +31,10 @@ pub trait select_puzzle_cover_image { input: PuzzleSelectCoverImageInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl select_puzzle_cover_image for super::RemoteProcedures { input: PuzzleSelectCoverImageInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs index 63d9fa6b..9507df73 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_message_table.rs @@ -153,7 +153,7 @@ pub trait square_hole_agent_messageQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `SquareHoleAgentMessageRow`. fn square_hole_agent_message(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl square_hole_agent_messageQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs index 057e4469..1f8098b1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_agent_session_table.rs @@ -153,7 +153,7 @@ pub trait square_hole_agent_sessionQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `SquareHoleAgentSessionRow`. fn square_hole_agent_session(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl square_hole_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs index c5cc5256..5809736b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_reducer.rs @@ -47,11 +47,9 @@ pub trait start_ai_task { &self, input: AiTaskStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl start_ai_task for super::RemoteReducers { &self, input: AiTaskStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(StartAiTaskArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs index 24ed5b3f..1d7b7582 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_ai_task_stage_reducer.rs @@ -47,11 +47,9 @@ pub trait start_ai_task_stage { &self, input: AiTaskStageStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl start_ai_task_stage for super::RemoteReducers { &self, input: AiTaskStageStartInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(StartAiTaskStageArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_bark_battle_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_bark_battle_run_procedure.rs index 1fdc1a09..a29ff5e9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_bark_battle_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_bark_battle_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_bark_battle_run { input: BarkBattleRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_bark_battle_run for super::RemoteProcedures { input: BarkBattleRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_big_fish_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_big_fish_run_procedure.rs index 6a149f03..7f3713ab 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_big_fish_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_big_fish_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_big_fish_run { input: BigFishRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_big_fish_run for super::RemoteProcedures { input: BigFishRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_jump_hop_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_jump_hop_run_procedure.rs index 7a52fc9f..c5da3298 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_jump_hop_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_jump_hop_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_jump_hop_run { input: JumpHopRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_jump_hop_run for super::RemoteProcedures { input: JumpHopRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_match_3_d_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_match_3_d_run_procedure.rs index c0a8c8a9..d4126af9 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_match_3_d_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_match_3_d_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_match_3_d_run { input: Match3DRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_match_3_d_run for super::RemoteProcedures { input: Match3DRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_puzzle_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_puzzle_run_procedure.rs index c3d6d457..b6baeb83 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_puzzle_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_puzzle_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_puzzle_run { input: PuzzleRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_puzzle_run for super::RemoteProcedures { input: PuzzleRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_square_hole_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_square_hole_run_procedure.rs index bda9eddd..d85e730b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_square_hole_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_square_hole_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_square_hole_run { input: SquareHoleRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_square_hole_run for super::RemoteProcedures { input: SquareHoleRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_visual_novel_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_visual_novel_run_procedure.rs index fabc598a..98f9cfa0 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_visual_novel_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_visual_novel_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_visual_novel_run { input: VisualNovelRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_visual_novel_run for super::RemoteProcedures { input: VisualNovelRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/start_wooden_fish_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/start_wooden_fish_run_procedure.rs index daf6358e..65fa87c2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/start_wooden_fish_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/start_wooden_fish_run_procedure.rs @@ -31,10 +31,10 @@ pub trait start_wooden_fish_run { input: WoodenFishRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl start_wooden_fish_run for super::RemoteProcedures { input: WoodenFishRunStartInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/stop_match_3_d_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/stop_match_3_d_run_procedure.rs index 630e7a98..f87a63d5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/stop_match_3_d_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/stop_match_3_d_run_procedure.rs @@ -31,10 +31,10 @@ pub trait stop_match_3_d_run { input: Match3DRunStopInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl stop_match_3_d_run for super::RemoteProcedures { input: Match3DRunStopInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/stop_square_hole_run_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/stop_square_hole_run_procedure.rs index 90702e09..076a3af8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/stop_square_hole_run_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/stop_square_hole_run_procedure.rs @@ -31,10 +31,10 @@ pub trait stop_square_hole_run { input: SquareHoleRunStopInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl stop_square_hole_run for super::RemoteProcedures { input: SquareHoleRunStopInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_input_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_input_procedure.rs index e5bbe6b0..8ef444c5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_input_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_input_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_big_fish_input { input: BigFishInputSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_big_fish_input for super::RemoteProcedures { input: BigFishInputSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_message_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_message_procedure.rs index 307d7755..0dbc0118 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_message_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_big_fish_message_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_big_fish_message { input: BigFishMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_big_fish_message for super::RemoteProcedures { input: BigFishMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_custom_world_agent_message_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_custom_world_agent_message_procedure.rs index 5debac19..c5e8def1 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_custom_world_agent_message_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_custom_world_agent_message_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_custom_world_agent_message { input: CustomWorldAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_custom_world_agent_message for super::RemoteProcedures { input: CustomWorldAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentOperationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_match_3_d_agent_message_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_match_3_d_agent_message_procedure.rs index c323ecda..1ceceaf5 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_match_3_d_agent_message_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_match_3_d_agent_message_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_match_3_d_agent_message { input: Match3DAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_match_3_d_agent_message for super::RemoteProcedures { input: Match3DAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs index 208a35a9..3534df7d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_profile_feedback_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_profile_feedback_and_return { input: RuntimeProfileFeedbackSubmissionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_profile_feedback_and_return for super::RemoteProcedures { input: RuntimeProfileFeedbackSubmissionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeProfileFeedbackSubmissionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_agent_message_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_agent_message_procedure.rs index 0d9e94e5..b5b2b090 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_agent_message_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_agent_message_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_puzzle_agent_message { input: PuzzleAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_puzzle_agent_message for super::RemoteProcedures { input: PuzzleAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_leaderboard_entry_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_leaderboard_entry_procedure.rs index 9f72a916..7df24564 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_leaderboard_entry_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_puzzle_leaderboard_entry_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_puzzle_leaderboard_entry { input: PuzzleLeaderboardSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_puzzle_leaderboard_entry for super::RemoteProcedures { input: PuzzleLeaderboardSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_square_hole_agent_message_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_square_hole_agent_message_procedure.rs index bbdbe51d..e740fe61 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_square_hole_agent_message_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_square_hole_agent_message_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_square_hole_agent_message { input: SquareHoleAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_square_hole_agent_message for super::RemoteProcedures { input: SquareHoleAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/submit_visual_novel_agent_message_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/submit_visual_novel_agent_message_procedure.rs index 5e9c93bb..0df949bd 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/submit_visual_novel_agent_message_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/submit_visual_novel_agent_message_procedure.rs @@ -31,10 +31,10 @@ pub trait submit_visual_novel_agent_message { input: VisualNovelAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl submit_visual_novel_agent_message for super::RemoteProcedures { input: VisualNovelAgentMessageSubmitInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelAgentSessionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/swap_puzzle_pieces_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/swap_puzzle_pieces_procedure.rs index f5835607..9c6a1337 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/swap_puzzle_pieces_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/swap_puzzle_pieces_procedure.rs @@ -31,10 +31,10 @@ pub trait swap_puzzle_pieces { input: PuzzleRunSwapInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl swap_puzzle_pieces for super::RemoteProcedures { input: PuzzleRunSwapInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/turn_in_quest_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/turn_in_quest_reducer.rs index 08727f04..4306a47f 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/turn_in_quest_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/turn_in_quest_reducer.rs @@ -47,11 +47,9 @@ pub trait turn_in_quest { &self, input: QuestTurnInInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl turn_in_quest for super::RemoteReducers { &self, input: QuestTurnInInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(TurnInQuestArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_and_return_procedure.rs index 31acccce..b87880a7 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait unpublish_custom_world_profile_and_return { input: CustomWorldProfileUnpublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl unpublish_custom_world_profile_and_return for super::RemoteProcedures { input: CustomWorldProfileUnpublishInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_reducer.rs index 51af927f..05274f62 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/unpublish_custom_world_profile_reducer.rs @@ -50,11 +50,9 @@ pub trait unpublish_custom_world_profile { &self, input: CustomWorldProfileUnpublishInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl unpublish_custom_world_profile for super::RemoteReducers { &self, input: CustomWorldProfileUnpublishInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(UnpublishCustomWorldProfileArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_bark_battle_draft_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_bark_battle_draft_config_procedure.rs index bd9fc421..545ca3f8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_bark_battle_draft_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_bark_battle_draft_config_procedure.rs @@ -31,10 +31,10 @@ pub trait update_bark_battle_draft_config { input: BarkBattleDraftConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_bark_battle_draft_config for super::RemoteProcedures { input: BarkBattleDraftConfigUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, BarkBattleProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_jump_hop_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_jump_hop_work_procedure.rs index 9186048b..c5f246bf 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_jump_hop_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_jump_hop_work_procedure.rs @@ -31,10 +31,10 @@ pub trait update_jump_hop_work { input: JumpHopWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_jump_hop_work for super::RemoteProcedures { input: JumpHopWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, JumpHopWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_match_3_d_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_match_3_d_work_procedure.rs index cdc42782..ea2ee9b4 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_match_3_d_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_match_3_d_work_procedure.rs @@ -31,10 +31,10 @@ pub trait update_match_3_d_work { input: Match3DWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_match_3_d_work for super::RemoteProcedures { input: Match3DWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, Match3DWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_run_pause_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_run_pause_procedure.rs index 3388380c..1679b5ec 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_run_pause_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_run_pause_procedure.rs @@ -31,10 +31,10 @@ pub trait update_puzzle_run_pause { input: PuzzleRunPauseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_puzzle_run_pause for super::RemoteProcedures { input: PuzzleRunPauseInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_work_procedure.rs index 80571241..6710b4da 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_puzzle_work_procedure.rs @@ -31,10 +31,10 @@ pub trait update_puzzle_work { input: PuzzleWorkUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_puzzle_work for super::RemoteProcedures { input: PuzzleWorkUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_square_hole_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_square_hole_work_procedure.rs index 914b3f05..16786527 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_square_hole_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_square_hole_work_procedure.rs @@ -31,10 +31,10 @@ pub trait update_square_hole_work { input: SquareHoleWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_square_hole_work for super::RemoteProcedures { input: SquareHoleWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, SquareHoleWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_visual_novel_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_visual_novel_work_procedure.rs index bb0ccc4e..b6e61e33 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_visual_novel_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_visual_novel_work_procedure.rs @@ -31,10 +31,10 @@ pub trait update_visual_novel_work { input: VisualNovelWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_visual_novel_work for super::RemoteProcedures { input: VisualNovelWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/update_wooden_fish_work_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/update_wooden_fish_work_procedure.rs index 31785275..6b7c03d8 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/update_wooden_fish_work_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/update_wooden_fish_work_procedure.rs @@ -31,10 +31,10 @@ pub trait update_wooden_fish_work { input: WoodenFishWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl update_wooden_fish_work for super::RemoteProcedures { input: WoodenFishWorkUpdateInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, WoodenFishWorkProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_and_return_procedure.rs index be3ff473..abc39bfe 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_chapter_progression_and_return { input: ChapterProgressionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_chapter_progression_and_return for super::RemoteProcedures { input: ChapterProgressionInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, ChapterProgressionProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_reducer.rs index de37e994..0cb4bb7a 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_chapter_progression_reducer.rs @@ -47,11 +47,9 @@ pub trait upsert_chapter_progression { &self, input: ChapterProgressionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl upsert_chapter_progression for super::RemoteReducers { &self, input: ChapterProgressionInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(UpsertChapterProgressionArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_creation_entry_type_config_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_creation_entry_type_config_procedure.rs index 98f1f7fb..32df13cb 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_creation_entry_type_config_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_creation_entry_type_config_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_creation_entry_type_config { input: CreationEntryTypeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_creation_entry_type_config for super::RemoteProcedures { input: CreationEntryTypeAdminUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CreationEntryConfigProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_agent_operation_progress_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_agent_operation_progress_procedure.rs index 6d8e39a2..554b95b2 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_agent_operation_progress_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_agent_operation_progress_procedure.rs @@ -34,10 +34,10 @@ pub trait upsert_custom_world_agent_operation_progress { input: CustomWorldAgentOperationProgressInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -47,10 +47,10 @@ impl upsert_custom_world_agent_operation_progress for super::RemoteProcedures { input: CustomWorldAgentOperationProgressInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldAgentOperationProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_and_return_procedure.rs index a761ab95..343e1807 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_custom_world_profile_and_return { input: CustomWorldProfileUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_custom_world_profile_and_return for super::RemoteProcedures { input: CustomWorldProfileUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, CustomWorldLibraryMutationResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_reducer.rs index 91ca2652..e343b491 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_custom_world_profile_reducer.rs @@ -50,11 +50,9 @@ pub trait upsert_custom_world_profile { &self, input: CustomWorldProfileUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -63,11 +61,9 @@ impl upsert_custom_world_profile for super::RemoteReducers { &self, input: CustomWorldProfileUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(UpsertCustomWorldProfileArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_and_return_procedure.rs index 91ba0d0e..b7f3a28d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_npc_state_and_return { input: NpcStateUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_npc_state_and_return for super::RemoteProcedures { input: NpcStateUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, NpcStateProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_reducer.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_reducer.rs index afbe61f8..f363770d 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_reducer.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_npc_state_reducer.rs @@ -47,11 +47,9 @@ pub trait upsert_npc_state { &self, input: NpcStateUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()>; } @@ -60,11 +58,9 @@ impl upsert_npc_state for super::RemoteReducers { &self, input: NpcStateUpsertInput, - callback: impl FnOnce( - &super::ReducerEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, + callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) + + Send + + 'static, ) -> __sdk::Result<()> { self.imp .invoke_reducer_with_callback(UpsertNpcStateArgs { input }, callback) diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_platform_browse_history_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_platform_browse_history_and_return_procedure.rs index 36e5f464..614a6d05 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_platform_browse_history_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_platform_browse_history_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_platform_browse_history_and_return { input: RuntimeBrowseHistorySyncInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_platform_browse_history_and_return for super::RemoteProcedures { input: RuntimeBrowseHistorySyncInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeBrowseHistoryProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs index f8fa0351..119eab70 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_setting_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_runtime_setting_and_return { input: RuntimeSettingUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_runtime_setting_and_return for super::RemoteProcedures { input: RuntimeSettingUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSettingProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_snapshot_and_return_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_snapshot_and_return_procedure.rs index fe0746ba..eceae785 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_snapshot_and_return_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_runtime_snapshot_and_return_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_runtime_snapshot_and_return { input: RuntimeSnapshotUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_runtime_snapshot_and_return for super::RemoteProcedures { input: RuntimeSnapshotUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, RuntimeSnapshotProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/upsert_visual_novel_run_snapshot_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/upsert_visual_novel_run_snapshot_procedure.rs index 8cc89e85..35722b1e 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/upsert_visual_novel_run_snapshot_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/upsert_visual_novel_run_snapshot_procedure.rs @@ -31,10 +31,10 @@ pub trait upsert_visual_novel_run_snapshot { input: VisualNovelRunSnapshotUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl upsert_visual_novel_run_snapshot for super::RemoteProcedures { input: VisualNovelRunSnapshotUpsertInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, VisualNovelRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/use_puzzle_runtime_prop_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/use_puzzle_runtime_prop_procedure.rs index 1e2dbe13..45bd3a73 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/use_puzzle_runtime_prop_procedure.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/use_puzzle_runtime_prop_procedure.rs @@ -31,10 +31,10 @@ pub trait use_puzzle_runtime_prop { input: PuzzleRunPropInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ); } @@ -44,10 +44,10 @@ impl use_puzzle_runtime_prop for super::RemoteProcedures { input: PuzzleRunPropInput, __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, - ) + Send - + 'static, + &super::ProcedureEventContext, + Result, + ) + Send + + 'static, ) { self.imp .invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>( diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs index a1f70563..1b393127 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs @@ -105,7 +105,7 @@ pub trait visual_novel_gallery_viewQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `VisualNovelGalleryViewRow`. fn visual_novel_gallery_view(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl visual_novel_gallery_viewQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs index 24682e11..55371a46 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_work_profile_table.rs @@ -153,7 +153,7 @@ pub trait visual_novel_work_profileQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `VisualNovelWorkProfileRow`. fn visual_novel_work_profile(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl visual_novel_work_profileQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs index 68f2e484..2b9e7d58 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/wooden_fish_agent_session_table.rs @@ -153,7 +153,7 @@ pub trait wooden_fish_agent_sessionQueryTableAccess { #[allow(non_snake_case)] /// Get a query builder for the table `WoodenFishAgentSessionRow`. fn wooden_fish_agent_session(&self) - -> __sdk::__query_builder::Table; + -> __sdk::__query_builder::Table; } impl wooden_fish_agent_sessionQueryTableAccess for __sdk::QueryTableAccessor { diff --git a/vite.config.ts b/vite.config.ts index ac0b1e69..7ed4ac21 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,6 +7,8 @@ import {defineConfig, loadEnv} from 'vite'; export default defineConfig(({mode}) => { const env = loadEnv(mode, __dirname, ''); const ignoredWatchGlobs = [ + '**/.git/**', + '**/.worktrees/**', '**/dist/**', '**/dist_check/**', '**/dist_check_final/**', @@ -22,6 +24,7 @@ export default defineConfig(({mode}) => { '**/media/**', '**/scripts/**', '**/server-rs/**', + '**/server-rs/target/**', '**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', From 26975644b5cd43cc52a6ec0eebbab4c8ba9b40dc Mon Sep 17 00:00:00 2001 From: kdletters Date: Sat, 30 May 2026 05:05:02 +0800 Subject: [PATCH 04/31] feat: unify phase one creation flow --- .gitignore | 1 + .hermes/shared-memory/development-workflow.md | 5 + ...发运维】本地开发验证与生产运维-2026-05-15.md | 4 + ...玩法创作】平台入口与玩法链路-2026-05-15.md | 4 +- quality-gates/README.md | 18 + ...发运维】dev-stack状态文件门禁-2026-05-29.md | 16 + .../【玩法创作】统一创作页门禁-2026-05-29.md | 16 + .../【玩法创作】统一生成页门禁-2026-05-29.md | 16 + scripts/dev.mjs | 287 +++++++- scripts/dev.test.ts | 75 +++ .../api-server/src/edutainment_baby_object.rs | 1 + .../crates/api-server/src/match3d/draft.rs | 110 ++- .../crates/api-server/src/match3d/mappers.rs | 41 ++ .../crates/api-server/src/match3d/tests.rs | 42 ++ server-rs/crates/api-server/src/state.rs | 4 + .../crates/api-server/src/wooden_fish.rs | 121 +++- .../crates/module-runtime/src/application.rs | 32 +- .../src/creation_entry_config.rs | 109 +++ .../src/mapper/wooden_fish.rs | 38 +- .../spacetime-client/src/wooden_fish.rs | 179 ++++- .../spacetime-module/src/wooden_fish.rs | 3 + .../spacetime-module/src/wooden_fish/types.rs | 1 + .../common/CreativeAudioInputPanel.tsx | 206 ++++++ .../PlatformEntryFlowShellImpl.tsx | 637 ++++++++++-------- .../UnifiedCreationPage.test.tsx | 42 ++ .../unified-creation/UnifiedCreationPage.tsx | 44 ++ .../UnifiedGenerationPage.test.tsx | 53 ++ .../UnifiedGenerationPage.tsx | 91 +++ .../unifiedCreationSpecs.test.ts | 42 ++ .../unified-creation/unifiedCreationSpecs.ts | 107 +++ .../WoodenFishWorkspace.tsx | 187 +---- src/services/creationEntryConfigService.ts | 23 + .../miniGameDraftGenerationProgress.ts | 21 +- 33 files changed, 2037 insertions(+), 539 deletions(-) create mode 100644 quality-gates/README.md create mode 100644 quality-gates/【开发运维】dev-stack状态文件门禁-2026-05-29.md create mode 100644 quality-gates/【玩法创作】统一创作页门禁-2026-05-29.md create mode 100644 quality-gates/【玩法创作】统一生成页门禁-2026-05-29.md create mode 100644 src/components/common/CreativeAudioInputPanel.tsx create mode 100644 src/components/unified-creation/UnifiedCreationPage.test.tsx create mode 100644 src/components/unified-creation/UnifiedCreationPage.tsx create mode 100644 src/components/unified-creation/UnifiedGenerationPage.test.tsx create mode 100644 src/components/unified-creation/UnifiedGenerationPage.tsx create mode 100644 src/components/unified-creation/unifiedCreationSpecs.test.ts create mode 100644 src/components/unified-creation/unifiedCreationSpecs.ts diff --git a/.gitignore b/.gitignore index c90efe5c..2885233d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ temp*build*/ /public/generated-character-drafts /public/generated-characters /.codex-temp +/.app/ /target/ /logs /server-rs/crates/*/logs/ diff --git a/.hermes/shared-memory/development-workflow.md b/.hermes/shared-memory/development-workflow.md index 3710e85b..23e61f20 100644 --- a/.hermes/shared-memory/development-workflow.md +++ b/.hermes/shared-memory/development-workflow.md @@ -57,6 +57,8 @@ npm run dev - 主站 Vite - 后台 Vite +`npm run dev` 和单模块 `dev:*` 命令会更新根目录 `.app/dev-stack.json`,记录四个本地服务的 pid、端口、URL、启动状态和当前命令。该目录只作本机运行态观测,不提交 Git。 + 开启自动刷新: ```bash @@ -240,6 +242,7 @@ npm run check:server-rs-ddd - 移动端优先,再兼容网页端。 - 页面只展示后端返回的状态,不自行计算结论型业务状态。 - 创作中心入口配置事实源在 SpacetimeDB,通过 `GET /api/creation-entry/config` 下发;前端只在 `platformEntryCreationTypes.ts` 做展示派生,api-server 路由熔断也使用同一份配置,禁止恢复前端硬编码入口配置文件。 +- 一期统一创作页字段 spec 同样跟随 `GET /api/creation-entry/config`,由 `creationTypes[].unifiedCreationSpec` 下发;拼图、抓大鹅、敲木鱼之外的模板不接入该扩展位,前端只保留旧后端缺字段时的兜底默认。 - 优先复用现有面板、抽屉、弹窗,不新建独立大系统。 - 不在 UI 中默认写功能说明类文本。 - 弹出独立面板的交互不要实现成在当前面板下方追加内容。 @@ -253,6 +256,8 @@ npm run check:server-rs-ddd ## 提交前建议让 Hermes 执行 +涉及拼图、抓大鹅、敲木鱼统一创作 / 生成链路或本地 dev 栈时,先按 `quality-gates/README.md` 和对应门禁文档执行自动脚本与体验检查。 + ```text 请检查当前 git diff,指出: 1. 是否违反 AGENTS.md 或 .hermes/shared-memory 约定; diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index befe256c..d04666dd 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -31,6 +31,8 @@ npm run dev - 主站 Vite。 - 后台 Vite。 +`npm run dev` 和单模块 `npm run dev:web`、`npm run dev:api-server`、`npm run dev:spacetime`、`npm run dev:admin-web` 启动后都会更新根目录 `.app/dev-stack.json`。该文件记录本次命令、数据库、更新时间,以及 `spacetime`、`api-server`、`web`、`admin-web` 的 `pid`、监听 host / port、可访问 URL、启动状态和当前命令。`.app/` 是本地运行态目录,不提交 Git;端口漂移、服务重启或子进程退出后以该文件里的实际状态为准。 + 单独启动主站前端: ```bash @@ -90,6 +92,8 @@ npm run build npm run check:content ``` +一期创作流程统一化新增 `quality-gates/` 提交前门禁。涉及拼图、抓大鹅、敲木鱼统一创作页、统一生成页或 dev 栈启动脚本时,先执行 `quality-gates/README.md` 列出的脚本,再按对应门禁文档完成体验检查。 + 综合检查: ```bash diff --git a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md index d5207f03..203eb5b1 100644 --- a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md +++ b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md @@ -8,7 +8,9 @@ 当前创作 Tab 只承载赛事 banner、玩法模板分类和两列模板卡;点击模板卡后直接进入对应玩法已有的入口创作表单 stage,不再经过空白占位页,也不把旧表单嵌进创作 Tab 首屏。移动端创作 Tab 顶栏在 `陶泥儿` 品牌同一行显示真实账户泥点数,数据来自 `profileDashboard.walletBalance`,不得再把活动奖池当作账号余额展示。首屏 banner 结构按参考图拆成横向可滑动赛事卡、主体宣传图文区、奖池胶囊、开始 / 结束时间条和卡片内分页点;轮播只保留 `拼图主题创作赛` 和 `抓大鹅主题创作赛`,两个主题赛事奖池均为 `1000` 泥点数。玩法列表不再套外部边框卡片,移动端需要压缩横向边距和两列间距;玩法卡统一按“上图、左上状态标签(仅非开放态显示)、封面右下 `10-20泥点数`、下方白底标题/描述”结构展示,卡片高度保持紧凑但标题、描述和预估消耗点数都必须可见。创作 Tab 根容器不再使用 `platform-page-stage` 这类全局内容卡片壳,但继续保留 `platform-remap-surface` 作为主题和输入框样式命中钩子。创作首屏字号需要对齐平台普通 UI 档位:顶栏泥点组件、banner 正文、分类 Tab 和玩法卡标题 / 副标题 / 消耗说明优先使用 `11px` 到 `14px`,不使用 `text-lg`、`text-xl` 或更大的展示级字号。草稿 Tab 继续承接作品架。RPG、RPG 之外的各玩法入口分别落到既有的 `agent-workspace`、`big-fish-agent-workspace`、`match3d-agent-workspace`、`square-hole-agent-workspace`、`jump-hop-workspace`、`wooden-fish-workspace`、`puzzle-agent-workspace`、`bark-battle-workspace`、`visual-novel-agent-workspace`、`baby-object-match-workspace`,这些入口继续承接各玩法自己的表单、草稿恢复和后续编排,不作为创作 Tab 首屏内容。 -创作恢复参数只保留 `sessionId`、`profileId`、`draftId`、`workId` 这四个私有 query。它们只允许在同一条创作链路的结果页、生成页、工作台之间保留;切到首页、公开作品详情、runtime 或另一条玩法链路时必须清掉。生成页恢复时只认当前进入页的时间作为新的 `startedAtMs`,作品摘要里的 `updatedAt` 只用于排序与摘要展示,不再作为生成进度起点。 +创作恢复参数只保留 `sessionId`、`profileId`、`draftId`、`workId` 这四个私有 query。它们只允许在同一条创作链路的结果页、生成页、工作台之间保留;切到首页、公开作品详情、runtime 或另一条玩法链路时必须清掉。生成页等待时间统一以生成状态里的 `startedAtMs` 为准;创建该状态时优先使用后端 session 下发的时间戳,作品摘要里的 `updatedAt` 仍只用于排序与摘要展示,不作为前端自行推导业务状态的真相。 + +一期创作流程统一化只覆盖拼图、抓大鹅和敲木鱼。三者在前端统一经过 `UnifiedCreationPage` 和 `UnifiedGenerationPage`:创作页字段清单由后端在 `GET /api/creation-entry/config` 的 `creationTypes[].unifiedCreationSpec` 下发,前端仅在该扩展位缺失时回退到本地默认 spec;首期字段类型只保留 `text`、`select`、`image`、`audio`。生成页统一展示阶段、当前步骤、总进度、错误和重试动作。视觉小说、`airp`、`component`、汪汪声浪、方洞、大鱼、跳一跳和宝贝识物不进入一期接线范围,已有链路保持现状。 创作表单提交前的泥点余额前置校验只允许用独立弹窗提示失败原因,不得把用户退回创作入口或玩法模板列表,也不得清空当前表单状态。当前适用拼图、抓大鹅和汪汪声浪等会在前端提交前校验泥点的生成入口;余额不足、余额读取失败都应停留在当前工作台,由用户关闭提示后继续编辑或自行补足泥点。 diff --git a/quality-gates/README.md b/quality-gates/README.md new file mode 100644 index 00000000..9fe983fe --- /dev/null +++ b/quality-gates/README.md @@ -0,0 +1,18 @@ +# 提交前质量门禁 + +本目录记录一期创作流程统一化提交前必须执行的检查。门禁既可以是自动脚本,也可以是需要人工确认的体验流程。 + +## 一期必跑 + +- [【玩法创作】统一创作页门禁-2026-05-29.md](./【玩法创作】统一创作页门禁-2026-05-29.md) +- [【玩法创作】统一生成页门禁-2026-05-29.md](./【玩法创作】统一生成页门禁-2026-05-29.md) +- [【开发运维】dev-stack状态文件门禁-2026-05-29.md](./【开发运维】dev-stack状态文件门禁-2026-05-29.md) + +## 基线脚本 + +```bash +npm run check:encoding +npm run test -- src/components/unified-creation/unifiedCreationSpecs.test.ts src/components/unified-creation/UnifiedGenerationPage.test.tsx +npm run test -- scripts/dev.test.ts +node --check scripts/dev.mjs +``` diff --git a/quality-gates/【开发运维】dev-stack状态文件门禁-2026-05-29.md b/quality-gates/【开发运维】dev-stack状态文件门禁-2026-05-29.md new file mode 100644 index 00000000..b136321b --- /dev/null +++ b/quality-gates/【开发运维】dev-stack状态文件门禁-2026-05-29.md @@ -0,0 +1,16 @@ +# dev-stack 状态文件门禁 + +## 自动检查 + +```bash +node --check scripts/dev.mjs +npm run test -- scripts/dev.test.ts +``` + +## 体验检查 + +- `npm run dev` 启动后根目录生成 `.app/dev-stack.json`。 +- `npm run dev:web`、`npm run dev:api-server`、`npm run dev:spacetime`、`npm run dev:admin-web` 单独启动时会更新对应服务状态。 +- 文件包含 `schemaVersion`、`command`、`repoRoot`、`database`、`updatedAt` 和四个服务条目。 +- 每个服务条目包含 `status`、`pid`、`host`、`port`、`url`、`command`、`updatedAt`。 +- 端口漂移后文件记录实际端口;服务退出或重启后 PID 与状态会更新。 diff --git a/quality-gates/【玩法创作】统一创作页门禁-2026-05-29.md b/quality-gates/【玩法创作】统一创作页门禁-2026-05-29.md new file mode 100644 index 00000000..bd3d7d6c --- /dev/null +++ b/quality-gates/【玩法创作】统一创作页门禁-2026-05-29.md @@ -0,0 +1,16 @@ +# 统一创作页门禁 + +## 自动检查 + +```bash +npm run test -- src/components/unified-creation/unifiedCreationSpecs.test.ts +npm run test -- src/components/wooden-fish-creation/WoodenFishWorkspace.test.tsx +``` + +## 体验检查 + +- 拼图、抓大鹅、敲木鱼均从 `/creation/` 进入创作工作台。 +- 三条链路都经过 `UnifiedCreationPage`,字段 spec 只包含 `text`、`select`、`image`、`audio` 四类。 +- 拼图参考图仍走 `CreativeImageInputPanel`,不新增专属上传入口。 +- 敲木鱼音频槽位走 `CreativeAudioInputPanel`,上传、录音、重置和默认音效状态可用。 +- 抓大鹅难度只显示轻松、标准、进阶、硬核四档,提交 payload 仍派生 `clearCount` 和 `difficulty`。 diff --git a/quality-gates/【玩法创作】统一生成页门禁-2026-05-29.md b/quality-gates/【玩法创作】统一生成页门禁-2026-05-29.md new file mode 100644 index 00000000..97626cb0 --- /dev/null +++ b/quality-gates/【玩法创作】统一生成页门禁-2026-05-29.md @@ -0,0 +1,16 @@ +# 统一生成页门禁 + +## 自动检查 + +```bash +npm run test -- src/components/unified-creation/UnifiedGenerationPage.test.tsx +npm run test -- src/services/miniGameDraftGenerationProgress.test.ts +``` + +## 体验检查 + +- `/creation/puzzle/generating`、`/creation/match3d/generating`、`/creation/wooden-fish/generating` 均渲染 `UnifiedGenerationPage`。 +- 生成页展示后端阶段、当前步骤、总进度、错误和重试动作。 +- 等待时间以生成状态里的 `startedAtMs` 为准;创建该状态时优先使用后端 session 时间戳。 +- 失败后生成页保持可见错误和重试入口,作品架恢复时不得只依赖前端内存 notice。 +- 不为一期新增客户端直连 SpacetimeDB 状态通道。 diff --git a/scripts/dev.mjs b/scripts/dev.mjs index 13cbb831..91955c8c 100644 --- a/scripts/dev.mjs +++ b/scripts/dev.mjs @@ -26,6 +26,7 @@ import { } from './dev-utils.mjs'; const repoRoot = process.cwd(); +const devStackStatePath = resolve(repoRoot, '.app/dev-stack.json'); const serverRsDir = resolve(repoRoot, 'server-rs'); const manifestPath = resolve(serverRsDir, 'Cargo.toml'); const modulePath = resolve(serverRsDir, 'crates/spacetime-module'); @@ -245,6 +246,136 @@ function normalizeServiceName(rawName) { throw new Error(`未知模块: ${rawName}`); } +function resolveDevStackStatePath(root = repoRoot) { + return resolve(root, '.app/dev-stack.json'); +} + +function buildDevStackSnapshot(runner, updatedAt = new Date().toISOString()) { + const services = {}; + for (const serviceName of SERVICE_NAMES) { + services[serviceName] = buildDevStackServiceSnapshot( + runner, + serviceName, + updatedAt, + ); + } + + return { + schemaVersion: 1, + command: runner.command ?? 'all', + repoRoot, + database: runner.options.database, + watch: Boolean(runner.options.watch), + updatedAt, + services, + }; +} + +function buildDevStackServiceSnapshot(runner, serviceName, updatedAt) { + const service = runner.services.get(serviceName); + const runtime = service?.runtime ?? {}; + const endpoint = resolveDevStackServiceEndpoint(runner, serviceName); + const isReusedSpacetime = + serviceName === 'spacetime' && runner.state.spacetimeReused; + const runtimeStatus = runtime.status ?? 'idle'; + const status = + runtimeStatus === 'idle' && isReusedSpacetime ? 'reused' : runtimeStatus; + const childPid = + service?.child && Number.isInteger(service.child.pid) + ? service.child.pid + : null; + + return { + status, + pid: + childPid ?? + runtime.pid ?? + (isReusedSpacetime ? (runner.state.spacetimePid ?? null) : null), + host: runtime.host ?? endpoint.host, + port: runtime.port ?? endpoint.port, + url: runtime.url ?? endpoint.url, + command: runtime.command ?? resolveDevStackServiceCommand(runner, serviceName), + startedAt: runtime.startedAt ?? null, + updatedAt: runtime.updatedAt ?? updatedAt, + exitCode: runtime.exitCode ?? null, + signal: runtime.signal ?? null, + }; +} + +function resolveDevStackServiceEndpoint(runner, serviceName) { + const {options, state} = runner; + switch (serviceName) { + case 'spacetime': + return { + host: options.spacetimeHost, + port: options.spacetimePort, + url: state.spacetimeServer, + }; + case 'api-server': + return { + host: options.apiHost, + port: options.apiPort, + url: state.apiTarget, + }; + case 'web': + return { + host: options.webHost, + port: options.webPort, + url: `http://${resolveClientHost(options.webHost)}:${options.webPort}`, + }; + case 'admin-web': + return { + host: options.adminWebHost, + port: options.adminWebPort, + url: `http://${state.adminWebTargetHost}:${options.adminWebPort}/admin/`, + }; + default: + return { + host: null, + port: null, + url: null, + }; + } +} + +function resolveDevStackServiceCommand(runner, serviceName) { + const {options, state} = runner; + switch (serviceName) { + case 'spacetime': + return state.spacetimeReused + ? `reuse spacetime standalone ${state.spacetimeServer}` + : [ + 'spacetime', + 'start', + '--data-dir', + options.spacetimeDataDir, + '--listen-addr', + `${options.spacetimeHost}:${options.spacetimePort}`, + '--non-interactive', + ].join(' '); + case 'api-server': + return 'cargo run -p api-server --manifest-path server-rs/Cargo.toml'; + case 'web': + return [ + 'node', + relative(repoRoot, viteCliPath), + `--port=${options.webPort}`, + `--host=${options.webHost}`, + '--strictPort', + ].join(' '); + case 'admin-web': + return [ + 'node', + relative(adminWebDir, viteCliPath), + `--host=${options.adminWebHost}`, + `--port=${options.adminWebPort}`, + '--strictPort', + ].join(' '); + default: + return null; + } +} + function requireCommand(command) { const result = spawnSync(command, ['--version'], { cwd: repoRoot, @@ -374,14 +505,37 @@ function ensureRequiredFiles(command) { } class DevService { - constructor(name, startFn) { + constructor(name, startFn, onStateChange = null) { this.name = name; this.startFn = startFn; + this.onStateChange = onStateChange; this.child = null; this.children = []; this.logStream = null; this.stopping = false; this.restartTimer = null; + this.runtime = { + status: 'idle', + pid: null, + host: null, + port: null, + url: null, + command: null, + startedAt: null, + updatedAt: null, + exitCode: null, + signal: null, + }; + } + + updateRuntimeState(patch) { + const updatedAt = new Date().toISOString(); + this.runtime = { + ...this.runtime, + ...patch, + updatedAt, + }; + this.onStateChange?.(); } async start() { @@ -389,17 +543,36 @@ class DevService { return; } - await this.startFn(this); + this.updateRuntimeState({status: 'starting', exitCode: null, signal: null}); + try { + await this.startFn(this); + } catch (error) { + this.updateRuntimeState({status: 'failed', pid: null}); + throw error; + } } registerChild(child) { this.child = child; + this.updateRuntimeState({ + status: 'running', + pid: Number.isInteger(child.pid) ? child.pid : null, + exitCode: null, + signal: null, + startedAt: this.runtime.startedAt ?? new Date().toISOString(), + }); child.on('exit', (code, signal) => { if (this.logStream && !this.logStream.destroyed) { this.logStream.end(); } this.child = null; + this.updateRuntimeState({ + status: this.stopping ? 'stopped' : code === 0 ? 'stopped' : 'failed', + pid: null, + exitCode: code ?? null, + signal: signal ?? null, + }); if (this.stopping) { this.stopping = false; return; @@ -418,6 +591,9 @@ class DevService { const processes = [this.child, ...this.children].filter(Boolean); this.stopping = processes.length > 0; + if (processes.length > 0) { + this.updateRuntimeState({status: 'stopping'}); + } this.child = null; this.children = []; @@ -430,6 +606,9 @@ class DevService { } this.logStream = null; this.stopping = false; + if (processes.length > 0) { + this.updateRuntimeState({status: 'stopped', pid: null}); + } } scheduleRestart(delayMs = 250, restartFn = null, actionLabel = '重启') { @@ -576,6 +755,7 @@ class DevRunner { await this.resolvePorts(command); this.registerServices(); this.printSummary(command); + this.writeDevStackState(); } shouldValidateSpacetimeToolVersion(command) { @@ -642,6 +822,9 @@ class DevRunner { } this.state.spacetimeServer = candidate; this.state.spacetimeReused = true; + this.state.spacetimePid = Number.isInteger(pidState.pid) + ? pidState.pid + : null; const pidLabel = Number.isInteger(pidState.pid) ? ` pid=${pidState.pid}` : ''; console.log(`[dev:spacetime] 复用已启动实例${pidLabel}: ${candidate}`); return; @@ -727,19 +910,48 @@ class DevRunner { } registerServices() { + const onStateChange = () => this.writeDevStackState(); this.services.set( 'spacetime', - new DevService('spacetime', async (service) => this.startSpacetime(service)), + new DevService( + 'spacetime', + async (service) => this.startSpacetime(service), + onStateChange, + ), ); this.services.set( 'api-server', - new DevService('api-server', async (service) => this.startApiServer(service)), + new DevService( + 'api-server', + async (service) => this.startApiServer(service), + onStateChange, + ), + ); + this.services.set( + 'web', + new DevService('web', async (service) => this.startWeb(service), onStateChange), ); - this.services.set('web', new DevService('web', async (service) => this.startWeb(service))); this.services.set( 'admin-web', - new DevService('admin-web', async (service) => this.startAdminWeb(service)), + new DevService( + 'admin-web', + async (service) => this.startAdminWeb(service), + onStateChange, + ), ); + + if (this.state.spacetimeReused) { + const spacetimeService = this.services.get('spacetime'); + const endpoint = resolveDevStackServiceEndpoint(this, 'spacetime'); + spacetimeService?.updateRuntimeState({ + status: 'reused', + pid: this.state.spacetimePid ?? null, + host: endpoint.host, + port: endpoint.port, + url: endpoint.url, + command: resolveDevStackServiceCommand(this, 'spacetime'), + }); + } } printSummary(command) { @@ -754,6 +966,16 @@ class DevRunner { console.log(`[dev] database: ${options.database}`); } + writeDevStackState() { + try { + ensureParentDir(devStackStatePath); + const snapshot = buildDevStackSnapshot(this); + writeFileSync(devStackStatePath, `${JSON.stringify(snapshot, null, 2)}\n`, 'utf8'); + } catch (error) { + console.warn(`[dev] 写入 ${devStackStatePath} 失败: ${error.message}`); + } + } + async startCommand(command) { if (command === 'all') { await this.startSpacetimeForFullStack(); @@ -827,6 +1049,17 @@ class DevRunner { ); console.log(`[dev:spacetime] log: ${logFile}`); + service.updateRuntimeState({ + status: 'starting', + pid: null, + host: options.spacetimeHost, + port: options.spacetimePort, + url: this.state.spacetimeServer, + command: resolveDevStackServiceCommand(this, 'spacetime'), + startedAt: new Date().toISOString(), + exitCode: null, + signal: null, + }); const env = { ...this.baseEnv, }; @@ -880,6 +1113,11 @@ class DevRunner { this.options.spacetimePort = port; this.state.spacetimeServer = `http://${this.options.spacetimeHost}:${port}`; recordSpacetimeUrl(this.options.spacetimeDataDir, this.state.spacetimeServer); + this.services.get('spacetime')?.updateRuntimeState({ + host: this.options.spacetimeHost, + port, + url: this.state.spacetimeServer, + }); console.log(`[dev:spacetime] actual: ${this.state.spacetimeServer}`); } @@ -976,6 +1214,17 @@ class DevRunner { console.log( `[dev:api-server] SpacetimeDB ${this.options.database} @ ${this.state.spacetimeServer}`, ); + service.updateRuntimeState({ + status: 'starting', + pid: null, + host: this.options.apiHost, + port: this.options.apiPort, + url: this.state.apiTarget, + command: resolveDevStackServiceCommand(this, 'api-server'), + startedAt: new Date().toISOString(), + exitCode: null, + signal: null, + }); const child = spawn( 'cargo', @@ -1018,6 +1267,7 @@ class DevRunner { startWeb(service) { const apiTarget = this.resolveFrontendApiTarget(); + const endpoint = resolveDevStackServiceEndpoint(this, 'web'); const env = { ...this.baseEnv, RUST_SERVER_TARGET: apiTarget, @@ -1028,6 +1278,17 @@ class DevRunner { }; console.log(`[dev:web] api target: ${apiTarget}`); + service.updateRuntimeState({ + status: 'starting', + pid: null, + host: endpoint.host, + port: endpoint.port, + url: endpoint.url, + command: resolveDevStackServiceCommand(this, 'web'), + startedAt: new Date().toISOString(), + exitCode: null, + signal: null, + }); const child = spawn( 'node', [ @@ -1053,6 +1314,7 @@ class DevRunner { startAdminWeb(service) { const apiTarget = this.resolveFrontendApiTarget({admin: true}); + const endpoint = resolveDevStackServiceEndpoint(this, 'admin-web'); const env = { ...this.baseEnv, ADMIN_API_TARGET: apiTarget, @@ -1061,6 +1323,17 @@ class DevRunner { }; console.log(`[dev:admin-web] api target: ${apiTarget}`); + service.updateRuntimeState({ + status: 'starting', + pid: null, + host: endpoint.host, + port: endpoint.port, + url: endpoint.url, + command: resolveDevStackServiceCommand(this, 'admin-web'), + startedAt: new Date().toISOString(), + exitCode: null, + signal: null, + }); const child = spawn( 'node', [ @@ -1731,12 +2004,14 @@ export { assertReusableSpacetimeProcessVersionMatchesWorkspace, assertSpacetimeToolVersionMatchesWorkspace, buildApiServerProcessEnv, + buildDevStackSnapshot, buildSpacetimePublishArgs, createDevServerSpawnOptions, createWatchConfigs, isSpacetimePublishPermissionError, parseSpacetimeToolVersion, parseArgs, + resolveDevStackStatePath, shouldAcceptWatchEvent, }; diff --git a/scripts/dev.test.ts b/scripts/dev.test.ts index 341cde80..b281dd43 100644 --- a/scripts/dev.test.ts +++ b/scripts/dev.test.ts @@ -9,12 +9,14 @@ import { assertReusableSpacetimeProcessVersionMatchesWorkspace, assertSpacetimeToolVersionMatchesWorkspace, buildApiServerProcessEnv, + buildDevStackSnapshot, buildSpacetimePublishArgs, createDevServerSpawnOptions, createWatchConfigs, isSpacetimePublishPermissionError, parseSpacetimeToolVersion, parseArgs, + resolveDevStackStatePath, shouldAcceptWatchEvent, } from './dev.mjs'; @@ -105,6 +107,79 @@ describe('dev scheduler api-server env', () => { }); }); +describe('dev scheduler stack state file', () => { + test('状态文件路径固定在根目录 .app/dev-stack.json', () => { + expect(resolveDevStackStatePath('C:\\repo\\Genarrative')).toBe( + join('C:\\repo\\Genarrative', '.app/dev-stack.json'), + ); + }); + + test('状态快照记录服务 pid、端口、URL 和当前命令', () => { + const updatedAt = '2026-05-29T00:00:00.000Z'; + const runner = { + command: 'web', + options: { + apiHost: '127.0.0.1', + apiPort: 8090, + webHost: '0.0.0.0', + webPort: 3010, + adminWebHost: '127.0.0.1', + adminWebPort: 3110, + spacetimeHost: '127.0.0.1', + spacetimePort: 3120, + spacetimeDataDir: 'server-rs/.spacetimedb/local/data', + database: 'genarrative-test', + watch: false, + }, + state: { + apiTarget: 'http://127.0.0.1:8090', + adminWebTargetHost: '127.0.0.1', + spacetimeServer: 'http://127.0.0.1:3120', + }, + services: new Map([ + [ + 'web', + { + child: {pid: 4321}, + runtime: { + status: 'running', + pid: 4321, + host: '0.0.0.0', + port: 3010, + url: 'http://127.0.0.1:3010', + command: 'node scripts/vite-cli.mjs --port=3010', + startedAt: updatedAt, + updatedAt, + exitCode: null, + signal: null, + }, + }, + ], + ]), + }; + + const snapshot = buildDevStackSnapshot(runner, updatedAt); + + expect(snapshot.schemaVersion).toBe(1); + expect(snapshot.command).toBe('web'); + expect(snapshot.database).toBe('genarrative-test'); + expect(snapshot.services.web).toMatchObject({ + status: 'running', + pid: 4321, + host: '0.0.0.0', + port: 3010, + url: 'http://127.0.0.1:3010', + command: 'node scripts/vite-cli.mjs --port=3010', + }); + expect(snapshot.services['api-server']).toMatchObject({ + status: 'idle', + pid: null, + port: 8090, + url: 'http://127.0.0.1:8090', + }); + }); +}); + describe('dev scheduler spacetime reuse guard', () => { test('记录 URL 可 ping 但没有 spacetime.pid 时不复用宿主', async () => { const tempDir = mkdtempSync(join(tmpdir(), 'genarrative-spacetime-reuse-')); diff --git a/server-rs/crates/api-server/src/edutainment_baby_object.rs b/server-rs/crates/api-server/src/edutainment_baby_object.rs index dda85bf5..abfb5349 100644 --- a/server-rs/crates/api-server/src/edutainment_baby_object.rs +++ b/server-rs/crates/api-server/src/edutainment_baby_object.rs @@ -1052,6 +1052,7 @@ mod tests { external_api_audit_state: None, external_api_audit_user_id: None, external_api_audit_profile_id: None, + external_api_audit_request_id: None, }); assert_eq!( diff --git a/server-rs/crates/api-server/src/match3d/draft.rs b/server-rs/crates/api-server/src/match3d/draft.rs index 79a0aa77..98e8a8b2 100644 --- a/server-rs/crates/api-server/src/match3d/draft.rs +++ b/server-rs/crates/api-server/src/match3d/draft.rs @@ -163,7 +163,14 @@ pub(super) async fn compile_match3d_draft_for_session( .clone() .unwrap_or_else(|| fallback_work_metadata.tags.clone()); let billing_asset_id = format!("{}:{}:{}", session_id, profile_id, current_utc_micros()); - execute_billable_match3d_draft_generation( + let compile_session_id = session_id.clone(); + let compile_owner_user_id = owner_user_id.clone(); + let compile_profile_id = profile_id.clone(); + let compile_initial_game_name = initial_game_name.clone(); + let compile_requested_summary = requested_summary.clone(); + let compile_initial_tags = initial_tags.clone(); + let compile_requested_cover_image_src = requested_cover_image_src.clone(); + let result = execute_billable_match3d_draft_generation( state, request_context, owner_user_id.as_str(), @@ -307,7 +314,108 @@ pub(super) async fn compile_match3d_draft_for_session( Ok((next_session, generated_item_assets)) }, ) + .await; + + if let Err(response) = result.as_ref() + && response.status().is_server_error() + { + let failure_message = match3d_response_failure_message(response); + persist_failed_match3d_draft_generation( + state, + request_context, + authenticated, + compile_session_id, + compile_owner_user_id, + compile_profile_id, + compile_initial_game_name, + compile_requested_summary, + compile_initial_tags, + compile_requested_cover_image_src, + failure_message, + ) + .await; + } + + result +} + +#[allow(clippy::too_many_arguments)] +async fn persist_failed_match3d_draft_generation( + state: &AppState, + request_context: &RequestContext, + authenticated: &AuthenticatedAccessToken, + session_id: String, + owner_user_id: String, + profile_id: String, + game_name: String, + summary: Option, + tags: Vec, + cover_image_src: Option, + failure_message: String, +) { + let failure_assets_json = serialize_match3d_failed_generation_assets(failure_message.as_str()); + if let Err(persist_error) = upsert_match3d_draft_snapshot( + state, + request_context, + authenticated, + session_id, + owner_user_id, + profile_id, + Some(game_name), + summary.or_else(|| Some(String::new())), + Some(serde_json::to_string(&tags).unwrap_or_default()), + cover_image_src, + None, + failure_assets_json, + ) .await + { + tracing::error!( + provider = MATCH3D_AGENT_PROVIDER, + status = ?persist_error.status(), + "抓大鹅草稿生成失败后的状态回写失败" + ); + } +} + +fn serialize_match3d_failed_generation_assets(message: &str) -> Option { + let background_asset = Match3DGeneratedBackgroundAsset { + prompt: String::new(), + status: "failed".to_string(), + error: Some(message.trim().to_string()), + ..Default::default() + }; + let assets = vec![Match3DGeneratedItemAssetJson { + item_id: "match3d-generation-failure".to_string(), + item_name: "生成失败".to_string(), + item_size: Some(MATCH3D_ITEM_SIZE_LARGE.to_string()), + image_src: None, + image_object_key: None, + image_views: Vec::new(), + model_src: None, + model_object_key: None, + model_file_name: None, + task_uuid: None, + subscription_key: None, + sound_prompt: None, + background_music_title: None, + background_music_style: None, + background_music_prompt: None, + background_music: None, + click_sound: None, + background_asset: Some(background_asset), + status: "failed".to_string(), + error: Some(message.trim().to_string()), + }]; + serde_json::to_string(&assets).ok() +} + +fn match3d_response_failure_message(response: &Response) -> String { + response + .extensions() + .get::() + .cloned() + .unwrap_or_else(|| format!("抓大鹅草稿生成失败,HTTP {}", response.status())) } /// 中文注释:抓大鹅草稿生成是一次完整外部生成动作,按 session/profile 幂等预扣 10 泥点。 diff --git a/server-rs/crates/api-server/src/match3d/mappers.rs b/server-rs/crates/api-server/src/match3d/mappers.rs index 3fe49eb6..7ef007b8 100644 --- a/server-rs/crates/api-server/src/match3d/mappers.rs +++ b/server-rs/crates/api-server/src/match3d/mappers.rs @@ -453,6 +453,32 @@ fn match3d_background_asset_has_image(asset: &Match3DGeneratedBackgroundAsset) - || match3d_text_present(asset.container_image_object_key.as_ref()) } +fn match3d_asset_status_is_failure(status: &str) -> bool { + let normalized = status.trim().to_ascii_lowercase().replace(['-', ' '], "_"); + matches!( + normalized.as_str(), + "failed" | "failure" | "error" | "partial_failed" + ) +} + +fn match3d_error_present(value: Option<&String>) -> bool { + value.is_some_and(|value| !value.trim().is_empty()) +} + +fn match3d_item_asset_has_failure(asset: &Match3DGeneratedItemAssetJson) -> bool { + match3d_asset_status_is_failure(asset.status.as_str()) + || match3d_error_present(asset.error.as_ref()) + || asset.background_asset.as_ref().is_some_and(|background| { + match3d_asset_status_is_failure(background.status.as_str()) + || match3d_error_present(background.error.as_ref()) + }) +} + +fn match3d_background_asset_has_failure(asset: &Match3DGeneratedBackgroundAsset) -> bool { + match3d_asset_status_is_failure(asset.status.as_str()) + || match3d_error_present(asset.error.as_ref()) +} + fn resolve_match3d_work_generation_status( item: &Match3DWorkProfileRecord, assets: &[Match3DGeneratedItemAssetJson], @@ -462,6 +488,21 @@ fn resolve_match3d_work_generation_status( return Some("ready".to_string()); } + let has_failure = assets.iter().any(match3d_item_asset_has_failure) + || background_asset.is_some_and(match3d_background_asset_has_failure); + if has_failure { + let has_partial_result = assets.iter().any(match3d_item_asset_has_image) + || background_asset.is_some_and(match3d_background_asset_has_image); + return Some( + if has_partial_result { + "partial_failed" + } else { + "failed" + } + .to_string(), + ); + } + if assets.is_empty() || !assets.iter().any(match3d_item_asset_has_image) || !background_asset.is_some_and(match3d_background_asset_has_image) diff --git a/server-rs/crates/api-server/src/match3d/tests.rs b/server-rs/crates/api-server/src/match3d/tests.rs index 425fcb69..226be1f1 100644 --- a/server-rs/crates/api-server/src/match3d/tests.rs +++ b/server-rs/crates/api-server/src/match3d/tests.rs @@ -1842,3 +1842,45 @@ fn match3d_work_summary_marks_complete_generated_assets_ready() { assert_eq!(response.generation_status.as_deref(), Some("ready")); } + +#[test] +fn match3d_work_summary_marks_failed_generated_assets_failed() { + let assets = vec![Match3DGeneratedItemAsset { + background_asset: Some(Match3DGeneratedBackgroundAsset { + prompt: "水果厨房背景".to_string(), + status: "failed".to_string(), + error: Some("VectorEngine 请求失败".to_string()), + ..Default::default() + }), + status: "failed".to_string(), + error: Some("VectorEngine 请求失败".to_string()), + ..test_match3d_generated_item_asset(1, "草莓") + }]; + let response = map_match3d_work_summary_response(Match3DWorkProfileRecord { + work_id: "match3d-profile-1".to_string(), + profile_id: "match3d-profile-1".to_string(), + owner_user_id: "user-1".to_string(), + source_session_id: Some("match3d-session-1".to_string()), + author_display_name: "玩家".to_string(), + game_name: "水果抓大鹅".to_string(), + theme_text: "水果".to_string(), + summary: "水果主题".to_string(), + tags: vec!["水果".to_string()], + cover_image_src: None, + cover_asset_id: None, + reference_image_src: None, + clear_count: 3, + difficulty: 3, + publication_status: "draft".to_string(), + play_count: 0, + updated_at: "2026-05-10T00:00:00.000Z".to_string(), + published_at: None, + publish_ready: false, + generated_item_assets_json: serialize_match3d_generated_item_assets(&assets), + }); + + assert_eq!( + response.generation_status.as_deref(), + Some("partial_failed") + ); +} diff --git a/server-rs/crates/api-server/src/state.rs b/server-rs/crates/api-server/src/state.rs index 59d47d45..8d70b13e 100644 --- a/server-rs/crates/api-server/src/state.rs +++ b/server-rs/crates/api-server/src/state.rs @@ -555,6 +555,10 @@ impl AppState { .to_string(), category_sort_order: 0, updated_at_micros: 0, + unified_creation_spec: + shared_contracts::creation_entry_config::build_phase1_unified_creation_spec( + creation_type_id, + ), }, ); } diff --git a/server-rs/crates/api-server/src/wooden_fish.rs b/server-rs/crates/api-server/src/wooden_fish.rs index a181489e..ae0cc415 100644 --- a/server-rs/crates/api-server/src/wooden_fish.rs +++ b/server-rs/crates/api-server/src/wooden_fish.rs @@ -147,26 +147,34 @@ pub async fn execute_wooden_fish_action( wooden_fish_json(payload, &request_context, WOODEN_FISH_CREATION_PROVIDER)?; let owner_user_id = authenticated.claims().user_id().to_string(); let author_display_name = resolve_author_display_name(&state, &authenticated); - maybe_generate_hit_object_asset( + let result = execute_wooden_fish_action_with_generated_assets( &state, &request_context, &session_id, - owner_user_id.as_str(), + &owner_user_id, + &author_display_name, &mut payload, ) - .await?; - maybe_generate_hit_sound_asset(&mut payload); - let response = state - .spacetime_client() - .execute_wooden_fish_action(session_id, owner_user_id, author_display_name, payload) - .await - .map_err(|error| { - wooden_fish_error_response( - &request_context, - WOODEN_FISH_CREATION_PROVIDER, - map_wooden_fish_client_error(error), - ) - })?; + .await; + if result + .as_ref() + .err() + .is_some_and(|response| response.status().is_server_error()) + && matches!( + payload.action_type, + shared_contracts::wooden_fish::WoodenFishActionType::CompileDraft + ) + { + mark_wooden_fish_generation_failed( + &state, + &request_context, + &session_id, + owner_user_id.as_str(), + author_display_name.as_str(), + ) + .await; + } + let response = result?; Ok(json_success_body(Some(&request_context), response)) } @@ -372,16 +380,24 @@ async fn build_wooden_fish_draft( payload: &WoodenFishWorkspaceCreateRequest, state: &AppState, ) -> Result { - Ok(WoodenFishDraftResponse { + let work_title = resolve_wooden_fish_work_title( + state, + &payload.work_description, + &payload.hit_object_prompt, + ) + .await?; + Ok(build_wooden_fish_draft_response(payload, work_title)) +} + +fn build_wooden_fish_draft_response( + payload: &WoodenFishWorkspaceCreateRequest, + work_title: String, +) -> WoodenFishDraftResponse { + WoodenFishDraftResponse { template_id: WOODEN_FISH_TEMPLATE_ID.to_string(), template_name: WOODEN_FISH_TEMPLATE_NAME.to_string(), profile_id: None, - work_title: resolve_wooden_fish_work_title( - state, - &payload.work_description, - &payload.hit_object_prompt, - ) - .await?, + work_title, work_description: payload.work_description.trim().to_string(), theme_tags: normalize_tags(payload.theme_tags.clone()), hit_object_prompt: clean_string(&payload.hit_object_prompt, DEFAULT_HIT_OBJECT_PROMPT), @@ -401,7 +417,7 @@ async fn build_wooden_fish_draft( .or_else(|| Some(default_wooden_fish_hit_sound_asset())), cover_image_src: None, generation_status: WoodenFishGenerationStatus::Draft, - }) + } } fn validate_workspace_request( @@ -543,6 +559,62 @@ async fn maybe_generate_hit_object_asset( Ok(()) } +async fn execute_wooden_fish_action_with_generated_assets( + state: &AppState, + request_context: &RequestContext, + session_id: &str, + owner_user_id: &str, + author_display_name: &str, + payload: &mut WoodenFishActionRequest, +) -> Result { + maybe_generate_hit_object_asset(state, request_context, session_id, owner_user_id, payload) + .await?; + maybe_generate_hit_sound_asset(payload); + state + .spacetime_client() + .execute_wooden_fish_action( + session_id.to_string(), + owner_user_id.to_string(), + author_display_name.to_string(), + payload.clone(), + ) + .await + .map_err(|error| { + wooden_fish_error_response( + request_context, + WOODEN_FISH_CREATION_PROVIDER, + map_wooden_fish_client_error(error), + ) + }) +} + +async fn mark_wooden_fish_generation_failed( + state: &AppState, + request_context: &RequestContext, + session_id: &str, + owner_user_id: &str, + author_display_name: &str, +) { + if let Err(error) = state + .spacetime_client() + .mark_wooden_fish_generation_failed( + session_id.to_string(), + owner_user_id.to_string(), + author_display_name.to_string(), + ) + .await + { + tracing::error!( + provider = WOODEN_FISH_CREATION_PROVIDER, + session_id, + owner_user_id, + request_id = request_context.request_id(), + error = %error, + "敲木鱼草稿生成失败后的状态回写失败" + ); + } +} + fn default_wooden_fish_hit_object_asset() -> WoodenFishImageAsset { WoodenFishImageAsset { asset_id: DEFAULT_HIT_OBJECT_ASSET_ID.to_string(), @@ -1475,7 +1547,8 @@ mod tests { floating_words: vec![], }; - let draft = build_wooden_fish_draft(&payload); + let draft = + build_wooden_fish_draft_response(&payload, WOODEN_FISH_TEMPLATE_NAME.to_string()); assert!(draft.hit_sound_prompt.is_none()); let asset = draft diff --git a/server-rs/crates/module-runtime/src/application.rs b/server-rs/crates/module-runtime/src/application.rs index 2d997da6..4a4e4b7d 100644 --- a/server-rs/crates/module-runtime/src/application.rs +++ b/server-rs/crates/module-runtime/src/application.rs @@ -11,7 +11,7 @@ use crate::errors::RuntimeProfileFieldError; use crate::format_utc_micros; use shared_contracts::creation_entry_config::{ CreationEntryConfigResponse, CreationEntryEventBannerResponse, CreationEntryStartCardResponse, - CreationEntryTypeModalResponse, CreationEntryTypeResponse, + CreationEntryTypeModalResponse, CreationEntryTypeResponse, build_phase1_unified_creation_spec, }; pub fn build_creation_entry_config_response( @@ -39,19 +39,23 @@ pub fn build_creation_entry_config_response( creation_types: snapshot .creation_types .into_iter() - .map(|item| CreationEntryTypeResponse { - id: item.id, - title: item.title, - subtitle: item.subtitle, - badge: item.badge, - image_src: item.image_src, - visible: item.visible, - open: item.open, - sort_order: item.sort_order, - category_id: item.category_id, - category_label: item.category_label, - category_sort_order: item.category_sort_order, - updated_at_micros: item.updated_at_micros, + .map(|item| { + let unified_creation_spec = build_phase1_unified_creation_spec(item.id.as_str()); + CreationEntryTypeResponse { + id: item.id, + title: item.title, + subtitle: item.subtitle, + badge: item.badge, + image_src: item.image_src, + visible: item.visible, + open: item.open, + sort_order: item.sort_order, + category_id: item.category_id, + category_label: item.category_label, + category_sort_order: item.category_sort_order, + updated_at_micros: item.updated_at_micros, + unified_creation_spec, + } }) .collect(), } diff --git a/server-rs/crates/shared-contracts/src/creation_entry_config.rs b/server-rs/crates/shared-contracts/src/creation_entry_config.rs index c6664cbb..3f981007 100644 --- a/server-rs/crates/shared-contracts/src/creation_entry_config.rs +++ b/server-rs/crates/shared-contracts/src/creation_entry_config.rs @@ -51,4 +51,113 @@ pub struct CreationEntryTypeResponse { pub category_label: String, pub category_sort_order: i32, pub updated_at_micros: i64, + #[serde(skip_serializing_if = "Option::is_none")] + pub unified_creation_spec: Option, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct UnifiedCreationSpecResponse { + pub play_id: String, + pub title: String, + pub workspace_stage: String, + pub generation_stage: String, + pub result_stage: String, + pub fields: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct UnifiedCreationFieldResponse { + pub id: String, + pub kind: String, + pub label: String, + pub required: bool, +} + +pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option { + let (workspace_stage, generation_stage, result_stage, fields) = match play_id { + "puzzle" => ( + "puzzle-agent-workspace", + "puzzle-generating", + "puzzle-result", + vec![ + unified_creation_field("pictureDescription", "text", "画面描述", true), + unified_creation_field("referenceImage", "image", "拼图画面", false), + unified_creation_field("promptReferenceImages", "image", "参考图", false), + ], + ), + "match3d" => ( + "match3d-agent-workspace", + "match3d-generating", + "match3d-result", + vec![ + unified_creation_field("themeText", "text", "题材", true), + unified_creation_field("difficulty", "select", "难度", true), + ], + ), + "wooden-fish" => ( + "wooden-fish-workspace", + "wooden-fish-generating", + "wooden-fish-result", + vec![ + unified_creation_field("hitObjectPrompt", "text", "敲什么", false), + unified_creation_field("hitObjectReferenceImage", "image", "参考图", false), + unified_creation_field("hitSoundAsset", "audio", "敲击音效", false), + unified_creation_field("floatingWords", "text", "功德有什么", true), + ], + ), + _ => return None, + }; + + Some(UnifiedCreationSpecResponse { + play_id: play_id.to_string(), + title: "想做个什么玩法?".to_string(), + workspace_stage: workspace_stage.to_string(), + generation_stage: generation_stage.to_string(), + result_stage: result_stage.to_string(), + fields, + }) +} + +fn unified_creation_field( + id: &str, + kind: &str, + label: &str, + required: bool, +) -> UnifiedCreationFieldResponse { + UnifiedCreationFieldResponse { + id: id.to_string(), + kind: kind.to_string(), + label: label.to_string(), + required, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn phase1_unified_creation_specs_only_cover_three_templates() { + let puzzle = build_phase1_unified_creation_spec("puzzle").expect("puzzle spec"); + assert_eq!(puzzle.fields[0].id, "pictureDescription"); + assert_eq!(puzzle.fields[1].kind, "image"); + + let match3d = build_phase1_unified_creation_spec("match3d").expect("match3d spec"); + assert_eq!( + match3d + .fields + .iter() + .filter(|field| field.kind == "select") + .count(), + 1 + ); + + let wooden_fish = + build_phase1_unified_creation_spec("wooden-fish").expect("wooden-fish spec"); + assert!(wooden_fish.fields.iter().any(|field| field.kind == "audio")); + assert!(build_phase1_unified_creation_spec("visual-novel").is_none()); + assert!(build_phase1_unified_creation_spec("bark-battle").is_none()); + } } diff --git a/server-rs/crates/spacetime-client/src/mapper/wooden_fish.rs b/server-rs/crates/spacetime-client/src/mapper/wooden_fish.rs index d4ec1031..60890a91 100644 --- a/server-rs/crates/spacetime-client/src/mapper/wooden_fish.rs +++ b/server-rs/crates/spacetime-client/src/mapper/wooden_fish.rs @@ -100,6 +100,7 @@ fn map_wooden_fish_session_snapshot( fn map_wooden_fish_work_snapshot( snapshot: WoodenFishWorkSnapshot, ) -> Result { + let generation_status = parse_generation_status(&snapshot.generation_status); let draft = WoodenFishDraftResponse { template_id: "wooden-fish".to_string(), template_name: "敲木鱼".to_string(), @@ -116,15 +117,23 @@ fn map_wooden_fish_work_snapshot( back_button_asset: snapshot.back_button_asset.clone().map(map_image_asset), hit_sound_asset: snapshot.hit_sound_asset.clone().map(map_audio_asset), cover_image_src: empty_string_to_none(snapshot.cover_image_src.clone()), - generation_status: parse_generation_status(&snapshot.generation_status), + generation_status: generation_status.clone(), }; let hit_object_asset = draft .hit_object_asset .clone() + .or_else(|| { + matches!(generation_status, WoodenFishGenerationStatus::Failed) + .then(default_failed_hit_object_asset) + }) .ok_or_else(|| SpacetimeClientError::missing_snapshot("wooden fish hit object asset"))?; let hit_sound_asset = draft .hit_sound_asset .clone() + .or_else(|| { + matches!(generation_status, WoodenFishGenerationStatus::Failed) + .then(default_failed_hit_sound_asset) + }) .ok_or_else(|| SpacetimeClientError::missing_snapshot("wooden fish hit sound asset"))?; Ok(WoodenFishWorkProfileResponse { summary: WoodenFishWorkSummaryResponse { @@ -143,7 +152,7 @@ fn map_wooden_fish_work_snapshot( updated_at: format_timestamp_micros(snapshot.updated_at_micros), published_at: snapshot.published_at_micros.map(format_timestamp_micros), publish_ready: snapshot.publish_ready, - generation_status: parse_generation_status(&snapshot.generation_status), + generation_status, }, draft, hit_object_asset, @@ -154,6 +163,31 @@ fn map_wooden_fish_work_snapshot( }) } +fn default_failed_hit_object_asset() -> WoodenFishImageAsset { + WoodenFishImageAsset { + asset_id: "wooden-fish-failed-hit-object".to_string(), + image_src: "/wooden-fish/default-hit-object.png".to_string(), + image_object_key: "public/wooden-fish/default-hit-object.png".to_string(), + asset_object_id: "wooden-fish-failed-hit-object".to_string(), + generation_provider: "failed-fallback".to_string(), + prompt: "生成失败占位图".to_string(), + width: 1024, + height: 1024, + } +} + +fn default_failed_hit_sound_asset() -> WoodenFishAudioAsset { + WoodenFishAudioAsset { + asset_id: "wooden-fish-failed-hit-sound".to_string(), + audio_src: "/wooden-fish/default-hit-sound.mp3".to_string(), + audio_object_key: "public/wooden-fish/default-hit-sound.mp3".to_string(), + asset_object_id: "wooden-fish-failed-hit-sound".to_string(), + source: "failed-fallback".to_string(), + prompt: Some("生成失败占位音效".to_string()), + duration_ms: Some(3_000), + } +} + fn map_wooden_fish_draft_snapshot(snapshot: WoodenFishDraftSnapshot) -> WoodenFishDraftResponse { WoodenFishDraftResponse { template_id: snapshot.template_id, diff --git a/server-rs/crates/spacetime-client/src/wooden_fish.rs b/server-rs/crates/spacetime-client/src/wooden_fish.rs index 66304b09..d09f5238 100644 --- a/server-rs/crates/spacetime-client/src/wooden_fish.rs +++ b/server-rs/crates/spacetime-client/src/wooden_fish.rs @@ -122,6 +122,35 @@ impl SpacetimeClient { }) } + pub async fn mark_wooden_fish_generation_failed( + &self, + session_id: String, + owner_user_id: String, + author_display_name: String, + ) -> Result { + let current = self + .get_wooden_fish_session(session_id.clone(), owner_user_id.clone()) + .await?; + let mut draft = current.draft.clone().unwrap_or_else(default_draft); + let profile_id = resolve_wooden_fish_profile_id( + &draft, + &WoodenFishActionType::CompileDraft, + draft.profile_id.as_deref(), + )?; + draft.profile_id = Some(profile_id.clone()); + draft.generation_status = WoodenFishGenerationStatus::Failed; + let now_micros = current_unix_micros(); + self.compile_wooden_fish_draft(build_failed_compile_input( + ¤t, + &owner_user_id, + &author_display_name, + &profile_id, + &draft, + now_micros, + )?) + .await + } + pub async fn compile_wooden_fish_draft( &self, procedure_input: WoodenFishDraftCompileInput, @@ -636,6 +665,52 @@ fn build_compile_input( }) } +fn build_failed_compile_input( + current: &WoodenFishSessionSnapshotResponse, + owner_user_id: &str, + author_display_name: &str, + profile_id: &str, + draft: &WoodenFishDraftResponse, + now_micros: i64, +) -> Result { + Ok(WoodenFishDraftCompileInput { + session_id: current.session_id.clone(), + owner_user_id: owner_user_id.to_string(), + profile_id: profile_id.to_string(), + author_display_name: author_display_name.trim().to_string(), + work_title: draft.work_title.clone(), + work_description: draft.work_description.clone(), + theme_tags_json: Some(json_string(&draft.theme_tags)?), + hit_object_prompt: draft.hit_object_prompt.clone(), + hit_object_reference_image_src: draft.hit_object_reference_image_src.clone(), + hit_sound_prompt: draft.hit_sound_prompt.clone(), + hit_object_asset_json: draft + .hit_object_asset + .as_ref() + .map(json_string) + .transpose()?, + background_asset_json: draft + .background_asset + .as_ref() + .map(json_string) + .transpose()?, + hit_sound_asset_json: draft + .hit_sound_asset + .as_ref() + .map(json_string) + .transpose()?, + back_button_asset_json: draft + .back_button_asset + .as_ref() + .map(json_string) + .transpose()?, + floating_words_json: Some(json_string(&draft.floating_words)?), + cover_image_src: draft.cover_image_src.clone(), + generation_status: Some("failed".to_string()), + compiled_at_micros: now_micros, + }) +} + fn build_update_input( owner_user_id: &str, profile_id: &str, @@ -801,6 +876,7 @@ mod tests { const SESSION_ID: &str = "wooden-fish-session-test"; const OWNER_USER_ID: &str = "user-test"; + const AUTHOR_DISPLAY_NAME: &str = "测试玩家"; const PROFILE_ID: &str = "wooden-fish-profile-test"; const NOW_MICROS: i64 = 1_763_456_789_000_000; @@ -813,9 +889,14 @@ mod tests { payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back")); payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound")); - let (plan, draft) = - build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) - .expect("compile-draft should build plan"); + let (plan, draft) = build_wooden_fish_action_plan( + &session, + OWNER_USER_ID, + AUTHOR_DISPLAY_NAME, + &payload, + NOW_MICROS, + ) + .expect("compile-draft should build plan"); let WoodenFishActionProcedure::Compile(input) = plan else { panic!("compile-draft should call compile_wooden_fish_draft"); @@ -862,11 +943,16 @@ mod tests { payload.background_asset = Some(generated_background_asset("generated-compile-background")); payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back")); - let error = - match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) { - Ok(_) => panic!("compile-draft should not synthesize fake hit sound assets"), - Err(error) => error, - }; + let error = match build_wooden_fish_action_plan( + &session, + OWNER_USER_ID, + AUTHOR_DISPLAY_NAME, + &payload, + NOW_MICROS, + ) { + Ok(_) => panic!("compile-draft should not synthesize fake hit sound assets"), + Err(error) => error, + }; assert!( error @@ -883,11 +969,16 @@ mod tests { payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound")); payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back")); - let error = - match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) { - Ok(_) => panic!("compile-draft should not publish without background asset"), - Err(error) => error, - }; + let error = match build_wooden_fish_action_plan( + &session, + OWNER_USER_ID, + AUTHOR_DISPLAY_NAME, + &payload, + NOW_MICROS, + ) { + Ok(_) => panic!("compile-draft should not publish without background asset"), + Err(error) => error, + }; assert!( error @@ -904,11 +995,16 @@ mod tests { payload.background_asset = Some(generated_background_asset("generated-compile-background")); payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound")); - let error = - match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) { - Ok(_) => panic!("compile-draft should not publish without back button asset"), - Err(error) => error, - }; + let error = match build_wooden_fish_action_plan( + &session, + OWNER_USER_ID, + AUTHOR_DISPLAY_NAME, + &payload, + NOW_MICROS, + ) { + Ok(_) => panic!("compile-draft should not publish without back button asset"), + Err(error) => error, + }; assert!( error @@ -926,9 +1022,14 @@ mod tests { payload.background_asset = Some(generated_background_asset("generated-background")); payload.back_button_asset = Some(generated_back_button_asset("generated-back")); - let (plan, _draft) = - build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) - .expect("regenerate-hit-object should build plan"); + let (plan, _draft) = build_wooden_fish_action_plan( + &session, + OWNER_USER_ID, + AUTHOR_DISPLAY_NAME, + &payload, + NOW_MICROS, + ) + .expect("regenerate-hit-object should build plan"); let WoodenFishActionProcedure::Compile(input) = plan else { panic!("regenerate-hit-object should call compile_wooden_fish_draft"); @@ -987,9 +1088,14 @@ mod tests { "健康+1".to_string(), ]); - let (plan, draft) = - build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) - .expect("update-floating-words should build plan"); + let (plan, draft) = build_wooden_fish_action_plan( + &session, + OWNER_USER_ID, + AUTHOR_DISPLAY_NAME, + &payload, + NOW_MICROS, + ) + .expect("update-floating-words should build plan"); let WoodenFishActionProcedure::Update(input) = plan else { panic!("update-floating-words should call update_wooden_fish_work"); @@ -1016,6 +1122,31 @@ mod tests { assert!(draft.hit_sound_prompt.is_none()); } + #[test] + fn wooden_fish_failed_compile_input_preserves_session_and_marks_failed() { + let session = session_with_draft(draft_without_assets()); + let mut draft = session.draft.clone().expect("draft should exist"); + draft.profile_id = Some(PROFILE_ID.to_string()); + draft.generation_status = WoodenFishGenerationStatus::Failed; + + let input = build_failed_compile_input( + &session, + OWNER_USER_ID, + "测试玩家", + PROFILE_ID, + &draft, + NOW_MICROS, + ) + .expect("failed compile input should build"); + + assert_eq!(input.session_id, SESSION_ID); + assert_eq!(input.profile_id, PROFILE_ID); + assert_eq!(input.generation_status.as_deref(), Some("failed")); + assert!(input.hit_object_asset_json.is_none()); + assert!(input.background_asset_json.is_none()); + assert!(input.back_button_asset_json.is_none()); + } + fn action(action_type: WoodenFishActionType) -> WoodenFishActionRequest { WoodenFishActionRequest { action_type, diff --git a/server-rs/crates/spacetime-module/src/wooden_fish.rs b/server-rs/crates/spacetime-module/src/wooden_fish.rs index 33482ac2..d4dc56de 100644 --- a/server-rs/crates/spacetime-module/src/wooden_fish.rs +++ b/server-rs/crates/spacetime-module/src/wooden_fish.rs @@ -534,6 +534,9 @@ fn publish_wooden_fish_work_tx( input: WoodenFishWorkPublishInput, ) -> Result { let row = find_owned_work(ctx, &input.profile_id, &input.owner_user_id)?; + if row.generation_status == WOODEN_FISH_GENERATION_FAILED { + return Err("生成失败的敲木鱼作品需要重新生成后才能发布".to_string()); + } if !is_publish_ready(&row) { return Err("发布需要完整的敲击物图案、背景、返回按钮、敲击音效和飘字配置".to_string()); } diff --git a/server-rs/crates/spacetime-module/src/wooden_fish/types.rs b/server-rs/crates/spacetime-module/src/wooden_fish/types.rs index 12ebbdca..2ad5cb1b 100644 --- a/server-rs/crates/spacetime-module/src/wooden_fish/types.rs +++ b/server-rs/crates/spacetime-module/src/wooden_fish/types.rs @@ -12,6 +12,7 @@ pub const WOODEN_FISH_PUBLICATION_PUBLISHED: &str = "Published"; pub const WOODEN_FISH_GENERATION_DRAFT: &str = "draft"; pub const WOODEN_FISH_GENERATION_GENERATING: &str = "generating"; pub const WOODEN_FISH_GENERATION_READY: &str = "ready"; +pub const WOODEN_FISH_GENERATION_FAILED: &str = "failed"; pub const WOODEN_FISH_EVENT_RUN_STARTED: &str = "run-started"; pub const WOODEN_FISH_EVENT_RUN_CHECKPOINT: &str = "checkpoint"; pub const WOODEN_FISH_EVENT_RUN_FINISHED: &str = "finish"; diff --git a/src/components/common/CreativeAudioInputPanel.tsx b/src/components/common/CreativeAudioInputPanel.tsx new file mode 100644 index 00000000..84d87893 --- /dev/null +++ b/src/components/common/CreativeAudioInputPanel.tsx @@ -0,0 +1,206 @@ +import { Mic, Pause, Upload } from 'lucide-react'; +import { useRef, useState } from 'react'; + +export type CreativeAudioAsset = { + assetId: string; + audioSrc: string; + audioObjectKey: string; + assetObjectId: string; + source: string; + prompt?: string | null; + durationMs?: number | null; +}; + +type CreativeAudioInputPanelProps = { + disabled?: boolean; + title: string; + defaultLabel: string; + asset: TAsset | null; + buildRecordedFileName: () => string; + onAssetChange: (asset: TAsset | null) => void; + onError: (message: string | null) => void; + readFileAsAsset?: ( + file: File, + source: 'uploaded' | 'recorded', + ) => Promise; +}; + +export function readCreativeAudioFileAsAsset( + file: File, + source: 'uploaded' | 'recorded', +) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onerror = () => reject(new Error('音频读取失败,请重试。')); + reader.onload = () => { + if (typeof reader.result !== 'string') { + reject(new Error('音频读取失败,请重试。')); + return; + } + resolve({ + assetId: `local-${source}-${Date.now()}`, + audioSrc: reader.result, + audioObjectKey: '', + assetObjectId: '', + source, + prompt: file.name, + durationMs: null, + } as TAsset); + }; + reader.readAsDataURL(file); + }); +} + +export function CreativeAudioInputPanel({ + disabled = false, + title, + defaultLabel, + asset, + buildRecordedFileName, + onAssetChange, + onError, + readFileAsAsset = readCreativeAudioFileAsAsset, +}: CreativeAudioInputPanelProps) { + const [isRecording, setIsRecording] = useState(false); + const recorderRef = useRef(null); + const chunksRef = useRef([]); + + const startRecording = async () => { + if (disabled || isRecording) { + return; + } + + try { + if ( + typeof navigator === 'undefined' || + !navigator.mediaDevices?.getUserMedia || + typeof MediaRecorder === 'undefined' + ) { + throw new Error('当前浏览器不支持录音。'); + } + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + const recorder = new MediaRecorder(stream); + chunksRef.current = []; + recorder.ondataavailable = (event) => { + if (event.data.size > 0) { + chunksRef.current.push(event.data); + } + }; + recorder.onstop = () => { + const blob = new Blob(chunksRef.current, { + type: recorder.mimeType || 'audio/webm', + }); + stream.getTracks().forEach((track) => track.stop()); + const file = new File([blob], buildRecordedFileName(), { + type: blob.type, + }); + void readFileAsAsset(file, 'recorded') + .then(onAssetChange) + .catch((caughtError) => { + onError( + caughtError instanceof Error + ? caughtError.message + : '录音保存失败。', + ); + }); + }; + recorderRef.current = recorder; + recorder.start(); + setIsRecording(true); + onError(null); + } catch (caughtError) { + onError( + caughtError instanceof Error ? caughtError.message : '录音启动失败。', + ); + } + }; + + const stopRecording = () => { + recorderRef.current?.stop(); + recorderRef.current = null; + setIsRecording(false); + }; + + return ( +
+
+
+ {title} +
+ {asset ? ( + + ) : null} +
+
+ + + {asset?.audioSrc ? ( +
+
+ ); +} + +export default CreativeAudioInputPanel; diff --git a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx index 32c45498..d5e17908 100644 --- a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx +++ b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx @@ -215,11 +215,13 @@ import { buildSquareHoleGenerationAnchorEntries, buildWoodenFishGenerationAnchorEntries, createMiniGameDraftGenerationState, + resolveMiniGameDraftGenerationStartedAtMs, type MiniGameDraftGenerationKind, type MiniGameDraftGenerationPhase, type MiniGameDraftGenerationState, } from '../../services/miniGameDraftGenerationProgress'; import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient'; +import { getUnifiedCreationSpec } from '../unified-creation/unifiedCreationSpecs'; import { buildBabyObjectMatchPublicWorkCode, buildBarkBattlePublicWorkCode, @@ -2195,9 +2197,7 @@ function rebaseMiniGameDraftGenerationStateForDisplay( function rebaseMiniGameDraftBackgroundCompileTaskForDisplay< T extends PuzzleBackgroundCompileTask | Match3DBackgroundCompileTask, ->( - task: T, -): T { +>(task: T): T { return { ...task, generationState: rebaseMiniGameDraftGenerationStateForDisplay( @@ -2216,7 +2216,10 @@ function createPuzzleDraftGenerationStateFromPayload( : undefined; return { - ...createMiniGameDraftGenerationState('puzzle'), + ...createMiniGameDraftGenerationState( + 'puzzle', + resolveMiniGameDraftGenerationStartedAtMs(session?.updatedAt), + ), metadata: { puzzleAiRedraw: payload?.aiRedraw ?? true, puzzleActivePhaseId: @@ -2269,7 +2272,7 @@ function mergePuzzleSessionProgressIntoGenerationState( ...state.metadata, puzzleActivePhaseId: nextPhaseId, puzzleActiveStepStartedAtMs: shouldResetActiveStepStart - ? Date.now() + ? resolveMiniGameDraftGenerationStartedAtMs(session.updatedAt) : state.metadata?.puzzleActiveStepStartedAtMs, puzzleProgressPercent: isCompiledGenerationSession ? session.progressPercent @@ -2734,7 +2737,8 @@ function buildPendingBarkBattleWorks( uiBackgroundImageSrc: null, difficultyPreset: 'normal', status: 'draft', - generationStatus: state.status === 'generating' ? 'pending_assets' : 'ready', + generationStatus: + state.status === 'generating' ? 'pending_assets' : 'ready', publishReady: false, playCount: 0, updatedAt: state.updatedAt, @@ -2852,6 +2856,20 @@ const CustomWorldGenerationView = lazy(async () => { }; }); +const UnifiedCreationPage = lazy(async () => { + const module = await import('../unified-creation/UnifiedCreationPage'); + return { + default: module.UnifiedCreationPage, + }; +}); + +const UnifiedGenerationPage = lazy(async () => { + const module = await import('../unified-creation/UnifiedGenerationPage'); + return { + default: module.UnifiedGenerationPage, + }; +}); + const RpgCreationResultView = lazy(async () => { const module = await import('../rpg-creation-result/RpgCreationResultView'); return { @@ -2983,7 +3001,9 @@ const BarkBattleConfigEditor = lazy(async () => { }); const BarkBattleGeneratingView = lazy(async () => { - const module = await import('../bark-battle-creation/BarkBattleGeneratingView'); + const module = await import( + '../bark-battle-creation/BarkBattleGeneratingView' + ); return { default: module.BarkBattleGeneratingView, }; @@ -3276,13 +3296,16 @@ export function PlatformEntryFlowShellImpl({ useState(null); const [barkBattleDraftConfig, setBarkBattleDraftConfig] = useState(null); - const [barkBattleRuntimeMode, setBarkBattleRuntimeMode] = - useState<'draft' | 'published'>('draft'); + const [barkBattleRuntimeMode, setBarkBattleRuntimeMode] = useState< + 'draft' | 'published' + >('draft'); const [barkBattleRuntimeReturnStage, setBarkBattleRuntimeReturnStage] = useState('platform'); const [barkBattleError, setBarkBattleError] = useState(null); - const [barkBattleGenerationPartialFailed, setBarkBattleGenerationPartialFailed] = - useState(false); + const [ + barkBattleGenerationPartialFailed, + setBarkBattleGenerationPartialFailed, + ] = useState(false); const [isBarkBattleBusy, setIsBarkBattleBusy] = useState(false); const [bigFishRun, setBigFishRun] = useState(null); @@ -3457,6 +3480,10 @@ export function PlatformEntryFlowShellImpl({ : [], [creationEntryConfig], ); + const unifiedCreationConfigById = useMemo(() => { + const entries = creationEntryConfig?.creationTypes ?? []; + return new Map(entries.map((entry) => [entry.id, entry])); + }, [creationEntryConfig]); const isBigFishCreationVisible = isPlatformCreationTypeVisible( creationEntryTypes, 'big-fish', @@ -3841,12 +3868,10 @@ export function PlatformEntryFlowShellImpl({ return true; } - setDraftGenerationPointNotice( - { - title: '泥点不足', - message: `本次需要 ${pointsCost} 泥点,当前 ${walletBalance} 泥点。`, - }, - ); + setDraftGenerationPointNotice({ + title: '泥点不足', + message: `本次需要 ${pointsCost} 泥点,当前 ${walletBalance} 泥点。`, + }); return false; } catch { setDraftGenerationPointNotice({ @@ -4157,26 +4182,36 @@ export function PlatformEntryFlowShellImpl({ (updated: BarkBattleWorkSummary) => { setBarkBattleWorks((current) => { const deduped = mergeBarkBattleWorksByWorkId(current); - const hasExisting = deduped.some((item) => item.workId === updated.workId); + const hasExisting = deduped.some( + (item) => item.workId === updated.workId, + ); if (hasExisting) { - return deduped.map((item) => mergeBarkBattleWorkSummary(item, updated)); + return deduped.map((item) => + mergeBarkBattleWorkSummary(item, updated), + ); } return [updated, ...deduped]; }); setBarkBattleGalleryEntries((current) => { - const hasExisting = current.some((item) => item.workId === updated.workId); + const hasExisting = current.some( + (item) => item.workId === updated.workId, + ); if (updated.status !== 'published') { return hasExisting ? current.map((item) => mergeBarkBattleWorkSummary(item, updated)) : current; } if (hasExisting) { - return current.map((item) => mergeBarkBattleWorkSummary(item, updated)); + return current.map((item) => + mergeBarkBattleWorkSummary(item, updated), + ); } return [updated, ...current]; }); if (updated.status === 'published') { - syncUpdatedPublicWorkDetail(mapBarkBattleWorkToPublicWorkDetail(updated)); + syncUpdatedPublicWorkDetail( + mapBarkBattleWorkToPublicWorkDetail(updated), + ); } }, [syncUpdatedPublicWorkDetail], @@ -4212,7 +4247,10 @@ export function PlatformEntryFlowShellImpl({ return; } - if (platformBootstrap.platformTab === 'create' || selectionStage === 'platform') { + if ( + platformBootstrap.platformTab === 'create' || + selectionStage === 'platform' + ) { void refreshBarkBattleShelf(); } }, [ @@ -4228,7 +4266,10 @@ export function PlatformEntryFlowShellImpl({ return; } - if (platformBootstrap.platformTab === 'create' || selectionStage === 'platform') { + if ( + platformBootstrap.platformTab === 'create' || + selectionStage === 'platform' + ) { void refreshJumpHopShelf(); } }, [ @@ -4509,7 +4550,9 @@ export function PlatformEntryFlowShellImpl({ : []), ...match3dGalleryEntries.map(mapMatch3DWorkToPublicWorkDetail), ...puzzleGalleryEntries.map(mapPuzzleWorkToPlatformGalleryCard), - ...barkBattleGalleryEntries.map(mapBarkBattleWorkToPlatformGalleryCard), + ...barkBattleGalleryEntries.map( + mapBarkBattleWorkToPlatformGalleryCard, + ), ...jumpHopGalleryEntries.map(mapJumpHopWorkToPlatformGalleryCard), ...(barkBattleGalleryEntries.length === 0 ? barkBattleWorks @@ -4557,8 +4600,8 @@ export function PlatformEntryFlowShellImpl({ ...featuredGalleryEntries, ...latestGalleryEntries, ]).forEach((entry) => { - entryMap.set(getPlatformPublicGalleryEntryKey(entry), entry); - }); + entryMap.set(getPlatformPublicGalleryEntryKey(entry), entry); + }); return Array.from(entryMap.values()); }, [featuredGalleryEntries, latestGalleryEntries]); @@ -5241,7 +5284,12 @@ export function PlatformEntryFlowShellImpl({ markPendingDraftGenerating('match3d', session.sessionId); selectionStageRef.current = 'match3d-generating'; setSelectionStage('match3d-generating'); - setMatch3DGenerationState(createMiniGameDraftGenerationState('match3d')); + setMatch3DGenerationState( + createMiniGameDraftGenerationState( + 'match3d', + resolveMiniGameDraftGenerationStartedAtMs(session.updatedAt), + ), + ); }, onActionError: async ({ payload, errorMessage, session, setSession }) => { if (payload.action !== 'match3d_compile_draft') { @@ -5870,9 +5918,7 @@ export function PlatformEntryFlowShellImpl({ return ensureEnoughDraftGenerationPointsFromServer( PUZZLE_DRAFT_GENERATION_POINT_COST, ); - }, [ - ensureEnoughDraftGenerationPointsFromServer, - ]); + }, [ensureEnoughDraftGenerationPointsFromServer]); const preflightMatch3DDraftGeneration = useCallback(async () => { setMatch3DError(null); return ensureEnoughDraftGenerationPointsFromServer( @@ -6164,7 +6210,8 @@ export function PlatformEntryFlowShellImpl({ puzzleGenerationViewSession?.sessionId ?? puzzleSession?.sessionId, ), - message: puzzleGenerationViewError ?? puzzleCreationError ?? puzzleError, + message: + puzzleGenerationViewError ?? puzzleCreationError ?? puzzleError, }, { key: 'puzzle-onboarding', @@ -6292,9 +6339,10 @@ export function PlatformEntryFlowShellImpl({ completedAtMs: number | null; }) | null - >(() => pendingPlatformTaskCompletionDialog, [ - pendingPlatformTaskCompletionDialog, - ]); + >( + () => pendingPlatformTaskCompletionDialog, + [pendingPlatformTaskCompletionDialog], + ); const activePlatformTaskCompletionDialogDismissKey = buildPlatformTaskCompletionDialogDismissKey( currentPlatformTaskCompletionDialog, @@ -6429,7 +6477,10 @@ export function PlatformEntryFlowShellImpl({ isMiniGameDraftGenerating(puzzleGenerationViewState); useEffect(() => { - if (!shouldPollPuzzleGenerationSession || !activePuzzleGenerationSessionId) { + if ( + !shouldPollPuzzleGenerationSession || + !activePuzzleGenerationSessionId + ) { return undefined; } @@ -6973,7 +7024,10 @@ export function PlatformEntryFlowShellImpl({ return; } - const generationState = createMiniGameDraftGenerationState('match3d'); + const generationState = createMiniGameDraftGenerationState( + 'match3d', + resolveMiniGameDraftGenerationStartedAtMs(nextSession.updatedAt), + ); setMatch3DBackgroundCompileTasks((current) => ({ ...current, [nextSession.sessionId]: { @@ -7687,7 +7741,10 @@ export function PlatformEntryFlowShellImpl({ writeCreationUrlState(buildBarkBattleCreationUrlState(draft)); setBarkBattlePublishedConfig(null); markDraftGenerating('bark-battle', [draft.workId, draft.draftId]); - markPendingDraftGenerating('bark-battle', draft.workId ?? draft.draftId); + markPendingDraftGenerating( + 'bark-battle', + draft.workId ?? draft.draftId, + ); updateBarkBattleWorkCaches( buildBarkBattleWorkSummaryFromDraft( draft, @@ -7780,9 +7837,11 @@ export function PlatformEntryFlowShellImpl({ const nextDraft = { ...persistedDraft, playerCharacterImageSrc: - draft.playerCharacterImageSrc ?? persistedDraft.playerCharacterImageSrc, + draft.playerCharacterImageSrc ?? + persistedDraft.playerCharacterImageSrc, opponentCharacterImageSrc: - draft.opponentCharacterImageSrc ?? persistedDraft.opponentCharacterImageSrc, + draft.opponentCharacterImageSrc ?? + persistedDraft.opponentCharacterImageSrc, uiBackgroundImageSrc: draft.uiBackgroundImageSrc ?? persistedDraft.uiBackgroundImageSrc, }; @@ -7852,7 +7911,9 @@ export function PlatformEntryFlowShellImpl({ setBarkBattleError(null); const workId = draft.workId?.trim(); if (!workId) { - setBarkBattleError('这份汪汪声浪草稿缺少作品ID,请重新生成草稿后再发布。'); + setBarkBattleError( + '这份汪汪声浪草稿缺少作品ID,请重新生成草稿后再发布。', + ); return; } setIsBarkBattleBusy(true); @@ -7885,7 +7946,8 @@ export function PlatformEntryFlowShellImpl({ playerCharacterImageSrc: published.playerCharacterImageSrc ?? draft.playerCharacterImageSrc, opponentCharacterImageSrc: - published.opponentCharacterImageSrc ?? draft.opponentCharacterImageSrc, + published.opponentCharacterImageSrc ?? + draft.opponentCharacterImageSrc, uiBackgroundImageSrc: published.uiBackgroundImageSrc ?? draft.uiBackgroundImageSrc, }; @@ -7911,7 +7973,9 @@ export function PlatformEntryFlowShellImpl({ ); selectionStageRef.current = 'work-detail'; setSelectionStage('work-detail'); - pushAppHistoryPath(buildPublicWorkStagePath('work-detail', publicWorkCode)); + pushAppHistoryPath( + buildPublicWorkStagePath('work-detail', publicWorkCode), + ); void Promise.allSettled([ refreshBarkBattleShelf(), refreshBarkBattleGallery(), @@ -8021,10 +8085,7 @@ export function PlatformEntryFlowShellImpl({ await ensureBabyObjectMatchGeneratedAssets(draft); } catch (error) { setBabyObjectMatchError( - resolvePuzzleErrorMessage( - error, - '重新生成宝贝识物素材失败。', - ), + resolvePuzzleErrorMessage(error, '重新生成宝贝识物素材失败。'), ); } finally { setIsBabyObjectMatchBusy(false); @@ -8680,9 +8741,12 @@ export function PlatformEntryFlowShellImpl({ ); setJumpHopGenerationState(readyState); if (response.work) { - setJumpHopWorks((current) => - [response.work!.summary, ...current.filter((item) => item.workId !== response.work!.summary.workId)], - ); + setJumpHopWorks((current) => [ + response.work!.summary, + ...current.filter( + (item) => item.workId !== response.work!.summary.workId, + ), + ]); markPendingDraftReady('jump-hop', created.session.sessionId, false); markDraftReady( 'jump-hop', @@ -8821,9 +8885,12 @@ export function PlatformEntryFlowShellImpl({ try { const response = await jumpHopClient.publishWork(profileId); setJumpHopWork(response.item); - setJumpHopWorks((current) => - [response.item.summary, ...current.filter((item) => item.workId !== response.item.summary.workId)], - ); + setJumpHopWorks((current) => [ + response.item.summary, + ...current.filter( + (item) => item.workId !== response.item.summary.workId, + ), + ]); void refreshJumpHopShelf().catch(() => undefined); openPublishShareModal({ title: response.item.summary.workTitle || '跳一跳', @@ -8967,7 +9034,12 @@ export function PlatformEntryFlowShellImpl({ created: WoodenFishSessionResponse, payload?: WoodenFishWorkspaceCreateRequest, ) => { - const generationState = createMiniGameDraftGenerationState('wooden-fish'); + const generationState = createMiniGameDraftGenerationState( + 'wooden-fish', + resolveMiniGameDraftGenerationStartedAtMs( + created.session.updatedAt ?? created.session.createdAt, + ), + ); setWoodenFishError(null); setWoodenFishSession(created.session); writeCreationUrlState( @@ -8994,7 +9066,8 @@ export function PlatformEntryFlowShellImpl({ payload?.workDescription ?? created.session.draft?.workDescription ?? '', - themeTags: payload?.themeTags ?? created.session.draft?.themeTags ?? ['敲木鱼'], + themeTags: payload?.themeTags ?? + created.session.draft?.themeTags ?? ['敲木鱼'], coverImageSrc: created.session.draft?.coverImageSrc ?? null, publicationStatus: 'draft', playCount: 0, @@ -9128,7 +9201,10 @@ export function PlatformEntryFlowShellImpl({ return; } - const generationState = createMiniGameDraftGenerationState('wooden-fish'); + const generationState = createMiniGameDraftGenerationState( + 'wooden-fish', + resolveMiniGameDraftGenerationStartedAtMs(woodenFishSession.updatedAt), + ); setWoodenFishError(null); setWoodenFishGenerationState(generationState); setIsWoodenFishBusy(true); @@ -9328,7 +9404,10 @@ export function PlatformEntryFlowShellImpl({ const [detail, runResponse] = await Promise.all([ woodenFishClient.getWorkDetail(normalizedProfileId).catch(() => null), options.embedded - ? woodenFishClient.startRun(normalizedProfileId, runtimeGuestOptions) + ? woodenFishClient.startRun( + normalizedProfileId, + runtimeGuestOptions, + ) : woodenFishClient.startRun(normalizedProfileId), ]); if (detail?.item) { @@ -9576,12 +9655,7 @@ export function PlatformEntryFlowShellImpl({ if (selectionStage === 'big-fish-runtime' && !bigFishRun) { setSelectionStage(bigFishSession?.draft ? 'big-fish-result' : 'platform'); } - }, [ - bigFishRun, - bigFishSession, - selectionStage, - setSelectionStage, - ]); + }, [bigFishRun, bigFishSession, selectionStage, setSelectionStage]); useEffect(() => { if (selectionStage === 'match3d-result' && !match3dSession?.draft) { @@ -9592,12 +9666,7 @@ export function PlatformEntryFlowShellImpl({ if (selectionStage === 'match3d-runtime' && !match3dRun) { setSelectionStage(match3dSession?.draft ? 'match3d-result' : 'platform'); } - }, [ - match3dRun, - match3dSession, - selectionStage, - setSelectionStage, - ]); + }, [match3dRun, match3dSession, selectionStage, setSelectionStage]); useEffect(() => { if (selectionStage === 'square-hole-result' && !squareHoleSession?.draft) { @@ -9610,12 +9679,7 @@ export function PlatformEntryFlowShellImpl({ squareHoleSession?.draft ? 'square-hole-result' : 'platform', ); } - }, [ - selectionStage, - setSelectionStage, - squareHoleRun, - squareHoleSession, - ]); + }, [selectionStage, setSelectionStage, squareHoleRun, squareHoleSession]); useEffect(() => { if ( @@ -9859,11 +9923,10 @@ export function PlatformEntryFlowShellImpl({ setMatch3DError(null); try { - let runtimeProfile: Match3DWorkProfile | Match3DWorkSummary = - profile; + let runtimeProfile: Match3DWorkProfile | Match3DWorkSummary = profile; if ( - (!hasMatch3DRuntimeAsset(profile.generatedItemAssets) || - !hasMatch3DRuntimeBackgroundAsset(profile)) + !hasMatch3DRuntimeAsset(profile.generatedItemAssets) || + !hasMatch3DRuntimeBackgroundAsset(profile) ) { try { const { item } = await getMatch3DWorkDetail(profile.profileId); @@ -10319,21 +10382,19 @@ export function PlatformEntryFlowShellImpl({ ? puzzleGalleryEntries.length > 0 ? puzzleGalleryEntries : await refreshPuzzleGallery() - : ( - puzzleWorks.length > 0 - ? puzzleWorks - : (await listPuzzleWorks().catch(() => ({ items: [] }))).items - ); + : puzzleWorks.length > 0 + ? puzzleWorks + : (await listPuzzleWorks().catch(() => ({ items: [] }))).items; const targetItem = runtimeProfileId || runtimeSessionId || publicWorkCode - ? candidateItems.find( + ? (candidateItems.find( (item) => item.profileId === runtimeProfileId || item.sourceSessionId === runtimeSessionId || (publicWorkCode ? isSamePuzzlePublicWorkCode(publicWorkCode, item.profileId) : false), - ) ?? null + ) ?? null) : null; if (!targetItem) { @@ -10381,9 +10442,7 @@ export function PlatformEntryFlowShellImpl({ } setSelectedPuzzleDetail(targetItem); - setPuzzleRun( - startLocalPuzzleRun(targetItem, runtimeLevelId ?? null), - ); + setPuzzleRun(startLocalPuzzleRun(targetItem, runtimeLevelId ?? null)); setPuzzleRuntimeAuthMode(isPublishedRuntime ? 'isolated' : 'default'); setPuzzleRuntimeReturnStage(fallbackStage); openPuzzleRuntimeStage( @@ -10634,7 +10693,11 @@ export function PlatformEntryFlowShellImpl({ const submitLeaderboardPromise = puzzleRuntimeAuthMode === 'isolated' ? buildRecommendRuntimeGuestOptions().then((runtimeGuestOptions) => - submitPuzzleLeaderboard(puzzleRun.runId, payload, runtimeGuestOptions), + submitPuzzleLeaderboard( + puzzleRun.runId, + payload, + runtimeGuestOptions, + ), ) : submitPuzzleLeaderboard(puzzleRun.runId, payload); @@ -10753,8 +10816,7 @@ export function PlatformEntryFlowShellImpl({ const item = await getPuzzleGalleryDetail(nextProfileId).then( (response) => response.item, ); - const nextRecommendEntry = - mapPuzzleWorkToPlatformGalleryCard(item); + const nextRecommendEntry = mapPuzzleWorkToPlatformGalleryCard(item); setPuzzleGalleryEntries((current) => { const nextEntries = current.filter( (entry) => entry.profileId !== item.profileId, @@ -10873,11 +10935,7 @@ export function PlatformEntryFlowShellImpl({ null, ); returnToCreationFlowSource(); - }, [ - autosaveCoordinator, - returnToCreationFlowSource, - sessionController, - ]); + }, [autosaveCoordinator, returnToCreationFlowSource, sessionController]); const leaveAgentDraftGeneration = useCallback(() => { if (sessionController.isActiveGenerationRunning) { @@ -10897,11 +10955,7 @@ export function PlatformEntryFlowShellImpl({ sessionController.setCustomWorldGenerationViewSource(null); sessionController.setCustomWorldResultViewSource(null); returnToCreationFlowSource(); - }, [ - autosaveCoordinator, - returnToCreationFlowSource, - sessionController, - ]); + }, [autosaveCoordinator, returnToCreationFlowSource, sessionController]); const leaveCustomWorldResult = useCallback(() => { sessionController.setGeneratedCustomWorldProfile(null); @@ -11887,7 +11941,12 @@ export function PlatformEntryFlowShellImpl({ setIsJumpHopBusy(false); } }, - [enterCreateTab, markDraftNoticeSeen, openPublicWorkDetail, setSelectionStage], + [ + enterCreateTab, + markDraftNoticeSeen, + openPublicWorkDetail, + setSelectionStage, + ], ); const openWoodenFishPublicWorkDetail = useCallback( @@ -12195,16 +12254,14 @@ export function PlatformEntryFlowShellImpl({ item.sourceSessionId, ); const payload = buildPuzzleFormPayloadFromSession(latestSession); - const generationState = createMiniGameDraftGenerationStateForRestoredDraft( - 'puzzle', - { + const generationState = + createMiniGameDraftGenerationStateForRestoredDraft('puzzle', { puzzleAiRedraw: payload.aiRedraw ?? true, puzzleProgressPercent: latestSession.draft && !latestSession.draft.formDraft ? latestSession.progressPercent : undefined, - }, - ); + }); puzzleFlow.setSession(latestSession); setPuzzleFormDraftPayload(payload); setPuzzleGenerationState( @@ -12401,10 +12458,9 @@ export function PlatformEntryFlowShellImpl({ setMatch3DSession(latestSession); setMatch3DFormDraftPayload(null); setMatch3DProfile(null); - const generationState = - rebaseMiniGameDraftGenerationStateForDisplay( - createMiniGameDraftGenerationStateForRestoredDraft('match3d'), - ); + const generationState = rebaseMiniGameDraftGenerationStateForDisplay( + createMiniGameDraftGenerationStateForRestoredDraft('match3d'), + ); setMatch3DGenerationState(generationState); enterCreateTab(); selectionStageRef.current = 'match3d-generating'; @@ -12603,14 +12659,18 @@ export function PlatformEntryFlowShellImpl({ }; setBarkBattleDraftConfig(nextDraft); enterCreateTab(); - selectionStageRef.current = - isPersistedBarkBattleDraftGenerating(item) - ? 'bark-battle-generating' - : 'bark-battle-result'; + selectionStageRef.current = isPersistedBarkBattleDraftGenerating(item) + ? 'bark-battle-generating' + : 'bark-battle-result'; setSelectionStage(selectionStageRef.current); writeCreationUrlState(buildBarkBattleCreationUrlState(nextDraft)); }, - [enterCreateTab, markDraftNoticeSeen, openPublicWorkDetail, setSelectionStage], + [ + enterCreateTab, + markDraftNoticeSeen, + openPublicWorkDetail, + setSelectionStage, + ], ); const openVisualNovelDraft = useCallback( @@ -12730,17 +12790,19 @@ export function PlatformEntryFlowShellImpl({ const profileId = normalizeCreationUrlValue( initialCreationUrlState.profileId, ); - const draftId = normalizeCreationUrlValue(initialCreationUrlState.draftId); + const draftId = normalizeCreationUrlValue( + initialCreationUrlState.draftId, + ); const workId = normalizeCreationUrlValue(initialCreationUrlState.workId); if (path.startsWith('/creation/big-fish')) { - const targetSessionId = sessionId ?? workId?.replace(/^big-fish-work-/u, ''); + const targetSessionId = + sessionId ?? workId?.replace(/^big-fish-work-/u, ''); if (targetSessionId) { const matchedWork = - ( - bigFishWorks.length > 0 - ? bigFishWorks - : (await listBigFishWorks().catch(() => ({ items: [] }))).items + (bigFishWorks.length > 0 + ? bigFishWorks + : (await listBigFishWorks().catch(() => ({ items: [] }))).items ).find( (item) => item.sourceSessionId === targetSessionId || @@ -12757,12 +12819,11 @@ export function PlatformEntryFlowShellImpl({ if (path.startsWith('/creation/match3d')) { const matchedWork = - ( - match3dWorks.length > 0 - ? match3dWorks - : mapMatch3DWorksForRuntimeUi( - (await listMatch3DWorks().catch(() => ({ items: [] }))).items, - ) + (match3dWorks.length > 0 + ? match3dWorks + : mapMatch3DWorksForRuntimeUi( + (await listMatch3DWorks().catch(() => ({ items: [] }))).items, + ) ).find( (item) => item.sourceSessionId === sessionId || @@ -12781,10 +12842,9 @@ export function PlatformEntryFlowShellImpl({ if (path.startsWith('/creation/square-hole')) { const matchedWork = - ( - squareHoleWorks.length > 0 - ? squareHoleWorks - : (await listSquareHoleWorks().catch(() => ({ items: [] }))).items + (squareHoleWorks.length > 0 + ? squareHoleWorks + : (await listSquareHoleWorks().catch(() => ({ items: [] }))).items ).find( (item) => item.sourceSessionId === sessionId || @@ -12803,10 +12863,9 @@ export function PlatformEntryFlowShellImpl({ if (path.startsWith('/creation/puzzle')) { const matchedWork = - ( - puzzleWorks.length > 0 - ? puzzleWorks - : (await listPuzzleWorks().catch(() => ({ items: [] }))).items + (puzzleWorks.length > 0 + ? puzzleWorks + : (await listPuzzleWorks().catch(() => ({ items: [] }))).items ).find( (item) => item.sourceSessionId === sessionId || @@ -12825,10 +12884,9 @@ export function PlatformEntryFlowShellImpl({ if (path.startsWith('/creation/visual-novel')) { const matchedWork = - ( - visualNovelWorks.length > 0 - ? visualNovelWorks - : (await listVisualNovelWorks().catch(() => ({ works: [] }))).works + (visualNovelWorks.length > 0 + ? visualNovelWorks + : (await listVisualNovelWorks().catch(() => ({ works: [] }))).works ).find((item) => item.profileId === profileId) ?? null; if (matchedWork) { await openVisualNovelDraft(matchedWork, { forceDraft: true }); @@ -12842,10 +12900,9 @@ export function PlatformEntryFlowShellImpl({ if (path.startsWith('/creation/bark-battle')) { const matchedWork = - ( - barkBattleWorks.length > 0 - ? barkBattleWorks - : (await listBarkBattleWorks().catch(() => ({ items: [] }))).items + (barkBattleWorks.length > 0 + ? barkBattleWorks + : (await listBarkBattleWorks().catch(() => ({ items: [] }))).items ).find( (item) => item.workId === workId || item.draftId === draftId, ) ?? null; @@ -12857,10 +12914,9 @@ export function PlatformEntryFlowShellImpl({ if (path.startsWith('/creation/baby-object-match')) { const matchedDraft = - ( - babyObjectMatchDrafts.length > 0 - ? babyObjectMatchDrafts - : await listLocalBabyObjectMatchDrafts().catch(() => []) + (babyObjectMatchDrafts.length > 0 + ? babyObjectMatchDrafts + : await listLocalBabyObjectMatchDrafts().catch(() => []) ).find( (item) => item.profileId === profileId || @@ -12885,7 +12941,9 @@ export function PlatformEntryFlowShellImpl({ } setJumpHopSession(session); setJumpHopWork(work); - writeCreationUrlState(buildJumpHopCreationUrlState({ session, work })); + writeCreationUrlState( + buildJumpHopCreationUrlState({ session, work }), + ); enterCreateTab(); setSelectionStage( path.includes('/generating') @@ -13019,7 +13077,13 @@ export function PlatformEntryFlowShellImpl({ return false; } }, - [authUi, bigFishFlow, resolveBigFishErrorMessage, setBigFishError, setSelectionStage], + [ + authUi, + bigFishFlow, + resolveBigFishErrorMessage, + setBigFishError, + setSelectionStage, + ], ); const startBarkBattleRunFromWork = useCallback( @@ -13334,8 +13398,9 @@ export function PlatformEntryFlowShellImpl({ ); } else if (isBarkBattleGalleryEntry(entry)) { const work = - barkBattleGalleryEntries.find((item) => item.workId === entry.workId) ?? - mapBarkBattlePublicDetailToWorkSummary(entry); + barkBattleGalleryEntries.find( + (item) => item.workId === entry.workId, + ) ?? mapBarkBattlePublicDetailToWorkSummary(entry); if (!work) { setBarkBattleError( '当前汪汪声浪作品信息不完整,暂时无法进入玩法。', @@ -13756,7 +13821,10 @@ export function PlatformEntryFlowShellImpl({ ); } - if (activeRecommendRuntimeKind === 'bark-battle' && barkBattlePublishedConfig) { + if ( + activeRecommendRuntimeKind === 'bark-battle' && + barkBattlePublishedConfig + ) { return ( work.workId === entry.workId) ?? - barkBattleGalleryEntries.find((work) => work.workId === entry.workId) ?? + barkBattleGalleryEntries.find( + (work) => work.workId === entry.workId, + ) ?? mapBarkBattlePublicDetailToWorkSummary(entry); if (!matchedWork?.draftId?.trim()) { setPublicWorkDetailError('这份汪汪声浪缺少可编辑草稿。'); @@ -15626,21 +15696,28 @@ export function PlatformEntryFlowShellImpl({ } > - { - void executeMatch3DAction(payload); - }} - initialFormPayload={match3dFormDraftPayload} - onCreateFromForm={(payload) => { - runProtectedAction(() => { - void createMatch3DDraftFromForm(payload); - }); - }} - /> + + { + void executeMatch3DAction(payload); + }} + initialFormPayload={match3dFormDraftPayload} + onCreateFromForm={(payload) => { + runProtectedAction(() => { + void createMatch3DDraftFromForm(payload); + }); + }} + /> + )} @@ -15656,7 +15733,8 @@ export function PlatformEntryFlowShellImpl({ } > - @@ -16413,14 +16481,21 @@ export function PlatformEntryFlowShellImpl({ } > - { - void compileWoodenFishSession(result, payload); - }} - /> + + { + void compileWoodenFishSession(result, payload); + }} + /> + )} @@ -16436,7 +16511,8 @@ export function PlatformEntryFlowShellImpl({ } > - @@ -16570,25 +16636,32 @@ export function PlatformEntryFlowShellImpl({ } > - { - void submitPuzzleMessage(payload); - }} - onExecuteAction={(payload) => { - executePuzzleWorkspaceAction(payload); - }} - initialFormPayload={puzzleFormDraftPayload} - onCreateFromForm={(payload) => { - void createPuzzleDraftFromForm(payload); - }} - onAutoSaveForm={(payload) => { - void savePuzzleFormDraft(payload); - }} - /> + + { + void submitPuzzleMessage(payload); + }} + onExecuteAction={(payload) => { + executePuzzleWorkspaceAction(payload); + }} + initialFormPayload={puzzleFormDraftPayload} + onCreateFromForm={(payload) => { + void createPuzzleDraftFromForm(payload); + }} + onAutoSaveForm={(payload) => { + void savePuzzleFormDraft(payload); + }} + /> + )} @@ -16626,7 +16699,8 @@ export function PlatformEntryFlowShellImpl({ } > - @@ -17028,32 +17093,33 @@ export function PlatformEntryFlowShellImpl({ )} - {selectionStage === 'bark-battle-generating' && barkBattleDraftConfig && ( - - } + {selectionStage === 'bark-battle-generating' && + barkBattleDraftConfig && ( + - { - enterCreateTab(); - selectionStageRef.current = 'platform'; - setSelectionStage('platform'); - }} - onComplete={handleBarkBattleGenerationComplete} - onError={setBarkBattleError} - /> - - - )} + } + > + { + enterCreateTab(); + selectionStageRef.current = 'platform'; + setSelectionStage('platform'); + }} + onComplete={handleBarkBattleGenerationComplete} + onError={setBarkBattleError} + /> + + + )} {selectionStage === 'bark-battle-result' && barkBattleDraftConfig && ( )} - {selectionStage === 'bark-battle-runtime' && barkBattlePublishedConfig && ( - - } + {selectionStage === 'bark-battle-runtime' && + barkBattlePublishedConfig && ( + - { - if ( - barkBattleRuntimeReturnStage === 'bark-battle-result' && - barkBattleDraftConfig - ) { - setSelectionStage('bark-battle-result'); - } else { - enterCreateTab(); - setSelectionStage('platform'); - } - }} - /> - - - )} + } + > + { + if ( + barkBattleRuntimeReturnStage === 'bark-battle-result' && + barkBattleDraftConfig + ) { + setSelectionStage('bark-battle-result'); + } else { + enterCreateTab(); + setSelectionStage('platform'); + } + }} + /> + + + )} {selectionStage === 'custom-world-result' && sessionController.generatedCustomWorldProfile && ( @@ -17319,7 +17386,7 @@ export function PlatformEntryFlowShellImpl({ {creationEntryConfig ? ( - { + test('按后端字段 spec 暴露统一创作页字段契约', () => { + render( + +
敲木鱼工作台
+
, + ); + + const root = screen + .getByText('敲木鱼工作台') + .closest('.unified-creation-page'); + expect(root?.getAttribute('data-play-id')).toBe('wooden-fish'); + expect(root?.getAttribute('data-field-kinds')).toBe( + 'text,image,audio,text', + ); + expect(root?.getAttribute('data-workspace-stage')).toBe( + 'wooden-fish-workspace', + ); + expect(root?.getAttribute('data-generation-stage')).toBe( + 'wooden-fish-generating', + ); + expect(root?.getAttribute('data-result-stage')).toBe('wooden-fish-result'); + + const fields = screen.getAllByTestId('unified-creation-field'); + expect(fields.map((field) => field.getAttribute('data-field-id'))).toEqual([ + 'hitObjectPrompt', + 'hitObjectReferenceImage', + 'hitSoundAsset', + 'floatingWords', + ]); + expect(fields[2]?.getAttribute('data-field-kind')).toBe('audio'); + expect(fields[3]?.getAttribute('data-required')).toBe('true'); + }); +}); diff --git a/src/components/unified-creation/UnifiedCreationPage.tsx b/src/components/unified-creation/UnifiedCreationPage.tsx new file mode 100644 index 00000000..950b01d7 --- /dev/null +++ b/src/components/unified-creation/UnifiedCreationPage.tsx @@ -0,0 +1,44 @@ +import type { ReactNode } from 'react'; + +import type { UnifiedCreationSpec } from './unifiedCreationSpecs'; + +type UnifiedCreationPageProps = { + spec: UnifiedCreationSpec; + children: ReactNode; +}; + +export function UnifiedCreationPage({ + spec, + children, +}: UnifiedCreationPageProps) { + return ( +
field.kind).join(',')} + data-workspace-stage={spec.workspaceStage} + data-generation-stage={spec.generationStage} + data-result-stage={spec.resultStage} + > +
+

{spec.title}

+
    + {spec.fields.map((field) => ( +
  • + {field.label} +
  • + ))} +
+
+ {children} +
+ ); +} + +export default UnifiedCreationPage; diff --git a/src/components/unified-creation/UnifiedGenerationPage.test.tsx b/src/components/unified-creation/UnifiedGenerationPage.test.tsx new file mode 100644 index 00000000..015199b2 --- /dev/null +++ b/src/components/unified-creation/UnifiedGenerationPage.test.tsx @@ -0,0 +1,53 @@ +/* @vitest-environment jsdom */ + +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; + +import type { CustomWorldGenerationProgress } from '../../../packages/shared/src/contracts/runtime'; +import { UnifiedGenerationPage } from './UnifiedGenerationPage'; + +function createProgress(): CustomWorldGenerationProgress { + return { + phaseId: 'puzzle-cover-image', + phaseLabel: '生成拼图首图', + phaseDetail: '正在生成图片。', + batchLabel: '生成拼图首图', + overallProgress: 36, + completedWeight: 36, + totalWeight: 100, + elapsedMs: 12_000, + estimatedRemainingMs: 30_000, + activeStepIndex: 0, + steps: [ + { + id: 'puzzle-cover-image', + label: '生成拼图首图', + detail: '正在生成图片。', + completed: 0.36, + total: 1, + status: 'active', + }, + ], + }; +} + +describe('UnifiedGenerationPage', () => { + test('按玩法下发统一生成页文案并透传进度', () => { + render( + {}} + onEditSetting={() => {}} + onRetry={() => {}} + />, + ); + + expect(document.body.textContent).toContain('拼图图片生成进度'); + expect(screen.getByText('图片生成中')).toBeTruthy(); + expect(screen.getAllByText('生成拼图首图').length).toBeGreaterThan(0); + expect(screen.getByText('当前拼图信息')).toBeTruthy(); + }); +}); diff --git a/src/components/unified-creation/UnifiedGenerationPage.tsx b/src/components/unified-creation/UnifiedGenerationPage.tsx new file mode 100644 index 00000000..e50f823e --- /dev/null +++ b/src/components/unified-creation/UnifiedGenerationPage.tsx @@ -0,0 +1,91 @@ +import type { CustomWorldGenerationProgress } from '../../../packages/shared/src/contracts/runtime'; +import type { CustomWorldStructuredAnchorEntry } from '../../services/customWorldAgentGenerationProgress'; +import { CustomWorldGenerationView } from '../CustomWorldGenerationView'; +import type { UnifiedCreationPlayId } from './unifiedCreationSpecs'; + +type UnifiedGenerationPageProps = { + playId: UnifiedCreationPlayId; + settingText: string; + anchorEntries?: CustomWorldStructuredAnchorEntry[]; + progress: CustomWorldGenerationProgress | null; + isGenerating: boolean; + error?: string | null; + onBack: () => void; + onEditSetting: () => void; + onRetry: () => void; + hideBatchModule?: boolean; +}; + +const UNIFIED_GENERATION_COPY = { + puzzle: { + retryLabel: '重新生成图片', + settingTitle: '当前拼图信息', + progressTitle: '拼图图片生成进度', + activeBadgeLabel: '图片生成中', + }, + match3d: { + retryLabel: '重新生成草稿', + settingTitle: '当前抓大鹅信息', + progressTitle: '抓大鹅草稿生成进度', + activeBadgeLabel: '素材生成中', + }, + 'wooden-fish': { + retryLabel: '重新生成草稿', + settingTitle: '当前敲木鱼信息', + progressTitle: '敲木鱼草稿生成进度', + activeBadgeLabel: '素材生成中', + }, +} as const satisfies Record< + UnifiedCreationPlayId, + { + retryLabel: string; + settingTitle: string; + progressTitle: string; + activeBadgeLabel: string; + } +>; + +export function getUnifiedGenerationCopy(playId: UnifiedCreationPlayId) { + return UNIFIED_GENERATION_COPY[playId]; +} + +export function UnifiedGenerationPage({ + playId, + settingText, + anchorEntries = [], + progress, + isGenerating, + error = null, + onBack, + onEditSetting, + onRetry, + hideBatchModule = false, +}: UnifiedGenerationPageProps) { + const copy = getUnifiedGenerationCopy(playId); + + return ( + + ); +} + +export default UnifiedGenerationPage; diff --git a/src/components/unified-creation/unifiedCreationSpecs.test.ts b/src/components/unified-creation/unifiedCreationSpecs.test.ts new file mode 100644 index 00000000..5d18ca54 --- /dev/null +++ b/src/components/unified-creation/unifiedCreationSpecs.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, test } from 'vitest'; + +import { + getUnifiedCreationSpec, + listUnifiedCreationSpecs, +} from './unifiedCreationSpecs'; + +describe('unified creation specs', () => { + test('一期只接拼图、抓大鹅和敲木鱼', () => { + expect(listUnifiedCreationSpecs().map((spec) => spec.playId).sort()).toEqual( + ['match3d', 'puzzle', 'wooden-fish'], + ); + }); + + test('字段模型只包含首期公共能力', () => { + const fieldKinds = new Set( + listUnifiedCreationSpecs().flatMap((spec) => + spec.fields.map((field) => field.kind), + ), + ); + + expect([...fieldKinds].sort()).toEqual(['audio', 'image', 'select', 'text']); + }); + + test('三条链路都映射到统一创作、生成、结果阶段', () => { + expect(getUnifiedCreationSpec('puzzle')).toMatchObject({ + workspaceStage: 'puzzle-agent-workspace', + generationStage: 'puzzle-generating', + resultStage: 'puzzle-result', + }); + expect(getUnifiedCreationSpec('match3d')).toMatchObject({ + workspaceStage: 'match3d-agent-workspace', + generationStage: 'match3d-generating', + resultStage: 'match3d-result', + }); + expect(getUnifiedCreationSpec('wooden-fish')).toMatchObject({ + workspaceStage: 'wooden-fish-workspace', + generationStage: 'wooden-fish-generating', + resultStage: 'wooden-fish-result', + }); + }); +}); diff --git a/src/components/unified-creation/unifiedCreationSpecs.ts b/src/components/unified-creation/unifiedCreationSpecs.ts new file mode 100644 index 00000000..7a849fc4 --- /dev/null +++ b/src/components/unified-creation/unifiedCreationSpecs.ts @@ -0,0 +1,107 @@ +import type { + CreationEntryTypeConfig, + UnifiedCreationSpec, +} from '../../services/creationEntryConfigService'; + +export type UnifiedCreationPlayId = UnifiedCreationSpec['playId']; +export type { UnifiedCreationSpec }; + +const FALLBACK_UNIFIED_CREATION_SPECS: Record< + UnifiedCreationPlayId, + UnifiedCreationSpec +> = { + puzzle: { + playId: 'puzzle', + title: '想做个什么玩法?', + workspaceStage: 'puzzle-agent-workspace', + generationStage: 'puzzle-generating', + resultStage: 'puzzle-result', + fields: [ + { + id: 'pictureDescription', + kind: 'text', + label: '画面描述', + required: true, + }, + { + id: 'referenceImage', + kind: 'image', + label: '拼图画面', + required: false, + }, + { + id: 'promptReferenceImages', + kind: 'image', + label: '参考图', + required: false, + }, + ], + }, + match3d: { + playId: 'match3d', + title: '想做个什么玩法?', + workspaceStage: 'match3d-agent-workspace', + generationStage: 'match3d-generating', + resultStage: 'match3d-result', + fields: [ + { + id: 'themeText', + kind: 'text', + label: '题材', + required: true, + }, + { + id: 'difficulty', + kind: 'select', + label: '难度', + required: true, + }, + ], + }, + 'wooden-fish': { + playId: 'wooden-fish', + title: '想做个什么玩法?', + workspaceStage: 'wooden-fish-workspace', + generationStage: 'wooden-fish-generating', + resultStage: 'wooden-fish-result', + fields: [ + { + id: 'hitObjectPrompt', + kind: 'text', + label: '敲什么', + required: false, + }, + { + id: 'hitObjectReferenceImage', + kind: 'image', + label: '参考图', + required: false, + }, + { + id: 'hitSoundAsset', + kind: 'audio', + label: '敲击音效', + required: false, + }, + { + id: 'floatingWords', + kind: 'text', + label: '功德有什么', + required: true, + }, + ], + }, +}; + +export function getUnifiedCreationSpec( + playId: UnifiedCreationPlayId, + configType?: CreationEntryTypeConfig | null, +) { + return ( + configType?.unifiedCreationSpec ?? FALLBACK_UNIFIED_CREATION_SPECS[playId] + ); +} + +export function listUnifiedCreationSpecs() { + return Object.values(FALLBACK_UNIFIED_CREATION_SPECS); +} diff --git a/src/components/wooden-fish-creation/WoodenFishWorkspace.tsx b/src/components/wooden-fish-creation/WoodenFishWorkspace.tsx index 9cd0e387..3d100f39 100644 --- a/src/components/wooden-fish-creation/WoodenFishWorkspace.tsx +++ b/src/components/wooden-fish-creation/WoodenFishWorkspace.tsx @@ -1,14 +1,11 @@ import { ArrowLeft, Loader2, - Mic, - Pause, Plus, Send, X, - Upload, } from 'lucide-react'; -import { useMemo, useRef, useState } from 'react'; +import { useMemo, useState } from 'react'; import type { WoodenFishAudioAsset, @@ -21,6 +18,7 @@ import { WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT, WOODEN_FISH_DEFAULT_HIT_SOUND_ASSET, } from '../../services/wooden-fish/woodenFishDefaults'; +import { CreativeAudioInputPanel } from '../common/CreativeAudioInputPanel'; import { CreativeImageInputPanel } from '../common/CreativeImageInputPanel'; type WoodenFishWorkspaceProps = { @@ -68,182 +66,6 @@ function normalizeFloatingWords(words: string[]) { return normalized.length > 0 ? normalized : [...DEFAULT_FLOATING_WORDS]; } -function readAudioFileAsAsset(file: File, source: 'uploaded' | 'recorded') { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onerror = () => reject(new Error('音频读取失败,请重试。')); - reader.onload = () => { - if (typeof reader.result !== 'string') { - reject(new Error('音频读取失败,请重试。')); - return; - } - resolve({ - assetId: `local-${source}-${Date.now()}`, - audioSrc: reader.result, - audioObjectKey: '', - assetObjectId: '', - source, - prompt: file.name, - durationMs: null, - }); - }; - reader.readAsDataURL(file); - }); -} - -function WoodenFishAudioInputPanel({ - disabled, - asset, - onAssetChange, - onError, -}: { - disabled: boolean; - asset: WoodenFishAudioAsset | null; - onAssetChange: (asset: WoodenFishAudioAsset | null) => void; - onError: (message: string | null) => void; -}) { - const [isRecording, setIsRecording] = useState(false); - const recorderRef = useRef(null); - const chunksRef = useRef([]); - - const startRecording = async () => { - if (disabled || isRecording) { - return; - } - - try { - if ( - typeof navigator === 'undefined' || - !navigator.mediaDevices?.getUserMedia || - typeof MediaRecorder === 'undefined' - ) { - throw new Error('当前浏览器不支持录音。'); - } - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - const recorder = new MediaRecorder(stream); - chunksRef.current = []; - recorder.ondataavailable = (event) => { - if (event.data.size > 0) { - chunksRef.current.push(event.data); - } - }; - recorder.onstop = () => { - const blob = new Blob(chunksRef.current, { - type: recorder.mimeType || 'audio/webm', - }); - stream.getTracks().forEach((track) => track.stop()); - const file = new File([blob], `wooden-fish-hit-${Date.now()}.webm`, { - type: blob.type, - }); - void readAudioFileAsAsset(file, 'recorded') - .then(onAssetChange) - .catch((caughtError) => { - onError( - caughtError instanceof Error - ? caughtError.message - : '录音保存失败。', - ); - }); - }; - recorderRef.current = recorder; - recorder.start(); - setIsRecording(true); - onError(null); - } catch (caughtError) { - onError( - caughtError instanceof Error ? caughtError.message : '录音启动失败。', - ); - } - }; - - const stopRecording = () => { - recorderRef.current?.stop(); - recorderRef.current = null; - setIsRecording(false); - }; - - return ( -
-
-
- 敲击音效 -
- {asset ? ( - - ) : null} -
-
- - - {asset?.audioSrc ? ( -
-
- ); -} - export function WoodenFishWorkspace({ isBusy = false, error = null, @@ -410,9 +232,12 @@ export function WoodenFishWorkspace({
- disabled={isBusy || isSubmitting} + title="敲击音效" + defaultLabel="默认木鱼音" asset={formState.hitSoundAsset} + buildRecordedFileName={() => `wooden-fish-hit-${Date.now()}.webm`} onAssetChange={(asset) => setFormState((current) => ({ ...current, diff --git a/src/services/creationEntryConfigService.ts b/src/services/creationEntryConfigService.ts index 2f38e371..7e3a33bb 100644 --- a/src/services/creationEntryConfigService.ts +++ b/src/services/creationEntryConfigService.ts @@ -13,6 +13,29 @@ export type CreationEntryTypeConfig = { categoryLabel: string; categorySortOrder: number; updatedAtMicros: number; + unifiedCreationSpec?: UnifiedCreationSpec | null; +}; + +export type UnifiedCreationField = { + id: string; + kind: 'text' | 'select' | 'image' | 'audio'; + label: string; + required: boolean; +}; + +export type UnifiedCreationSpec = { + playId: 'puzzle' | 'match3d' | 'wooden-fish'; + title: string; + workspaceStage: + | 'puzzle-agent-workspace' + | 'match3d-agent-workspace' + | 'wooden-fish-workspace'; + generationStage: + | 'puzzle-generating' + | 'match3d-generating' + | 'wooden-fish-generating'; + resultStage: 'puzzle-result' | 'match3d-result' | 'wooden-fish-result'; + fields: UnifiedCreationField[]; }; export type CreationEntryConfig = { diff --git a/src/services/miniGameDraftGenerationProgress.ts b/src/services/miniGameDraftGenerationProgress.ts index 58232ee9..d92c383a 100644 --- a/src/services/miniGameDraftGenerationProgress.ts +++ b/src/services/miniGameDraftGenerationProgress.ts @@ -467,6 +467,24 @@ function clampProgress(value: number) { return Math.max(0, Math.min(100, Math.round(value))); } +export function resolveMiniGameDraftGenerationStartedAtMs( + startedAt: string | number | null | undefined, + fallbackMs = Date.now(), +) { + if (typeof startedAt === 'number' && Number.isFinite(startedAt)) { + return startedAt; + } + + if (typeof startedAt === 'string') { + const parsed = Date.parse(startedAt); + if (Number.isFinite(parsed)) { + return parsed; + } + } + + return fallbackMs; +} + function getStepDefinitions(kind: MiniGameDraftGenerationKind) { if (kind === 'puzzle') { return buildPuzzleSteps(createMiniGameDraftGenerationState('puzzle')); @@ -542,6 +560,7 @@ function buildMiniGameProgressSteps( export function createMiniGameDraftGenerationState( kind: MiniGameDraftGenerationKind, + startedAtMs = Date.now(), ): MiniGameDraftGenerationState { return { kind, @@ -559,7 +578,7 @@ export function createMiniGameDraftGenerationState( : kind === 'wooden-fish' ? 'wooden-fish-draft' : 'compile', - startedAtMs: Date.now(), + startedAtMs, completedAssetCount: 0, totalAssetCount: 0, error: null, From c02dcd8aaf1b7df2da7bb10a261abd45033e5a9a Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Sat, 30 May 2026 15:15:53 +0800 Subject: [PATCH 05/31] fix wechat virtual payment signature --- .../crates/api-server/src/runtime_profile.rs | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/server-rs/crates/api-server/src/runtime_profile.rs b/server-rs/crates/api-server/src/runtime_profile.rs index effe4f8d..5bb731b7 100644 --- a/server-rs/crates/api-server/src/runtime_profile.rs +++ b/server-rs/crates/api-server/src/runtime_profile.rs @@ -1217,7 +1217,8 @@ fn build_wechat_virtual_pay_params( } let sign_data = sign_data.to_string(); let pay_sig = calc_wechat_virtual_payment_signature(state, &sign_data, false)?; - let signature = calc_wechat_virtual_payment_signature_with_key(&session_key, &sign_data)?; + let signature = + calc_wechat_virtual_payment_user_signature_with_key(&session_key, &sign_data)?; Ok(WechatMiniProgramVirtualPayParamsResponse { mode: mode.to_string(), @@ -1251,7 +1252,7 @@ fn calc_wechat_virtual_payment_signature( .ok_or_else(|| { AppError::from_status(StatusCode::BAD_REQUEST).with_message("微信虚拟支付 AppKey 未配置") })?; - calc_wechat_virtual_payment_signature_with_key(app_key, sign_data) + calc_wechat_virtual_payment_pay_signature_with_key(app_key, sign_data) } fn required_wechat_virtual_payment_config<'a>( @@ -1264,7 +1265,7 @@ fn required_wechat_virtual_payment_config<'a>( .ok_or_else(|| AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message(message)) } -fn calc_wechat_virtual_payment_signature_with_key( +fn calc_wechat_virtual_payment_pay_signature_with_key( key: &str, sign_data: &str, ) -> Result { @@ -1276,6 +1277,18 @@ fn calc_wechat_virtual_payment_signature_with_key( Ok(to_lower_hex(mac.finalize().into_bytes().as_slice())) } +fn calc_wechat_virtual_payment_user_signature_with_key( + session_key: &str, + sign_data: &str, +) -> Result { + let mut mac = HmacSha256::new_from_slice(session_key.as_bytes()).map_err(|_| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR) + .with_message("微信虚拟支付用户态签名密钥初始化失败") + })?; + mac.update(sign_data.as_bytes()); + Ok(to_lower_hex(mac.finalize().into_bytes().as_slice())) +} + fn to_lower_hex(bytes: &[u8]) -> String { const HEX: &[u8; 16] = b"0123456789abcdef"; let mut output = String::with_capacity(bytes.len() * 2); @@ -1765,8 +1778,9 @@ mod tests { }; use super::{ - build_wechat_virtual_pay_params, format_profile_wallet_ledger_source_type, - normalize_admin_invite_code_metadata, + build_wechat_virtual_pay_params, calc_wechat_virtual_payment_pay_signature_with_key, + calc_wechat_virtual_payment_user_signature_with_key, + format_profile_wallet_ledger_source_type, normalize_admin_invite_code_metadata, }; use axum::{ @@ -2345,6 +2359,29 @@ mod tests { assert_eq!(sign_data["outTradeNo"], "item01order01"); } + #[test] + fn wechat_virtual_payment_signatures_match_official_examples() { + let post_body = r#"{"openid": "xxx", "user_ip": "127.0.0.1", "env": 0}"#; + + let pay_sig = + calc_wechat_virtual_payment_pay_signature_with_key("12345", post_body) + .expect("pay signature should build"); + let signature = calc_wechat_virtual_payment_user_signature_with_key( + "9hAb/NEYUlkaMBEsmFgzig==", + post_body, + ) + .expect("user signature should build"); + + assert_eq!( + pay_sig, + "a1ab2651b927b6a766152cf864033417b85c1448fc3c6e1bedbbd7f49416e92f" + ); + assert_eq!( + signature, + "089d9e8dc5d308977360c4b79ec600a93d736802802a807d634192328032f6c7" + ); + } + #[tokio::test] async fn profile_feedback_requires_authentication() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); From e941ac4539ca14a85e903b6c1614dd5c9b2bd489 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Sat, 30 May 2026 15:43:07 +0800 Subject: [PATCH 06/31] fix wechat virtual payment sandbox app key --- .../crates/api-server/src/runtime_profile.rs | 80 +++++++++++++++---- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/server-rs/crates/api-server/src/runtime_profile.rs b/server-rs/crates/api-server/src/runtime_profile.rs index 5bb731b7..6e37e17c 100644 --- a/server-rs/crates/api-server/src/runtime_profile.rs +++ b/server-rs/crates/api-server/src/runtime_profile.rs @@ -1235,23 +1235,22 @@ fn calc_wechat_virtual_payment_signature( ) -> Result { let env = state.config.wechat_mini_program_virtual_payment_env; let app_key = if use_sandbox_key || env == 1 { - state - .config - .wechat_mini_program_virtual_payment_sandbox_app_key - .as_deref() - .or(state + required_wechat_virtual_payment_config( + state + .config + .wechat_mini_program_virtual_payment_sandbox_app_key + .as_deref(), + "微信虚拟支付沙箱 AppKey 未配置", + )? + } else { + required_wechat_virtual_payment_config( + state .config .wechat_mini_program_virtual_payment_app_key - .as_deref()) - } else { - state - .config - .wechat_mini_program_virtual_payment_app_key - .as_deref() - } - .ok_or_else(|| { - AppError::from_status(StatusCode::BAD_REQUEST).with_message("微信虚拟支付 AppKey 未配置") - })?; + .as_deref(), + "微信虚拟支付 AppKey 未配置", + )? + }; calc_wechat_virtual_payment_pay_signature_with_key(app_key, sign_data) } @@ -2382,6 +2381,57 @@ mod tests { ); } + #[tokio::test] + async fn wechat_virtual_payment_sandbox_requires_sandbox_app_key() { + let state = seed_authenticated_state_with_config(AppConfig { + wechat_mini_program_virtual_payment_offer_id: Some("offer-1".to_string()), + wechat_mini_program_virtual_payment_app_key: Some("app-key-1".to_string()), + wechat_mini_program_virtual_payment_sandbox_app_key: None, + wechat_mini_program_virtual_payment_env: 1, + ..fast_spacetime_timeout_config() + }) + .await; + let wechat_login = state + .wechat_auth_service() + .resolve_login(ResolveWechatLoginInput { + profile: WechatIdentityProfile { + provider_uid: "openid-sandbox-1".to_string(), + provider_union_id: Some("union-sandbox-1".to_string()), + display_name: Some("资料页用户".to_string()), + avatar_url: None, + session_key: Some("session-key-sandbox-1".to_string()), + }, + }) + .await + .expect("wechat identity should seed"); + let order = RuntimeProfileRechargeOrderRecord { + order_id: "sandboxorder01".to_string(), + user_id: wechat_login.user.id, + product_id: "points_60".to_string(), + product_title: "60泥点".to_string(), + kind: RuntimeProfileRechargeProductKind::Points, + amount_cents: 600, + status: RuntimeProfileRechargeOrderStatus::Pending, + payment_channel: PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL + .to_string(), + paid_at: None, + paid_at_micros: None, + provider_transaction_id: None, + created_at: "2026-05-30T10:00:00Z".to_string(), + created_at_micros: 1_780_000_000_000_000, + points_delta: 0, + membership_expires_at: None, + membership_expires_at_micros: None, + }; + + let error = build_wechat_virtual_pay_params(&state, &order, "openid-sandbox-1") + .expect_err("sandbox pay params should reject missing sandbox app key"); + assert!( + error.to_string().contains("沙箱 AppKey 未配置"), + "unexpected error: {error}" + ); + } + #[tokio::test] async fn profile_feedback_requires_authentication() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); From aaaba77c3a859664607395008e7614b1a31fd7db Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Sat, 30 May 2026 16:42:25 +0800 Subject: [PATCH 07/31] fix wechat virtual payment coin flow --- .hermes/shared-memory/decision-log.md | 2 +- ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 +- ...【技术方案】微信虚拟支付接入-2026-05-26.md | 3 + miniprogram/pages/wechat-pay/index.shared.js | 5 + miniprogram/pages/wechat-pay/index.test.js | 11 +- .../crates/api-server/src/runtime_profile.rs | 241 +++++++++++++++++- .../RpgEntryHomeView.recharge.test.tsx | 205 +++++++++++++++ src/components/rpg-entry/RpgEntryHomeView.tsx | 40 ++- 8 files changed, 496 insertions(+), 13 deletions(-) diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 5b820053..e9addcc5 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -19,7 +19,7 @@ ## 2026-05-26 微信小程序充值全面接入虚拟支付 - 背景:泥点和会员都属于小程序内由 Genarrative 控制的虚拟资产/权益,继续走普通小程序支付不符合微信虚拟支付接入口径。 -- 决策:小程序 WebView 内充值商品全部使用渠道 `wechat_mp_virtual` 并由 `miniprogram/pages/wechat-pay` 调用 `wx.requestVirtualPayment`;泥点使用 `short_series_coin`,会员使用 `short_series_goods`,会员 `signData` 必须带 `productId` 与 `goodsPrice`。后端保存微信小程序 `session_key`,仅用于生成 `signature`,不下发客户端。客户端 success 只作为支付页返回信号,最终到账仍由后端微信通知或查询确认后写订单。 +- 决策:小程序 WebView 内充值商品全部使用渠道 `wechat_mp_virtual` 并由 `miniprogram/pages/wechat-pay` 调用 `wx.requestVirtualPayment`;泥点属于代币(coin),使用 `short_series_coin`,`buyQuantity` 必须取当前充值中心商品快照里的 `points_amount`;会员和后台新增道具类商品使用 `short_series_goods`,`signData` 必须带 `productId` 与 `goodsPrice`。后端保存微信小程序 `session_key`,仅用于生成 `signature`,不下发客户端。客户端 success 只作为支付页返回信号,最终到账仍由后端微信通知或查询确认后写订单。 - 影响范围:`src/services/payment/paymentPlatform.ts`、`src/components/rpg-entry/RpgEntryHomeView.tsx`、`miniprogram/pages/wechat-pay/`、`server-rs/crates/api-server/src/runtime_profile.rs`、`server-rs/crates/shared-contracts/src/runtime.rs`、`packages/shared/src/contracts/runtime.ts`、微信登录态存储。 - 验证方式:泥点和会员商品在小程序运行态都请求 `wechat_mp_virtual`;小程序页能按 payload 调用 `wx.requestVirtualPayment` / `wx.requestPayment`;`cargo check -p api-server --manifest-path server-rs/Cargo.toml` 与支付相关前端测试通过。 - 关联文档:`docs/【技术方案】微信虚拟支付接入-2026-05-26.md`。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index d2c50272..42395cc2 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -47,7 +47,7 @@ npm run dev:api-server 开发态 `npm run dev` 与 `npm run dev:api-server` 会默认注入 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true`,因此密码登录在本地开发环境可直接注册未知手机号账号;生产环境仍按 `api-server` 配置默认关闭该开关。 -微信小程序虚拟支付使用 `WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID`、`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY`、`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY` 和 `WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV` 配置。泥点充值在小程序 WebView 内走 `wechat_mp_virtual` / `wx.requestVirtualPayment`,会员仍走普通 `wechat_mp` / `wx.requestPayment`。旧登录快照若缺 `session_key`,需要用户在小程序内重新登录后再支付;客户端成功回调不是最终到账,仍以后端通知或查询确认订单为准。详细口径见 `docs/【技术方案】微信虚拟支付接入-2026-05-26.md`。 +微信小程序虚拟支付使用 `WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_OFFER_ID`、`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY`、`WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_SANDBOX_APP_KEY` 和 `WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV` 配置。小程序充值统一走 `wechat_mp_virtual` / `wx.requestVirtualPayment`:泥点属于代币(`coin`),`buyQuantity` 按当前充值商品快照里的 `points_amount` 传;会员和后台新增道具类商品走 `short_series_goods`,`productId` 对应微信后台道具 ID。旧登录快照若缺 `session_key`,需要用户在小程序内重新登录后再支付;客户端成功回调不是最终到账,仍以后端通知或查询确认订单为准。详细口径见 `docs/【技术方案】微信虚拟支付接入-2026-05-26.md`。 如果本地 `GET /api/creation-entry/config` 返回 `No such procedure`,或 `api-server` 日志出现 `no such table: puzzle_gallery_card_view` / `no such table: wooden_fish_gallery_card_view` 这类公开 view 缺失,通常是 `.env.local` 指向的 SpacetimeDB 库还没有发布当前 `spacetime-module`,或当前 CLI 身份无权发布该库。debug 构建的 `api-server` 会临时使用后端默认入口配置兜底,避免创作作品架整块消失;正式修复仍应切换到拥有目标库权限的 SpacetimeDB 身份后重新运行 `npm run dev` 完成发布,或用 gitignored 的 `spacetime.local.json` 指向可发布的本地库。 diff --git a/docs/【技术方案】微信虚拟支付接入-2026-05-26.md b/docs/【技术方案】微信虚拟支付接入-2026-05-26.md index c5fdf9ed..cf10599d 100644 --- a/docs/【技术方案】微信虚拟支付接入-2026-05-26.md +++ b/docs/【技术方案】微信虚拟支付接入-2026-05-26.md @@ -38,6 +38,7 @@ WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV=0 - `signData`:传给 `wx.requestVirtualPayment` 的订单数据。 - `paySig`:`HMAC-SHA256(appKey, "requestVirtualPayment&" + signData)` 的小写 hex。 - `signature`:`HMAC-SHA256(session_key, signData)` 的小写 hex。 +- 泥点属于微信虚拟支付代币(coin),`short_series_coin` 的 `buyQuantity` 必须使用当前泥点商品的 `points_amount`;例如 60 泥点商品应传 `buyQuantity: 60`。 - 会员直购 `signData` 额外包含 `productId` 和 `goodsPrice`;`goodsPrice` 使用后端商品配置价,和微信后台道具价格校验保持一致。 ## 验收命令 @@ -54,7 +55,9 @@ npm run check:encoding - 旧微信登录快照可能没有 `session_key`;小程序 WebView 会在普通进入时静默刷新一次微信登录态,刷新失败时仍允许匿名打开 WebView,但虚拟支付会继续由后端拦截并提示重新登录。 - 小程序充值商品全部映射到虚拟支付;泥点使用 `short_series_coin`,会员使用 `short_series_goods`。 +- `short_series_coin` 只用于代币购买,后端从本次下单返回的充值中心商品快照读取 `points_amount` 并写入 `buyQuantity`;不要把 coin 商品当成道具,也不要把 `buyQuantity` 固定为 1。 - 后台新增的会员类充值商品会直接把商品 `productId` 作为微信 `short_series_goods` 的道具 ID;例如微信后台道具 ID 为 `item01` 时,后台会员商品 `productId` 也应配置为 `item01`,且商品价格需要与微信后台道具价格一致。 - 小程序页必须保留普通支付与虚拟支付双分支,按 pay params 字段判断调用 `wx.requestPayment` 或 `wx.requestVirtualPayment`。 - 小程序支付承接页回传 `wx_pay_result` 时必须携带 `requestId:status:orderId[:error]`,并同时写入上一页 hash 与本地 storage;WebView `onShow` 会立即检查一次、延迟二次检查一次,且同名 hash 参数必须替换,避免支付状态停留在处理中或重复处理。 - 沙箱或基础库失败会把微信返回的 `errCode` / `errMsg` 透传到前端失败弹窗,便于区分微信后台道具、沙箱 AppKey、签名和基础库能力问题。 +- Web 侧在“正在支付”状态下会短时轮询 `wx_pay_result`,即使小程序 `web-view` 回写 hash 没触发浏览器 `hashchange`,也必须展示回写的微信错误内容。 diff --git a/miniprogram/pages/wechat-pay/index.shared.js b/miniprogram/pages/wechat-pay/index.shared.js index d35b3c7d..d25f527e 100644 --- a/miniprogram/pages/wechat-pay/index.shared.js +++ b/miniprogram/pages/wechat-pay/index.shared.js @@ -105,6 +105,10 @@ function requestOrdinaryPayment(payParams) { function requestVirtualPayment(payParams) { return new Promise((resolve) => { if (!canUseVirtualPayment() || typeof wx.requestVirtualPayment !== 'function') { + console.error('[wechat-pay] requestVirtualPayment unavailable', { + canUseVirtualPayment: canUseVirtualPayment(), + hasRequestVirtualPayment: typeof wx.requestVirtualPayment === 'function', + }); resolve({ status: 'fail', errorMessage: '当前微信基础库不支持 requestVirtualPayment', @@ -120,6 +124,7 @@ function requestVirtualPayment(payParams) { resolve({ status: 'success', errorMessage: '' }); }, fail(error) { + console.error('[wechat-pay] requestVirtualPayment failed', error); resolve({ status: resolvePayStatus(error), errorMessage: normalizePayError(error), diff --git a/miniprogram/pages/wechat-pay/index.test.js b/miniprogram/pages/wechat-pay/index.test.js index e4520aa5..1407c89a 100644 --- a/miniprogram/pages/wechat-pay/index.test.js +++ b/miniprogram/pages/wechat-pay/index.test.js @@ -11,6 +11,7 @@ const { describe('wechat-pay mini program payment bridge', () => { beforeEach(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}); globalThis.wx = { requestPayment: vi.fn(), requestVirtualPayment: vi.fn(), @@ -100,8 +101,12 @@ describe('wechat-pay mini program payment bridge', () => { }); test('maps virtual payment cancel errCode to cancel result', async () => { + const payError = { + errCode: -2, + errMsg: 'requestVirtualPayment:fail cancel', + }; globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => { - options.fail?.({ errCode: -2, errMsg: 'requestVirtualPayment:fail cancel' }); + options.fail?.(payError); }); await expect( @@ -118,6 +123,10 @@ describe('wechat-pay mini program payment bridge', () => { errMsg: 'requestVirtualPayment:fail cancel', }), }); + expect(console.error).toHaveBeenCalledWith( + '[wechat-pay] requestVirtualPayment failed', + payError, + ); }); test('page notifies previous web-view after virtual payment', async () => { diff --git a/server-rs/crates/api-server/src/runtime_profile.rs b/server-rs/crates/api-server/src/runtime_profile.rs index 6e37e17c..52823013 100644 --- a/server-rs/crates/api-server/src/runtime_profile.rs +++ b/server-rs/crates/api-server/src/runtime_profile.rs @@ -256,7 +256,7 @@ pub async fn create_profile_recharge_order( .await .map_err(|error| runtime_profile_error_response(&request_context, error))?; Some( - build_wechat_virtual_pay_params(&state, &order, &openid) + build_wechat_virtual_pay_params(&state, ¢er, &order, &openid) .map(WechatMiniProgramPaymentParamsResponse::Virtual) .map_err(|error| runtime_profile_error_response(&request_context, error))?, ) @@ -1169,9 +1169,28 @@ async fn resolve_wechat_identity_for_payment( fn build_wechat_virtual_pay_params( state: &AppState, + center: &RuntimeProfileRechargeCenterRecord, order: &RuntimeProfileRechargeOrderRecord, openid: &str, ) -> Result { + let product = match order.kind { + RuntimeProfileRechargeProductKind::Points => center + .point_products + .iter() + .find(|item| item.product_id == order.product_id) + .ok_or_else(|| { + AppError::from_status(StatusCode::BAD_REQUEST) + .with_message("当前充值商品不存在,请刷新后再试") + })?, + RuntimeProfileRechargeProductKind::Membership => center + .membership_products + .iter() + .find(|item| item.product_id == order.product_id) + .ok_or_else(|| { + AppError::from_status(StatusCode::BAD_REQUEST) + .with_message("当前充值商品不存在,请刷新后再试") + })?, + }; let identity = state .wechat_auth_service() .get_identity_by_user_id(&order.user_id) @@ -1198,9 +1217,13 @@ fn build_wechat_virtual_pay_params( RuntimeProfileRechargeProductKind::Points => "short_series_coin", RuntimeProfileRechargeProductKind::Membership => "short_series_goods", }; + let buy_quantity = match product.kind { + RuntimeProfileRechargeProductKind::Points => product.points_amount, + RuntimeProfileRechargeProductKind::Membership => 1, + }; let mut sign_data = serde_json::json!({ "offerId": offer_id, - "buyQuantity": 1, + "buyQuantity": buy_quantity, "env": state.config.wechat_mini_program_virtual_payment_env, "currencyType": "CNY", "outTradeNo": order.order_id, @@ -1772,8 +1795,11 @@ mod tests { use module_auth::{ResolveWechatLoginInput, WechatIdentityProfile}; use module_runtime::{ PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL, + RuntimeProfileMembershipRecord, RuntimeProfileMembershipStatus, + RuntimeProfileMembershipTier, RuntimeProfileRechargeCenterRecord, RuntimeProfileRechargeOrderRecord, RuntimeProfileRechargeOrderStatus, - RuntimeProfileRechargeProductKind, RuntimeProfileWalletLedgerSourceType, + RuntimeProfileRechargeProductKind, RuntimeProfileRechargeProductRecord, + RuntimeProfileWalletLedgerSourceType, }; use super::{ @@ -2284,7 +2310,39 @@ mod tests { membership_expires_at_micros: None, }; - let params = build_wechat_virtual_pay_params(&state, &order, "openid-user-00000001") + let center = RuntimeProfileRechargeCenterRecord { + user_id: user_id.clone(), + wallet_balance: 0, + membership: RuntimeProfileMembershipRecord { + user_id: user_id.clone(), + status: RuntimeProfileMembershipStatus::Normal, + tier: RuntimeProfileMembershipTier::Normal, + started_at: None, + started_at_micros: None, + expires_at: None, + expires_at_micros: None, + updated_at: None, + updated_at_micros: None, + }, + point_products: vec![], + membership_products: vec![RuntimeProfileRechargeProductRecord { + product_id: "member_month".to_string(), + title: "月卡".to_string(), + price_cents: 2800, + kind: RuntimeProfileRechargeProductKind::Membership, + points_amount: 0, + bonus_points: 0, + duration_days: 30, + badge_label: String::new(), + description: "30天会员".to_string(), + tier: RuntimeProfileMembershipTier::Month, + }], + benefits: vec![], + latest_order: None, + has_points_recharged: false, + }; + + let params = build_wechat_virtual_pay_params(&state, ¢er, &order, "openid-user-00000001") .expect("membership virtual pay params should build"); let sign_data: Value = serde_json::from_str(¶ms.sign_data).expect("sign data should be valid json"); @@ -2296,6 +2354,7 @@ mod tests { .expect("attach should decode"); assert_eq!(params.mode, "short_series_goods"); + assert_eq!(sign_data["buyQuantity"], 1); assert_eq!(sign_data["offerId"], "offer-1"); assert_eq!(sign_data["productId"], "member_month"); assert_eq!(sign_data["goodsPrice"], 2800); @@ -2305,6 +2364,106 @@ mod tests { assert!(!params.signature.is_empty()); } + #[tokio::test] + async fn wechat_virtual_pay_params_use_coin_quantity_for_points_products() { + let state = seed_authenticated_state_with_config(AppConfig { + wechat_mini_program_virtual_payment_offer_id: Some("offer-1".to_string()), + wechat_mini_program_virtual_payment_app_key: Some("app-key-1".to_string()), + wechat_mini_program_virtual_payment_env: 0, + ..fast_spacetime_timeout_config() + }) + .await; + let wechat_login = state + .wechat_auth_service() + .resolve_login(ResolveWechatLoginInput { + profile: WechatIdentityProfile { + provider_uid: "openid-user-points-60".to_string(), + provider_union_id: Some("union-user-points-60".to_string()), + display_name: Some("资料页用户".to_string()), + avatar_url: None, + session_key: Some("session-key-points-60".to_string()), + }, + }) + .await + .expect("wechat identity should seed"); + let user_id = wechat_login.user.id.clone(); + let order = RuntimeProfileRechargeOrderRecord { + order_id: "pointsorder60".to_string(), + user_id: user_id.clone(), + product_id: "points_60".to_string(), + product_title: "60泥点".to_string(), + kind: RuntimeProfileRechargeProductKind::Points, + amount_cents: 600, + status: RuntimeProfileRechargeOrderStatus::Pending, + payment_channel: PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL + .to_string(), + paid_at: None, + paid_at_micros: None, + provider_transaction_id: None, + created_at: "2026-05-30T10:00:00Z".to_string(), + created_at_micros: 1_780_000_000_000_000, + points_delta: 0, + membership_expires_at: None, + membership_expires_at_micros: None, + }; + + let center = RuntimeProfileRechargeCenterRecord { + user_id: user_id.clone(), + wallet_balance: 0, + membership: RuntimeProfileMembershipRecord { + user_id: user_id.clone(), + status: RuntimeProfileMembershipStatus::Normal, + tier: RuntimeProfileMembershipTier::Normal, + started_at: None, + started_at_micros: None, + expires_at: None, + expires_at_micros: None, + updated_at: None, + updated_at_micros: None, + }, + point_products: vec![RuntimeProfileRechargeProductRecord { + product_id: "points_60".to_string(), + title: "60泥点".to_string(), + price_cents: 600, + kind: RuntimeProfileRechargeProductKind::Points, + points_amount: 60, + bonus_points: 60, + duration_days: 0, + badge_label: "首充双倍".to_string(), + description: "60+60泥点".to_string(), + tier: RuntimeProfileMembershipTier::Normal, + }], + membership_products: vec![], + benefits: vec![], + latest_order: None, + has_points_recharged: true, + }; + + let params = build_wechat_virtual_pay_params( + &state, + ¢er, + &order, + "openid-user-points-60", + ) + .expect("points virtual pay params should build"); + let sign_data: Value = + serde_json::from_str(¶ms.sign_data).expect("sign data should be valid json"); + let attach: Value = serde_json::from_str( + sign_data["attach"] + .as_str() + .expect("attach should be string json"), + ) + .expect("attach should decode"); + + assert_eq!(params.mode, "short_series_coin"); + assert_eq!(sign_data["buyQuantity"], 60); + assert_eq!(sign_data["offerId"], "offer-1"); + assert_eq!(sign_data["outTradeNo"], "pointsorder60"); + assert_eq!(attach["paymentChannel"], "wechat_mp_virtual"); + assert!(!params.pay_sig.is_empty()); + assert!(!params.signature.is_empty()); + } + #[tokio::test] async fn wechat_virtual_pay_params_accept_admin_membership_product_ids() { let state = seed_authenticated_state_with_config(AppConfig { @@ -2327,9 +2486,10 @@ mod tests { }) .await .expect("wechat identity should seed"); + let user_id = wechat_login.user.id.clone(); let order = RuntimeProfileRechargeOrderRecord { order_id: "item01order01".to_string(), - user_id: wechat_login.user.id, + user_id: user_id.clone(), product_id: "item01".to_string(), product_title: "测试道具".to_string(), kind: RuntimeProfileRechargeProductKind::Membership, @@ -2347,7 +2507,39 @@ mod tests { membership_expires_at_micros: None, }; - let params = build_wechat_virtual_pay_params(&state, &order, "openid-user-item01") + let center = RuntimeProfileRechargeCenterRecord { + user_id: user_id.clone(), + wallet_balance: 0, + membership: RuntimeProfileMembershipRecord { + user_id: user_id.clone(), + status: RuntimeProfileMembershipStatus::Normal, + tier: RuntimeProfileMembershipTier::Normal, + started_at: None, + started_at_micros: None, + expires_at: None, + expires_at_micros: None, + updated_at: None, + updated_at_micros: None, + }, + point_products: vec![], + membership_products: vec![RuntimeProfileRechargeProductRecord { + product_id: "item01".to_string(), + title: "测试道具".to_string(), + price_cents: 100, + kind: RuntimeProfileRechargeProductKind::Membership, + points_amount: 0, + bonus_points: 0, + duration_days: 30, + badge_label: String::new(), + description: "30天会员".to_string(), + tier: RuntimeProfileMembershipTier::Month, + }], + benefits: vec![], + latest_order: None, + has_points_recharged: false, + }; + + let params = build_wechat_virtual_pay_params(&state, ¢er, &order, "openid-user-item01") .expect("custom membership virtual pay params should build"); let sign_data: Value = serde_json::from_str(¶ms.sign_data).expect("sign data should be valid json"); @@ -2404,9 +2596,10 @@ mod tests { }) .await .expect("wechat identity should seed"); + let user_id = wechat_login.user.id.clone(); let order = RuntimeProfileRechargeOrderRecord { order_id: "sandboxorder01".to_string(), - user_id: wechat_login.user.id, + user_id: user_id.clone(), product_id: "points_60".to_string(), product_title: "60泥点".to_string(), kind: RuntimeProfileRechargeProductKind::Points, @@ -2424,7 +2617,39 @@ mod tests { membership_expires_at_micros: None, }; - let error = build_wechat_virtual_pay_params(&state, &order, "openid-sandbox-1") + let center = RuntimeProfileRechargeCenterRecord { + user_id: user_id.clone(), + wallet_balance: 0, + membership: RuntimeProfileMembershipRecord { + user_id: user_id.clone(), + status: RuntimeProfileMembershipStatus::Normal, + tier: RuntimeProfileMembershipTier::Normal, + started_at: None, + started_at_micros: None, + expires_at: None, + expires_at_micros: None, + updated_at: None, + updated_at_micros: None, + }, + point_products: vec![RuntimeProfileRechargeProductRecord { + product_id: "points_60".to_string(), + title: "60泥点".to_string(), + price_cents: 600, + kind: RuntimeProfileRechargeProductKind::Points, + points_amount: 60, + bonus_points: 60, + duration_days: 0, + badge_label: "首充双倍".to_string(), + description: "60+60泥点".to_string(), + tier: RuntimeProfileMembershipTier::Normal, + }], + membership_products: vec![], + benefits: vec![], + latest_order: None, + has_points_recharged: false, + }; + + let error = build_wechat_virtual_pay_params(&state, ¢er, &order, "openid-sandbox-1") .expect_err("sandbox pay params should reject missing sandbox app key"); assert!( error.to_string().contains("沙箱 AppKey 未配置"), diff --git a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx index 4fbd15a3..bd57b40d 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx @@ -1594,6 +1594,211 @@ test('profile recharge modal releases submitting state and shows virtual payment }); }); +test('profile recharge modal eventually shows error text even when hashchange is not dispatched', async () => { + const user = userEvent.setup(); + window.history.replaceState(null, '', '/?clientRuntime=wechat_mini_program'); + const navigateTo = vi.fn((options: { url: string; success?: () => void }) => { + options.success?.(); + }); + window.wx = { + miniProgram: { + navigateTo, + }, + }; + mockCreateRpgProfileRechargeOrder.mockResolvedValueOnce({ + order: { + orderId: 'order-wechat-delayed-fail', + productId: 'points_60', + productTitle: '60泥点', + kind: 'points', + amountCents: 600, + status: 'pending' as const, + paymentChannel: 'wechat_mp_virtual', + paidAt: null as string | null, + providerTransactionId: null, + createdAt: '2026-04-25T10:00:00Z', + pointsDelta: 0, + membershipExpiresAt: null, + }, + center: { + walletBalance: 0, + membership: { + status: 'normal', + tier: 'normal', + startedAt: null, + expiresAt: null, + updatedAt: null, + }, + pointProducts: [], + membershipProducts: [], + benefits: [], + latestOrder: null, + hasPointsRecharged: false, + }, + wechatMiniProgramPayParams: { + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":1,"env":1,"currencyType":"CNY","outTradeNo":"order-wechat-delayed-fail","attach":"mud_points_60"}', + paySig: 'sandbox-pay-sig', + signature: 'user-sig', + }, + }); + + renderProfileView(); + await openRechargeModal(user); + const buyButton = await screen.findByRole('button', { name: /60泥点/u }); + await user.click(buyButton); + + const navigateUrl = navigateTo.mock.calls[0]?.[0].url ?? ''; + const requestId = new URL(`https://mini.test${navigateUrl}`).searchParams.get( + 'requestId', + ); + expect(requestId).toBeTruthy(); + window.location.hash = `wx_pay_result=${requestId}:fail:order-wechat-delayed-fail:${encodeURIComponent('{"errCode":-1,"errMsg":"requestVirtualPayment:fail delayed"}')}`; + + expect( + await screen.findByRole('dialog', { name: '支付未完成' }), + ).toBeTruthy(); + expect(screen.getByText(/requestVirtualPayment:fail delayed/u)).toBeTruthy(); +}); + +test('profile recharge modal keeps polling long enough for late success result', async () => { + const user = userEvent.setup(); + const onRechargeSuccess = vi.fn(); + window.history.replaceState(null, '', '/?clientRuntime=wechat_mini_program'); + const navigateTo = vi.fn((options: { url: string; success?: () => void }) => { + options.success?.(); + }); + window.wx = { + miniProgram: { + navigateTo, + }, + }; + mockCreateRpgProfileRechargeOrder.mockResolvedValueOnce({ + order: { + orderId: 'order-wechat-late-success', + productId: 'points_60', + productTitle: '60泥点', + kind: 'points', + amountCents: 600, + status: 'pending' as const, + paymentChannel: 'wechat_mp_virtual', + paidAt: null as string | null, + providerTransactionId: null, + createdAt: '2026-04-25T10:00:00Z', + pointsDelta: 0, + membershipExpiresAt: null, + }, + center: { + walletBalance: 0, + membership: { + status: 'normal', + tier: 'normal', + startedAt: null, + expiresAt: null, + updatedAt: null, + }, + pointProducts: [], + membershipProducts: [], + benefits: [], + latestOrder: null, + hasPointsRecharged: false, + }, + wechatMiniProgramPayParams: { + mode: 'short_series_coin', + signData: + '{"offerId":"offer-1","buyQuantity":60,"env":0,"currencyType":"CNY","outTradeNo":"order-wechat-late-success","attach":"mud_points_60"}', + paySig: 'pay-sig', + signature: 'user-sig', + }, + }); + mockConfirmWechatRpgProfileRechargeOrder + .mockResolvedValueOnce({ + order: { + orderId: 'order-wechat-late-success', + productId: 'points_60', + productTitle: '60泥点', + kind: 'points', + amountCents: 600, + status: 'pending' as const, + paymentChannel: 'wechat_mp_virtual', + paidAt: null, + providerTransactionId: null, + createdAt: '2026-04-25T10:00:00Z', + pointsDelta: 0, + membershipExpiresAt: null, + }, + center: { + walletBalance: 0, + membership: { + status: 'normal', + tier: 'normal', + startedAt: null, + expiresAt: null, + updatedAt: null, + }, + pointProducts: [], + membershipProducts: [], + benefits: [], + latestOrder: null, + hasPointsRecharged: false, + }, + }) + .mockResolvedValueOnce({ + order: { + orderId: 'order-wechat-late-success', + productId: 'points_60', + productTitle: '60泥点', + kind: 'points', + amountCents: 600, + status: 'paid' as const, + paymentChannel: 'wechat_mp_virtual', + paidAt: '2026-04-25T10:01:00Z', + providerTransactionId: 'wx-transaction-late', + createdAt: '2026-04-25T10:00:00Z', + pointsDelta: 120, + membershipExpiresAt: null, + }, + center: { + walletBalance: 120, + membership: { + status: 'normal', + tier: 'normal', + startedAt: null, + expiresAt: null, + updatedAt: null, + }, + pointProducts: [], + membershipProducts: [], + benefits: [], + latestOrder: null, + hasPointsRecharged: true, + }, + }); + + renderProfileView(onRechargeSuccess); + await openRechargeModal(user); + await user.click(await screen.findByRole('button', { name: /60泥点/u })); + + const navigateUrl = navigateTo.mock.calls[0]?.[0].url ?? ''; + const requestId = new URL(`https://mini.test${navigateUrl}`).searchParams.get( + 'requestId', + ); + expect(requestId).toBeTruthy(); + + await new Promise((resolve) => window.setTimeout(resolve, 2600)); + act(() => { + window.location.hash = `wx_pay_result=${requestId}:success:order-wechat-late-success`; + window.dispatchEvent(new HashChangeEvent('hashchange')); + }); + + await waitFor(() => { + expect(mockConfirmWechatRpgProfileRechargeOrder).toHaveBeenCalledTimes(2); + }); + expect(await screen.findByRole('dialog', { name: '支付成功' })).toBeTruthy(); + expect(onRechargeSuccess).toHaveBeenCalledTimes(1); +}, 12000); + test('profile recharge modal waits for paid confirmation before refreshing dashboard', async () => { const user = userEvent.setup(); const onRechargeSuccess = vi.fn(); diff --git a/src/components/rpg-entry/RpgEntryHomeView.tsx b/src/components/rpg-entry/RpgEntryHomeView.tsx index 8bb452ad..a83f5a12 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.tsx @@ -337,6 +337,8 @@ type RechargePaymentResult = { title: string; message: string; }; +const WECHAT_PAY_RESULT_RECHECK_INTERVAL_MS = 250; +const WECHAT_PAY_RESULT_RECHECK_TIMEOUT_MS = 10000; function getBarcodeDetectorConstructor(): BarcodeDetectorConstructorLike | null { const maybeDetector = (globalThis as unknown as { @@ -4588,7 +4590,7 @@ export function RpgEntryHomeView({ const handleWechatPayResult = useCallback(() => { const payResult = readWechatPayResultFromHash(); if (!payResult) { - return; + return false; } if ( @@ -4596,7 +4598,7 @@ export function RpgEntryHomeView({ payResult.orderId && payResult.orderId !== pendingWechatRechargeOrderIdRef.current ) { - return; + return false; } setSubmittingRechargeProductId(null); @@ -4661,6 +4663,7 @@ export function RpgEntryHomeView({ } clearWechatPayResultHash(); + return true; }, [onRechargeSuccess, refreshRechargeState]); const openRechargeModal = () => { if (!authUi?.user) { @@ -4823,6 +4826,39 @@ export function RpgEntryHomeView({ document.removeEventListener('visibilitychange', handleResume); }; }, [handleWechatPayResult]); + useEffect(() => { + if ( + rechargePaymentResult?.kind !== 'pending' || + rechargePaymentResult.title !== '正在支付' + ) { + return undefined; + } + + const startedAt = Date.now(); + let timer: number | null = null; + const pollPayResult = () => { + if (handleWechatPayResult()) { + return; + } + if (Date.now() - startedAt >= WECHAT_PAY_RESULT_RECHECK_TIMEOUT_MS) { + return; + } + timer = window.setTimeout( + pollPayResult, + WECHAT_PAY_RESULT_RECHECK_INTERVAL_MS, + ); + }; + + timer = window.setTimeout( + pollPayResult, + WECHAT_PAY_RESULT_RECHECK_INTERVAL_MS, + ); + return () => { + if (timer !== null) { + window.clearTimeout(timer); + } + }; + }, [handleWechatPayResult, rechargePaymentResult?.kind, rechargePaymentResult?.title]); const loadTaskCenter = useCallback(() => { const requestId = ++taskCenterRequestIdRef.current; setTaskCenterError(null); From 9b3616fd4267d74254f50cdcd71bb12357eb358f Mon Sep 17 00:00:00 2001 From: kdletters Date: Sun, 31 May 2026 05:56:06 +0000 Subject: [PATCH 08/31] feat: allocate linux dev port ranges --- .hermes/shared-memory/decision-log.md | 8 + .hermes/shared-memory/development-workflow.md | 2 + .hermes/shared-memory/pitfalls.md | 8 + .../SKILL.md | 7 + ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 + scripts/dev-stack-port-utils.mjs | 466 +++++++++++++++++- scripts/dev-stack-port-utils.test.ts | 217 ++++++++ scripts/dev.mjs | 89 ++++ scripts/dev.test.ts | 63 +++ 9 files changed, 858 insertions(+), 4 deletions(-) diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 93ddf685..d5e9f6e8 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -16,6 +16,14 @@ --- +## 2026-05-30 Linux 本地 dev 端口段按系统级注册表分配 + +- 背景:同一台 Linux 开发机上有多个用户同时跑 `npm run dev` 时,单纯靠各自 `GENARRATIVE_DEV_PORT_RANGE` 容易撞段,且同一用户并发起两个 dev 会话时也会把相同端口段重复拿走。 +- 决策:Linux 上的本地 dev 端口段分配统一收口到系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,锁文件为 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。未手动指定时自动从 `10000-10099` 开始按 100 端口块分配,后续块按 `10100-10199`、`10200-10299` 递增;端口段映射固定为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`admin-web = start + 3`;注册表会拒绝不同用户的相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。`GENARRATIVE_DEV_PORT_RANGE` 与 `--port-range` 仍可手动指定端口段,但只在 Linux 生效,Windows 继续沿用原有端口探测与漂移逻辑,不读注册表。 +- 影响范围:`scripts/dev-stack-port-utils.mjs`、`scripts/dev.mjs`、`scripts/dev-stack-port-utils.test.ts`、`scripts/dev.test.ts`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、本条决策记录、`development-workflow.md`。 +- 验证方式:`node --check scripts/dev-stack-port-utils.mjs`、`node --check scripts/dev.mjs`、`node node_modules/vitest/vitest.mjs run scripts/dev-stack-port-utils.test.ts scripts/dev.test.ts` 通过;Linux 下能看到 `[dev] port-range:` 与 `registry.json` 路径日志,自动分配从 `10000-10099` 起步,Windows 不出现注册表分配日志。 +- 关联文档:`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。 + ## 2026-05-27 生成页总进度圆弧锁定固定画布 - 背景:多轮圆环角度微调后,`GenerationProgressHero` 的 SVG 圆弧仍会出现底部开口偏斜的问题,且圆环还会随着容器宽度伸缩,导致 UI 看起来时大时小、位置漂移。 diff --git a/.hermes/shared-memory/development-workflow.md b/.hermes/shared-memory/development-workflow.md index 3710e85b..7ee99e27 100644 --- a/.hermes/shared-memory/development-workflow.md +++ b/.hermes/shared-memory/development-workflow.md @@ -50,6 +50,8 @@ npm install npm run dev ``` +Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Linux 用户分配一个固定端口段并写入系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,自动分配从 `10000-10099` 开始,每段 100 个端口,四个 dev 服务依次使用 `start` 到 `start + 3`。可用 `GENARRATIVE_DEV_PORT_RANGE` 或 `npm run dev -- --port-range` 手动指定端口段用于特殊场景;注册表会阻止不同用户使用相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。该机制只在 Linux 生效,Windows 仍沿用原有端口探测与漂移逻辑。 + 该命令会启动: - SpacetimeDB standalone diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index 3dea8cd4..90d4b5db 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -151,6 +151,14 @@ - 验证:检查 `jenkins/Jenkinsfile.production-stdb-module-publish` 文件开头字节不再是 `EF BB BF`,并用 Jenkins `validateDeclarativePipeline` 或重放 `Genarrative-Stdb-Module-Publish`,不应再停在 `No such DSL method 'pipeline'`。 - 关联:`jenkins/Jenkinsfile.production-stdb-module-publish`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。 +## Linux 多用户 dev 端口冲突先查系统级端口段注册表 + +- 现象:同一台 Linux 机器上多个用户同时开发时,`npm run dev` 报端口段已被其他用户占用、同一用户已有活跃端口段,或 SpacetimeDB 复用记录指向当前用户端口段之外的地址;未手动指定时自动分配应从 `10000-10099` 起步。 +- 原因:Linux dev 脚本会通过 `/var/tmp/genarrative-dev-port-ranges/registry.json` 做系统级端口段分配,避免两个用户配置相同或重叠端口段;同一用户后续启动会继续复用自己已经占用的固定端口段。注册表会保留该用户的段记录,不会因为多开而要求重新分配。 +- 处理:先确认当前用户已经占用的端口段,再让后续 `npm run dev` / `dev:*` 继续沿用这段;如确实要切换段,手动释放或清掉对应 registry 记录后再重启。需要临时隔离测试时用 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR=` 覆盖注册表目录。不要在 Windows 上按这个注册表排查,Windows 仍走原有端口探测与漂移逻辑。未指定端口段时,系统会从 `10000-10099` 开始顺序分配。 +- 验证:重新启动后终端应打印 `[dev] port-range: ()` 与 `[dev] port-range-registry: .../registry.json`;`node node_modules/vitest/vitest.mjs run scripts/dev-stack-port-utils.test.ts scripts/dev.test.ts` 应通过 Linux registry、自动分配 `10000-10099` 与 Windows bypass 用例。 +- 关联:`scripts/dev-stack-port-utils.mjs`、`scripts/dev.mjs`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。 + ## SpacetimeDB 入口迁移 helper 合并时不要只保留调用 - 现象:`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 或 Jenkins `Genarrative-Stdb-Module-Build` 报 `E0425 cannot find function migrate_rpg_entry_from_old_hidden_default in this scope`,位置在 `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs` 的默认入口配置播种流程。 diff --git a/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md b/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md index 9e7e0b86..f2262353 100644 --- a/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md +++ b/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md @@ -34,6 +34,8 @@ metadata: 端口不可用时,脚本会从优先端口开始向后寻找可用端口。后续流程必须以解析后的实际端口为准,不能继续使用默认端口。 +Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 会先向系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json` 申请一个端口段,再把该段映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`adminWeb = start + 3`。注册表锁文件是 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。自动分配从 `10000-10099` 起,每次占用 100 个端口块,后续块按 `10100-10199`、`10200-10299` 递增;当前口径是“一个用户固定占用一个段,后续启动继续复用这段并在段内漂移”;该注册表只在 Linux 上生效;Windows 继续沿用原有端口探测、漂移和复用逻辑,不读系统级注册表。 + ## 实现入口 - `package.json` @@ -43,10 +45,12 @@ metadata: - `isPortAvailable(...)`:探测端口是否可监听。 - `findAvailablePort(...)`:从优先端口向后寻找可用端口,`0` 表示申请临时端口。 - `resolveDevStackPorts(...)`:一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,并避免本次解析结果互相冲突。 + - Linux 注册表分配:`reserveLinuxDevPortRange(...)` / `releaseLinuxDevPortRange(...)`,仅在 Linux 上启用系统级端口段登记与用户段复用,自动分配从 `10000-10099` 起。 - CLI 模式:`node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102`。 - `scripts/dev.mjs` - 解析 CLI 参数后统一计算 client host、端口、`SPACETIME_SERVER`、`RUST_SERVER_TARGET`。 - 完整栈按 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 顺序启动。 + - Linux 下会先申请系统级端口段并把它映射成四个 dev 端口;自动分配从 `10000-10099` 起,Windows 则直接沿用原有参数解析与端口漂移逻辑。 - 单模块命令复用同一套参数和 env 解析。 ## 必须保持的传递链路 @@ -60,6 +64,7 @@ metadata: 5. 主站 Vite:`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET`、`ADMIN_WEB_TARGET`、`ADMIN_WEB_PORT`、`--port=${WEB_PORT}`、`--host=${WEB_HOST}`。 6. 后台 Vite:`ADMIN_API_TARGET`、`GENARRATIVE_API_TARGET`、`GENARRATIVE_API_PORT`、`--port=${ADMIN_WEB_PORT}`。 7. 控制台日志:`[dev:ports]` 和 `[dev] web/admin web/api-server/spacetime` 必须显示最终实际地址。 +8. Linux 端口段注册:`[dev] port-range:` 与 `[dev] port-range-registry:` 只在 Linux 输出,Windows 不应依赖系统级注册表。 如果只改了其中一段,通常会出现:浏览器打开的前端可用,但 `/api/*` 代理到旧端口;后台页面可用但后台 API 失败;SpacetimeDB 启动在新端口但 publish 仍发往旧端口。 @@ -76,6 +81,7 @@ metadata: 4. 修改 watch 时保持模块边界:SpacetimeDB 只监听 `spacetime-module` 且改动后重新 publish,不重启 standalone 宿主;api-server 排除 `spacetime-module`;web/admin-web 源码变化交给 Vite 自身 HMR,外层调度器不要再监听前端目录重启 Vite。 5. 修改 `dev:web` 时不要自动改后端目标策略;`dev:web` 只负责主站 Vite 端口可用性与已有后端目标选择。 6. 同步更新技术文档和团队共享记忆。 +7. 如果修改 Linux 端口段注册口径,确认 Windows 分支仍保持旧行为,不要把系统级注册表逻辑扩散到 Windows。 ## 测试与验证 @@ -113,6 +119,7 @@ node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 ap ## 验收清单 - [ ] 端口工具有测试覆盖端口被占用和多端口互斥解析。 +- [ ] Linux 注册表分配、同用户复用固定段并继续漂移、自动分配从 `10000-10099` 起、Windows bypass 都有测试覆盖。 - [ ] `scripts/dev.mjs` 通过 `node --check`。 - [ ] `npm run dev` 的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 都使用实际端口。 - [ ] `npm run dev:web` 在主站端口不可用时能切换到可用端口。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index c7d2c9a7..a44c0304 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -43,6 +43,8 @@ npm run dev:web npm run dev:api-server ``` +Linux 本机多用户并发开发时,`npm run dev` 和 `npm run dev:*` 单模块命令会先在系统级端口段注册表里给当前用户分配一个端口段,再把该段映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`admin-web = start + 3`。默认注册表目录是 `/var/tmp/genarrative-dev-port-ranges/`,其中 `registry.json` 记录各用户的活跃段,`registry.lock` 负责串行化分配;可以用 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。系统自动分配时从 `10000-10099` 开始,每次占用 100 个端口块,后续块按 `10100-10199`、`10200-10299` 递增;`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 只在 Linux 上生效,Windows 仍按原来的 3000 / 8082 / 3101 / 3102 端口探测与漂移逻辑运行,不读这个系统级注册表。 + 后端日志默认写入 `logs/api-server/`。后端 API smoke 使用 `npm run dev:api-server` 并检查 `/healthz`;不要使用旧 `api-server:maincloud` 或任何 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 口径。 开发态 `npm run dev` 与 `npm run dev:api-server` 会默认注入 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true`,因此密码登录在本地开发环境可直接注册未知手机号账号;生产环境仍按 `api-server` 配置默认关闭该开关。 diff --git a/scripts/dev-stack-port-utils.mjs b/scripts/dev-stack-port-utils.mjs index 1a03a19d..bbd8f6e5 100644 --- a/scripts/dev-stack-port-utils.mjs +++ b/scripts/dev-stack-port-utils.mjs @@ -1,5 +1,22 @@ +import {randomBytes} from 'node:crypto'; +import { + chmodSync, + existsSync, + mkdirSync, + readFileSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import {hostname, userInfo} from 'node:os'; +import {dirname, resolve} from 'node:path'; import {createServer} from 'node:net'; +const LINUX_DEV_PORT_RANGE_REGISTRY_ROOT = '/var/tmp/genarrative-dev-port-ranges'; +const LINUX_DEV_PORT_RANGE_POOL_START = 10000; +const LINUX_DEV_PORT_RANGE_POOL_END = 39999; +const LINUX_DEV_PORT_RANGE_BLOCK_SIZE = 100; + function toListenHosts(host) { if (host === '0.0.0.0') { return ['0.0.0.0']; @@ -21,6 +38,416 @@ export function normalizePort(value, fallback) { return port; } +export function parsePortRangeSpec(value) { + const spec = String(value ?? '').trim(); + if (!spec) { + return null; + } + + const match = /^(\d+)\s*[-:]\s*(\d+)$/u.exec(spec); + if (!match) { + throw new Error(`端口段格式错误: ${spec},应为 start-end 形式,如 10000-10099`); + } + + const start = normalizePort(match[1], -1); + const end = normalizePort(match[2], -1); + if (start < 1024 || end < 1024 || start > end) { + throw new Error(`端口段无效: ${spec},端口必须在 1024-65535 且起始不大于结束`); + } + + if (end - start + 1 < 4) { + throw new Error(`端口段至少需要 4 个端口: ${spec}`); + } + + return {start, end, label: `${start}-${end}`}; +} + +function normalizePortRange(portRange) { + if (!portRange) { + return null; + } + + if (typeof portRange === 'string') { + return parsePortRangeSpec(portRange); + } + + return parsePortRangeSpec(`${portRange.start}-${portRange.end}`); +} + +export function getLinuxDevPortRangeRegistryPaths(env = process.env) { + const registryRoot = + String(env.GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR ?? '').trim() || + LINUX_DEV_PORT_RANGE_REGISTRY_ROOT; + + return { + root: registryRoot, + registryPath: resolve(registryRoot, 'registry.json'), + lockPath: resolve(registryRoot, 'registry.lock'), + }; +} + +export function getLinuxDevPortRangeUsername(env = process.env) { + const candidates = [env.SUDO_USER, env.LOGNAME, env.USER, env.USERNAME]; + + for (const candidate of candidates) { + const value = String(candidate ?? '').trim(); + if (value) { + return value; + } + } + + try { + return userInfo().username; + } catch { + return 'unknown'; + } +} + +export function getLinuxDevPortRangeSpec(env = process.env) { + return parsePortRangeSpec(env.GENARRATIVE_DEV_PORT_RANGE); +} + +export function mapDevPortsToPortRange(portRange) { + const normalizedRange = normalizePortRange(portRange); + if (!normalizedRange) { + return null; + } + + return { + webPort: normalizedRange.start, + apiPort: normalizedRange.start + 1, + spacetimePort: normalizedRange.start + 2, + adminWebPort: normalizedRange.start + 3, + range: normalizedRange, + }; +} + +function ensureWorldWritableDirectory(path) { + mkdirSync(path, {recursive: true}); + try { + chmodSync(path, 0o777); + } catch { + // 目录已存在时若无法改权限,也不影响当前进程继续写入。 + } +} + +function randomToken(byteLength = 8) { + return randomBytes(byteLength).toString('hex'); +} + +function readJsonFile(path, fallbackValue) { + if (!existsSync(path)) { + return fallbackValue; + } + + const rawText = readFileSync(path, 'utf8').trim(); + if (!rawText) { + return fallbackValue; + } + + try { + return JSON.parse(rawText); + } catch (error) { + throw new Error(`系统级端口段记录文件损坏: ${path}; ${error.message}`); + } +} + +function atomicWriteJsonFile(path, value) { + const targetDir = dirname(path); + ensureWorldWritableDirectory(targetDir); + + const tempPath = resolve( + targetDir, + `.tmp.${process.pid}.${Date.now()}.${randomToken()}.json`, + ); + + writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, { + encoding: 'utf8', + mode: 0o666, + }); + + try { + chmodSync(tempPath, 0o666); + } catch { + // 先写成功再说,后续 rename 之后还能补一次。 + } + + try { + renameSync(tempPath, path); + } catch (error) { + try { + rmSync(tempPath, {force: true}); + } catch { + // ignore cleanup races + } + throw error; + } + + try { + chmodSync(path, 0o666); + } catch { + // 忽略权限补写失败,记录已落盘即可。 + } +} + +function isProcessAlive(pid) { + if (!Number.isInteger(pid) || pid <= 0) { + return false; + } + + try { + process.kill(pid, 0); + return true; + } catch (error) { + return error?.code === 'EPERM'; + } +} + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function getDefaultPortRangeRegistry() { + return { + version: 4, + updatedAt: '', + allocations: {}, + }; +} + +function readLinuxPortRangeRegistry(registryPath) { + const registry = readJsonFile(registryPath, getDefaultPortRangeRegistry()); + if (!registry || typeof registry !== 'object' || Array.isArray(registry)) { + throw new Error(`系统级端口段记录文件格式错误: ${registryPath}`); + } + + if (!registry.allocations || typeof registry.allocations !== 'object') { + registry.allocations = {}; + } + + const normalizedAllocations = {}; + for (const [key, record] of Object.entries(registry.allocations)) { + if (!record || typeof record !== 'object' || Array.isArray(record)) { + continue; + } + + const username = String(record.username ?? key ?? '').trim(); + const range = safeNormalizePortRange(record.range); + if (!username || !range) { + continue; + } + + normalizedAllocations[username] = { + username, + range, + claimedAt: String(record.claimedAt ?? '').trim(), + updatedAt: String(record.updatedAt ?? record.claimedAt ?? '').trim(), + source: String(record.source ?? 'auto').trim() || 'auto', + }; + } + + registry.version = 4; + registry.allocations = normalizedAllocations; + return registry; +} + +function safeNormalizePortRange(portRange) { + try { + return normalizePortRange(portRange); + } catch { + return null; + } +} + +function rangesOverlap(left, right) { + return left.start <= right.end && right.start <= left.end; +} + +function findRangeConflict(registry, portRange, excludingUsername = '') { + const rangeToCheck = safeNormalizePortRange(portRange); + if (!rangeToCheck) { + return null; + } + + for (const [username, record] of Object.entries(registry.allocations ?? {})) { + if (username === excludingUsername) { + continue; + } + + const recordRange = safeNormalizePortRange(record?.range); + if (!recordRange || !rangesOverlap(recordRange, rangeToCheck)) { + continue; + } + + return {username, record, range: recordRange}; + } + + return null; +} + +function nextLinuxPortRangeCandidate(registry) { + for ( + let start = LINUX_DEV_PORT_RANGE_POOL_START; + start <= LINUX_DEV_PORT_RANGE_POOL_END; + start += LINUX_DEV_PORT_RANGE_BLOCK_SIZE + ) { + const end = start + LINUX_DEV_PORT_RANGE_BLOCK_SIZE - 1; + if (end > LINUX_DEV_PORT_RANGE_POOL_END) { + break; + } + + const label = `${start}-${end}`; + if (!findRangeConflict(registry, {start, end, label})) { + return {start, end, label}; + } + } + + return null; +} + +async function withLinuxPortRangeRegistryLock(lockPath, action) { + ensureWorldWritableDirectory(dirname(lockPath)); + + while (true) { + try { + writeFileSync( + lockPath, + JSON.stringify( + { + pid: process.pid, + hostname: hostname(), + acquiredAt: new Date().toISOString(), + }, + null, + 2, + ), + {encoding: 'utf8', flag: 'wx', mode: 0o666}, + ); + break; + } catch (error) { + if (error?.code !== 'EEXIST') { + throw error; + } + + let lockRecord = null; + try { + lockRecord = readJsonFile(lockPath, null); + } catch { + lockRecord = null; + } + + if (!lockRecord || !isProcessAlive(lockRecord.pid)) { + try { + rmSync(lockPath, {force: true}); + } catch { + // ignore cleanup races + } + continue; + } + + await sleep(50); + } + } + + try { + return await action(); + } finally { + try { + rmSync(lockPath, {force: true}); + } catch { + // ignore cleanup races + } + } +} + +export async function reserveLinuxDevPortRange({ + env = process.env, + username = getLinuxDevPortRangeUsername(env), + requestedRange = getLinuxDevPortRangeSpec(env), + registryPath = getLinuxDevPortRangeRegistryPaths(env).registryPath, + lockPath = getLinuxDevPortRangeRegistryPaths(env).lockPath, +} = {}) { + if (process.platform !== 'linux') { + return null; + } + + const normalizedRequestedRange = normalizePortRange(requestedRange); + const now = new Date().toISOString(); + + return await withLinuxPortRangeRegistryLock(lockPath, async () => { + const registry = readLinuxPortRangeRegistry(registryPath); + + const current = registry.allocations[username]; + if (current) { + registry.updatedAt = now; + registry.allocations[username] = { + ...current, + username, + range: current.range, + updatedAt: now, + }; + atomicWriteJsonFile(registryPath, registry); + return registry.allocations[username]; + } + + const rangeToUse = normalizedRequestedRange || nextLinuxPortRangeCandidate(registry); + + if (!rangeToUse) { + throw new Error( + `无法为 Linux dev 分配端口段,范围 ${LINUX_DEV_PORT_RANGE_POOL_START}-${LINUX_DEV_PORT_RANGE_POOL_END} 已耗尽`, + ); + } + + const conflict = findRangeConflict(registry, rangeToUse.label, username); + if (conflict) { + if (conflict.range?.label === rangeToUse.label) { + throw new Error( + `Linux 端口段 ${rangeToUse.label} 已被用户 ${conflict.username} 占用,请换一段再启动`, + ); + } + + throw new Error( + `Linux 端口段 ${rangeToUse.label} 已与用户 ${conflict.username} 的端口段 ${conflict.range?.label} 重叠,请换一段再启动`, + ); + } + + registry.allocations[username] = { + username, + range: rangeToUse, + source: normalizedRequestedRange ? 'manual' : 'auto', + claimedAt: now, + updatedAt: now, + }; + registry.updatedAt = now; + atomicWriteJsonFile(registryPath, registry); + + return registry.allocations[username]; + }); +} + +export async function releaseLinuxDevPortRange({ + env = process.env, + username = getLinuxDevPortRangeUsername(env), + registryPath = getLinuxDevPortRangeRegistryPaths(env).registryPath, + lockPath = getLinuxDevPortRangeRegistryPaths(env).lockPath, +} = {}) { + if (process.platform !== 'linux') { + return false; + } + + return await withLinuxPortRangeRegistryLock(lockPath, async () => { + const registry = readLinuxPortRangeRegistry(registryPath); + if (!registry.allocations[username]) { + return false; + } + + delete registry.allocations[username]; + registry.updatedAt = new Date().toISOString(); + atomicWriteJsonFile(registryPath, registry); + return true; + }); +} + export async function isPortAvailable({host, port}) { if (port === 0) { return true; @@ -46,16 +473,45 @@ export async function isPortAvailable({host, port}) { return true; } -export async function findAvailablePort({host, preferredPort, reservedPorts = new Set(), maxAttempts = 200}) { +export async function findAvailablePort({ + host, + preferredPort, + reservedPorts = new Set(), + maxAttempts = null, + portRange = null, +}) { + const range = normalizePortRange(portRange); const startPort = normalizePort(preferredPort, 0); + if (startPort === 0 && range) { + return await findAvailablePort({ + host, + preferredPort: range.start, + reservedPorts, + maxAttempts: range.end - range.start, + portRange: range, + }); + } + if (startPort === 0) { return await reserveEphemeralPort(host, reservedPorts); } - for (let offset = 0; offset <= maxAttempts; offset += 1) { + if (range && (startPort < range.start || startPort > range.end)) { + throw new Error(`端口 ${startPort} 不在允许端口段 ${range.label} 内`); + } + + const boundedAttempts = range + ? Number.isFinite(maxAttempts) + ? Math.min(Math.max(0, maxAttempts), range.end - startPort) + : range.end - startPort + : Number.isFinite(maxAttempts) + ? Math.max(0, maxAttempts) + : 200; + + for (let offset = 0; offset <= boundedAttempts; offset += 1) { const candidate = startPort + offset; - if (candidate > 65535) { + if (candidate > 65535 || (range && candidate > range.end)) { break; } @@ -68,7 +524,8 @@ export async function findAvailablePort({host, preferredPort, reservedPorts = ne } } - throw new Error(`无法从 ${host}:${startPort} 开始找到可用端口`); + const rangeHint = range ? `,允许端口段 ${range.label}` : ''; + throw new Error(`无法从 ${host}:${startPort} 开始找到可用端口${rangeHint}`); } async function reserveEphemeralPort(host, reservedPorts) { @@ -107,6 +564,7 @@ export async function resolveDevStackPorts(config) { host: portConfig.host, preferredPort: portConfig.preferredPort, reservedPorts, + portRange: portConfig.portRange, }); reservedPorts.add(resolvedPort); result[name] = resolvedPort; diff --git a/scripts/dev-stack-port-utils.test.ts b/scripts/dev-stack-port-utils.test.ts index 62240f9f..5521538d 100644 --- a/scripts/dev-stack-port-utils.test.ts +++ b/scripts/dev-stack-port-utils.test.ts @@ -1,7 +1,13 @@ import {createServer} from 'node:net'; +import {mkdtempSync, readFileSync, rmSync} from 'node:fs'; +import {tmpdir} from 'node:os'; +import {join} from 'node:path'; import {describe, expect, it} from 'vitest'; import { findAvailablePort, + mapDevPortsToPortRange, + parsePortRangeSpec, + reserveLinuxDevPortRange, resolveDevStackPorts, } from './dev-stack-port-utils.mjs'; @@ -18,6 +24,20 @@ function reservePort(port) { } describe('dev stack port utils', () => { + it('解析端口段并映射到四个 dev 端口', () => { + expect(parsePortRangeSpec('10000-10099')).toEqual({ + start: 10000, + end: 10099, + label: '10000-10099', + }); + expect(mapDevPortsToPortRange('10000-10099')).toMatchObject({ + webPort: 10000, + apiPort: 10001, + spacetimePort: 10002, + adminWebPort: 10003, + }); + }); + it('使用端口可用性检查为被占用端口寻找后续可用端口', async () => { const firstServer = await reservePort(0); const firstPort = firstServer.address().port; @@ -38,6 +58,16 @@ describe('dev stack port utils', () => { } }); + it('端口查找不会越过 Linux 用户端口段', async () => { + await expect( + findAvailablePort({ + host: '127.0.0.1', + preferredPort: 9999, + portRange: {start: 10000, end: 10099, label: '10000-10099'}, + }), + ).rejects.toThrow('不在允许端口段'); + }); + it('为 npm run dev 的所有后续流程解析互不冲突的端口', async () => { const resolvedPorts = await resolveDevStackPorts({ spacetime: {host: '127.0.0.1', preferredPort: 0}, @@ -48,4 +78,191 @@ describe('dev stack port utils', () => { expect(new Set(Object.values(resolvedPorts)).size).toBe(4); }); + + it('端口段内会一直漂移到段尾,不会被默认 200 次尝试截断', async () => { + const rangeStart = 10000; + const rangeEnd = 10300; + const reservedPorts = new Set( + Array.from({length: 201}, (_, index) => rangeStart + index), + ); + + const availablePort = await findAvailablePort({ + host: '127.0.0.1', + preferredPort: rangeStart, + reservedPorts, + portRange: {start: rangeStart, end: rangeEnd, label: `${rangeStart}-${rangeEnd}`}, + }); + + expect(availablePort).toBeGreaterThan(rangeStart + 200); + expect(availablePort).toBeLessThanOrEqual(rangeEnd); + }); + + const linuxIt = process.platform === 'linux' ? it : it.skip; + + linuxIt('Linux 未手动指定端口段时从 10000 开始按 100 端口块自动分配', async () => { + const tempRoot = mkdtempSync(join(tmpdir(), 'genarrative-port-range-')); + const registryPath = join(tempRoot, 'registry.json'); + const lockPath = join(tempRoot, 'registry.lock'); + + try { + const aliceAllocation = await reserveLinuxDevPortRange({ + env: { + USER: 'alice', + LOGNAME: 'alice', + GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR: tempRoot, + }, + username: 'alice', + requestedRange: null, + registryPath, + lockPath, + }); + const bobAllocation = await reserveLinuxDevPortRange({ + env: { + USER: 'bob', + LOGNAME: 'bob', + GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR: tempRoot, + }, + username: 'bob', + requestedRange: null, + registryPath, + lockPath, + }); + + expect(aliceAllocation.range.label).toBe('10000-10099'); + expect(aliceAllocation.source).toBe('auto'); + expect(bobAllocation.range.label).toBe('10100-10199'); + expect(bobAllocation.source).toBe('auto'); + } finally { + rmSync(tempRoot, {recursive: true, force: true}); + } + }); + + linuxIt('Linux 系统级端口段记录会阻止两个用户拿到同一段', async () => { + const tempRoot = mkdtempSync(join(tmpdir(), 'genarrative-port-range-')); + const registryPath = join(tempRoot, 'registry.json'); + const lockPath = join(tempRoot, 'registry.lock'); + + try { + const baseEnv = { + USER: 'alice', + LOGNAME: 'alice', + GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR: tempRoot, + GENARRATIVE_DEV_PORT_RANGE: '10000-10099', + }; + + const aliceAllocation = await reserveLinuxDevPortRange({ + env: baseEnv, + username: 'alice', + registryPath, + lockPath, + }); + + expect(aliceAllocation.range.label).toBe('10000-10099'); + + const registryAfterAlice = JSON.parse(readFileSync(registryPath, 'utf8')); + expect(registryAfterAlice.allocations.alice.range.label).toBe('10000-10099'); + + await expect( + reserveLinuxDevPortRange({ + env: { + ...baseEnv, + USER: 'bob', + LOGNAME: 'bob', + }, + username: 'bob', + requestedRange: '10000-10099', + registryPath, + lockPath, + }), + ).rejects.toThrow('已被用户 alice 占用'); + + const aliceReuse = await reserveLinuxDevPortRange({ + env: { + ...baseEnv, + USER: 'alice', + LOGNAME: 'alice', + }, + username: 'alice', + registryPath, + lockPath, + }); + + expect(aliceReuse.range.label).toBe('10000-10099'); + expect(aliceReuse.source).toBe('manual'); + expect( + ( + await reserveLinuxDevPortRange({ + env: { + ...baseEnv, + USER: 'alice', + LOGNAME: 'alice', + GENARRATIVE_DEV_PORT_RANGE: '10100-10199', + }, + username: 'alice', + requestedRange: '10100-10199', + registryPath, + lockPath, + }) + ).range.label, + ).toBe('10000-10099'); + + const registryAfterReuse = JSON.parse(readFileSync(registryPath, 'utf8')); + expect(registryAfterReuse.allocations.alice.range.label).toBe('10000-10099'); + + const bobAllocation = await reserveLinuxDevPortRange({ + env: { + ...baseEnv, + USER: 'bob', + LOGNAME: 'bob', + GENARRATIVE_DEV_PORT_RANGE: '10100-10199', + }, + username: 'bob', + requestedRange: '10100-10199', + registryPath, + lockPath, + }); + + expect(bobAllocation.range.label).toBe('10100-10199'); + } finally { + rmSync(tempRoot, {recursive: true, force: true}); + } + }); + + linuxIt('Linux 同一用户第二个 dev 会话会复用同一用户段并继续在段内漂移', async () => { + const tempRoot = mkdtempSync(join(tmpdir(), 'genarrative-port-range-')); + const registryPath = join(tempRoot, 'registry.json'); + const lockPath = join(tempRoot, 'registry.lock'); + + try { + const baseEnv = { + USER: 'alice', + LOGNAME: 'alice', + GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR: tempRoot, + GENARRATIVE_DEV_PORT_RANGE: '10000-10099', + }; + + const first = await reserveLinuxDevPortRange({ + env: baseEnv, + username: 'alice', + registryPath, + lockPath, + }); + + const second = await reserveLinuxDevPortRange({ + env: baseEnv, + username: 'alice', + registryPath, + lockPath, + }); + + expect(first.range.label).toBe('10000-10099'); + expect(second.range.label).toBe('10000-10099'); + expect(second.username).toBe('alice'); + expect(JSON.parse(readFileSync(registryPath, 'utf8')).allocations.alice.range.label).toBe( + '10000-10099', + ); + } finally { + rmSync(tempRoot, {recursive: true, force: true}); + } + }); }); diff --git a/scripts/dev.mjs b/scripts/dev.mjs index 13cbb831..82d462db 100644 --- a/scripts/dev.mjs +++ b/scripts/dev.mjs @@ -15,7 +15,11 @@ import {fileURLToPath} from 'node:url'; import { formatPortDecision, + getLinuxDevPortRangeRegistryPaths, + getLinuxDevPortRangeUsername, + mapDevPortsToPortRange, normalizePort, + reserveLinuxDevPortRange, resolveDevStackPorts, } from './dev-stack-port-utils.mjs'; import { @@ -59,6 +63,7 @@ function usage() { --spacetime-port SpacetimeDB 端口 --spacetime-data-dir SpacetimeDB 本地数据目录 --database SpacetimeDB 数据库名 + --port-range Linux 用户端口段,手动指定示例 10000-10099;默认自动从 10000-10099 起分配 --watch 文件改动后刷新/重启对应模块 --no-interactive 关闭交互式手动命令 @@ -109,6 +114,7 @@ function parseArgs(argv, baseEnv) { spacetimePort: normalizePort(env.SPACETIME_PORT, 3101), spacetimeDataDir: resolve(serverRsDir, '.spacetimedb/local/data'), spacetimeServerUrl: String(env.GENARRATIVE_SPACETIME_SERVER_URL ?? '').trim(), + portRangeSpec: String(env.GENARRATIVE_DEV_PORT_RANGE ?? '').trim(), database: readLocalSpacetimeDatabase() || String(env.GENARRATIVE_SPACETIME_DATABASE ?? '').trim() || @@ -184,6 +190,10 @@ function parseArgs(argv, baseEnv) { options.database = readValue(); explicitOptions.add('database'); break; + case '--port-range': + options.portRangeSpec = readValue(); + explicitOptions.add('portRangeSpec'); + break; case '--log': options.apiLog = readValue(); break; @@ -549,6 +559,8 @@ class DevRunner { adminWebTargetHost: resolveClientHost(options.adminWebHost), spacetimeServer: initialSpacetimeServer, apiTarget: `http://${resolveClientHost(options.apiHost)}:${options.apiPort}`, + portRange: null, + portRangeReservation: null, }; this.services = new Map(); this.watchers = []; @@ -572,12 +584,57 @@ class DevRunner { ensureSpacetimeToolVersionMatchesWorkspace(); } + await this.prepareLinuxPortRange(command); await this.tryReuseExistingSpacetime(command); await this.resolvePorts(command); this.registerServices(); this.printSummary(command); } + async prepareLinuxPortRange(command) { + if (process.platform !== 'linux') { + return; + } + + const requestedRange = String(this.options.portRangeSpec ?? '').trim(); + const allocation = await reserveLinuxDevPortRange({ + env: { + ...this.baseEnv, + GENARRATIVE_DEV_PORT_RANGE: requestedRange, + }, + username: getLinuxDevPortRangeUsername(this.baseEnv), + }); + + if (!allocation) { + return; + } + + this.state.portRangeReservation = allocation; + this.state.portRange = allocation.range; + this.baseEnv.GENARRATIVE_DEV_PORT_RANGE = allocation.range.label; + + const mappedPorts = mapDevPortsToPortRange(allocation.range); + if (!mappedPorts) { + return; + } + + if (!this.explicitOptions.has('webPort')) { + this.options.webPort = mappedPorts.webPort; + } + if (!this.explicitOptions.has('apiPort')) { + this.options.apiPort = mappedPorts.apiPort; + } + if (!this.explicitOptions.has('spacetimePort')) { + this.options.spacetimePort = mappedPorts.spacetimePort; + } + if (!this.explicitOptions.has('adminWebPort')) { + this.options.adminWebPort = mappedPorts.adminWebPort; + } + + this.state.spacetimeServer = `http://${this.options.spacetimeHost}:${this.options.spacetimePort}`; + this.state.apiTarget = `http://${this.state.apiTargetHost}:${this.options.apiPort}`; + } + shouldValidateSpacetimeToolVersion(command) { if (command === 'spacetime') { return true; @@ -626,6 +683,10 @@ class DevRunner { ]); for (const candidate of candidates) { + if (!this.isCandidateSpacetimeWithinAssignedRange(candidate)) { + continue; + } + const pingUrl = buildUrl(candidate, '/v1/ping'); if (!pingUrl || !(await isHttpReady(pingUrl))) { continue; @@ -653,6 +714,21 @@ class DevRunner { ); } + isCandidateSpacetimeWithinAssignedRange(candidateUrl) { + const range = this.state.portRange; + if (!range) { + return true; + } + + try { + const url = new URL(candidateUrl); + const port = Number(url.port); + return Number.isInteger(port) && port >= range.start && port <= range.end; + } catch { + return false; + } + } + async resolvePorts(command) { const {options} = this; const portConfig = {}; @@ -662,6 +738,7 @@ class DevRunner { portConfig.spacetime = { host: options.spacetimeHost, preferredPort: options.spacetimePort, + portRange: this.state.portRange, }; } } @@ -670,6 +747,7 @@ class DevRunner { portConfig.api = { host: options.apiHost, preferredPort: options.apiPort, + portRange: this.state.portRange, }; } @@ -677,6 +755,7 @@ class DevRunner { portConfig.web = { host: options.webHost, preferredPort: options.webPort, + portRange: this.state.portRange, }; } @@ -684,6 +763,7 @@ class DevRunner { portConfig.adminWeb = { host: options.adminWebHost, preferredPort: options.adminWebPort, + portRange: this.state.portRange, }; } @@ -747,6 +827,15 @@ class DevRunner { console.log(`[dev] repo: ${repoRoot}`); console.log(`[dev] command: ${command}`); console.log(`[dev] watch: ${options.watch ? 'on' : 'off'}`); + if (state.portRange) { + const owner = + state.portRangeReservation?.username || + getLinuxDevPortRangeUsername(this.baseEnv); + console.log(`[dev] port-range: ${state.portRange.label} (${owner})`); + console.log( + `[dev] port-range-registry: ${getLinuxDevPortRangeRegistryPaths(this.baseEnv).registryPath}`, + ); + } console.log(`[dev] web: http://127.0.0.1:${options.webPort}`); console.log(`[dev] admin web: http://${state.adminWebTargetHost}:${options.adminWebPort}/admin/`); console.log(`[dev] api-server: ${state.apiTarget}`); diff --git a/scripts/dev.test.ts b/scripts/dev.test.ts index 2870d0de..7219908d 100644 --- a/scripts/dev.test.ts +++ b/scripts/dev.test.ts @@ -35,6 +35,8 @@ function workspaceSpacetimeVersionForTest() { } describe('dev scheduler argument routing', () => { + const linuxTest = process.platform === 'linux' ? test : test.skip; + test('完整 dev 栈覆盖前端代理到本次解析出的 api-server 地址', () => { const {command, explicitOptions, options} = parseArgs([], { GENARRATIVE_API_PORT: '8090', @@ -88,6 +90,67 @@ describe('dev scheduler argument routing', () => { 'http://127.0.0.1:3100', ); }); + + linuxTest('Linux 启动时按系统级端口段映射四个 dev 端口', async () => { + const tempDir = mkdtempSync(join(tmpdir(), 'genarrative-dev-port-range-')); + try { + const {command, explicitOptions, options} = parseArgs([], { + USER: 'alice', + LOGNAME: 'alice', + GENARRATIVE_DEV_PORT_RANGE: '22000-22099', + GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR: tempDir, + }); + const runner = new DevRunner(options, { + USER: 'alice', + LOGNAME: 'alice', + GENARRATIVE_DEV_PORT_RANGE: '22000-22099', + GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR: tempDir, + }, explicitOptions); + + await runner.prepareLinuxPortRange(command); + + expect(runner.state.portRange.label).toBe('22000-22099'); + expect(runner.options.webPort).toBe(22000); + expect(runner.options.apiPort).toBe(22001); + expect(runner.options.spacetimePort).toBe(22002); + expect(runner.options.adminWebPort).toBe(22003); + expect(runner.state.apiTarget).toBe('http://127.0.0.1:22001'); + expect(runner.state.spacetimeServer).toBe('http://127.0.0.1:22002'); + } finally { + rmSync(tempDir, {recursive: true, force: true}); + } + }); + + test('Windows 仍沿用原有端口解析,不启用 Linux 端口段登记', async () => { + const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform'); + Object.defineProperty(process, 'platform', { + configurable: true, + value: 'win32', + }); + + try { + const {command, explicitOptions, options} = parseArgs([], { + USER: 'alice', + GENARRATIVE_DEV_PORT_RANGE: '22000-22099', + }); + const runner = new DevRunner(options, { + USER: 'alice', + GENARRATIVE_DEV_PORT_RANGE: '22000-22099', + }, explicitOptions); + + await runner.prepareLinuxPortRange(command); + + expect(runner.state.portRange).toBeNull(); + expect(runner.options.webPort).toBe(3000); + expect(runner.options.apiPort).toBe(8082); + expect(runner.options.spacetimePort).toBe(3101); + expect(runner.options.adminWebPort).toBe(3102); + } finally { + if (originalPlatform) { + Object.defineProperty(process, 'platform', originalPlatform); + } + } + }); }); describe('dev scheduler api-server env', () => { From c193a352df4509d02b0231663e2115b5dcd3959d Mon Sep 17 00:00:00 2001 From: kdletters Date: Sun, 31 May 2026 05:57:34 +0000 Subject: [PATCH 09/31] =?UTF-8?q?=E6=94=B6=E5=8F=A3=E5=88=9B=E4=BD=9C?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E7=BB=9F=E4=B8=80=E6=80=BB=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E5=B9=B6=E4=BF=AE=E5=A4=8D=E7=AD=89=E5=BE=85=E9=A1=B5=E7=AA=84?= =?UTF-8?q?=E5=B1=8F=E8=A3=81=E5=88=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .hermes/shared-memory/decision-log.md | 33 +- .hermes/shared-memory/development-workflow.md | 2 +- .hermes/shared-memory/document-map.md | 6 +- .hermes/shared-memory/pitfalls.md | 15 + apps/admin-web/src/api/adminApiTypes.ts | 18 + .../AdminCreationEntrySwitchPage.test.tsx | 112 ++++++ .../pages/AdminCreationEntrySwitchPage.tsx | 198 +++++++++- docs/README.md | 4 +- docs/planning/README.md | 13 + ...玩法创作】创作流程统一总计划-2026-05-30.md | 371 ++++++++++++++++++ ...】server-rs与SpacetimeDB数据契约-2026-05-15.md | 4 +- ...玩法创作】平台入口与玩法链路-2026-05-15.md | 4 +- ...玩法创作】生成页圆环布局口径-2026-05-23.md | 8 +- quality-gates/README.md | 20 +- ...法创作】跨玩法回归与冒烟门禁-2026-05-30.md | 94 +++++ scripts/dev.mjs | 6 +- server-rs/Cargo.lock | 1 + server-rs/crates/api-server/src/admin.rs | 22 ++ .../crates/module-runtime/src/application.rs | 14 +- server-rs/crates/module-runtime/src/domain.rs | 2 + .../crates/shared-contracts/src/admin.rs | 6 + .../src/creation_entry_config.rs | 96 ++++- .../spacetime-client/src/mapper/runtime.rs | 3 + ...tion_entry_type_admin_upsert_input_type.rs | 1 + .../creation_entry_type_config_type.rs | 7 + .../creation_entry_type_snapshot_type.rs | 1 + server-rs/crates/spacetime-module/Cargo.toml | 1 + .../crates/spacetime-module/src/migration.rs | 5 +- .../src/runtime/creation_entry_config.rs | 24 ++ .../spacetime-module/src/visual_novel.rs | 6 +- .../CustomWorldGenerationView.test.tsx | 9 +- src/components/GenerationProgressHero.tsx | 68 ++-- .../BarkBattleGeneratingView.test.tsx | 9 +- .../JumpHopWorkspace.test.tsx | 92 +++++ .../JumpHopResultView.test.tsx | 144 +++++++ .../JumpHopRuntimeShell.test.tsx | 212 ++++++++++ ...Match3DAgentWorkspace.interaction.test.tsx | 22 ++ .../Match3DAgentWorkspace.tsx | 35 +- .../PlatformEntryFlowShellImpl.tsx | 144 +++++-- .../PuzzleAgentWorkspace.interaction.test.tsx | 23 ++ .../puzzle-agent/PuzzleAgentWorkspace.tsx | 14 +- ...gEntryFlowShell.agent.interaction.test.tsx | 218 ++++++++++ src/components/rpg-entry/RpgEntryHomeView.tsx | 16 +- .../rpg-entry/rpgEntryWorldPresentation.ts | 6 +- .../SquareHoleResultView.test.tsx | 102 +++++ .../UnifiedCreationPage.test.tsx | 12 + .../unified-creation/UnifiedCreationPage.tsx | 19 +- .../UnifiedGenerationPage.tsx | 34 +- .../unified-creation/unifiedGenerationCopy.ts | 34 ++ .../VisualNovelAgentWorkspace.test.tsx | 8 +- .../WoodenFishWorkspace.test.tsx | 21 + .../WoodenFishWorkspace.tsx | 8 +- src/index.css | 6 +- 53 files changed, 2192 insertions(+), 161 deletions(-) create mode 100644 apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx create mode 100644 docs/planning/README.md create mode 100644 docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md create mode 100644 quality-gates/【玩法创作】跨玩法回归与冒烟门禁-2026-05-30.md create mode 100644 src/components/jump-hop-creation/JumpHopWorkspace.test.tsx create mode 100644 src/components/jump-hop-result/JumpHopResultView.test.tsx create mode 100644 src/components/jump-hop-runtime/JumpHopRuntimeShell.test.tsx create mode 100644 src/components/square-hole-result/SquareHoleResultView.test.tsx create mode 100644 src/components/unified-creation/unifiedGenerationCopy.ts diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 93ddf685..d5a01ba1 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -16,12 +16,37 @@ --- -## 2026-05-27 生成页总进度圆弧锁定固定画布 +## 2026-05-30 创作流程统一化门禁扩展为跨玩法矩阵 -- 背景:多轮圆环角度微调后,`GenerationProgressHero` 的 SVG 圆弧仍会出现底部开口偏斜的问题,且圆环还会随着容器宽度伸缩,导致 UI 看起来时大时小、位置漂移。 -- 决策:共用 `GenerationProgressHero` 的 SVG 圆弧起始角固定为 `135deg`,轨道和橘黄色填充都从同一个对称起点 `rotate(135 200 200)` 出发;`270deg` 扫描角配合正下方 `90deg` 留空,圆环本体改为固定 `400x400` 画布,不再跟随页面宽度缩放,外层布局只负责定位,不负责改动圆环样式。 +- 背景:统一创作 / 统一生成门禁已经足够覆盖 Phase 2 的入口与壳层,但当前总计划已经推进到 Phase 3-6,继续只保留单页门禁会让 Phase 4 的特殊工作台、Phase 5 的结果页 / 作品架 / 公开详情和 Phase 6 的冻结验收没有统一入口。 +- 决策:`quality-gates/README.md` 继续保留单页门禁与 `dev-stack` 门禁,同时新增跨玩法回归 / 冒烟门禁,按 Phase 2 到 Phase 5 的最小验证集合分层执行;Phase 6 冻结前以这份矩阵为主,不再另外拆新波次。涉及入口配置、统一字段 spec、普通工作台、RPG / Bark Battle / 视觉小说特殊边界、发布 / 公开 / runtime 或本地 smoke 的变更,优先对照这份矩阵补齐验收命令。 +- 影响范围:`quality-gates/README.md`、`quality-gates/【玩法创作】跨玩法回归与冒烟门禁-2026-05-30.md`、`docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md`、后续 Phase 2-6 玩法接入与冻结流程。 +- 验证方式:按矩阵执行 `npm run check:encoding`、`npm run typecheck`、`npm run admin-web:typecheck`、对应分期 `npm run test`、`npm run check:visual-novel-vn11`,以及需要时的 `npm run dev:api-server` + `/healthz` smoke。 +- 关联文档:`quality-gates/README.md`、`quality-gates/【玩法创作】跨玩法回归与冒烟门禁-2026-05-30.md`、`docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md`。 + +## 2026-05-30 跳一跳结果页直达必须优先恢复作品而不是白屏 + +- 背景:跳一跳结果页已经接入统一壳,但如果用户直接打开 `/creation/jump-hop/result`,旧路径容易因为缺少 `draft` 恢复信息而看起来像白屏,误导成结果页坏了。 +- 决策:`PlatformEntryFlowShellImpl` 的跳一跳恢复顺序固定为 `profileId -> getWorkDetail`,再 `sessionId -> getSession`;两者都拿不到时必须展示 `跳一跳草稿未恢复` 恢复面板和 `返回创作`,不能继续留空白结果页。进入结果页的 smoke 允许恢复面板,但不允许纯空白。 +- 影响范围:`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、`src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`、`quality-gates/【玩法创作】跨玩法回归与冒烟门禁-2026-05-30.md`、`docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md`。 +- 验证方式:`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "direct jump hop result route"`;手测 `/creation/jump-hop/result` 和 `/creation/jump-hop/result?profileId=`。 +- 关联文档:`docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md`、`quality-gates/【玩法创作】跨玩法回归与冒烟门禁-2026-05-30.md`、`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。 + +## 2026-05-29 一期统一创作页必须提供可见统一外壳 + +- 背景:`UnifiedCreationPage` 首版只暴露隐藏 spec 元数据并包裹旧玩法工作台,用户打开拼图创作页时仍只能看到旧工作台外观,无法验收“统一创作页”。 +- 决策:一期统一创作页(拼图、抓大鹅、敲木鱼)必须由 `UnifiedCreationPage` 提供统一标题栏、内容区和隐藏字段契约;字段元信息只留给测试和代码,不再额外作为可见 chip 占用首屏。玩法工作台只承载具体输入控件、上传、历史素材、校验和提交,不再各自渲染巨大入口标题。拼图继续复用 `PuzzleAgentWorkspace` 的上传、裁剪、历史图、AI 重绘和提交逻辑,抓大鹅继续复用 `Match3DAgentWorkspace` 的题材与难度表单逻辑;二者在统一壳内启用 `unifiedChrome`,收起旧标题与外层壳。敲木鱼右侧音效和功德面板不得再套内部滚动容器,移动端应自然跟随页面滚动。 +- 追加决策:`UnifiedCreationPage` 不创建自己的纵向滚动窗;拼图、抓大鹅和敲木鱼三个统一创作入口由平台 stage 承担整页滚动,竖屏移动端必须能从统一标题、表单控件一路滑到提交按钮,避免工作台内部或右侧面板形成套滚动。 +- 影响范围:`src/components/unified-creation/UnifiedCreationPage.tsx`、`src/components/puzzle-agent/PuzzleAgentWorkspace.tsx`、`src/components/wooden-fish-creation/WoodenFishWorkspace.tsx`、`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、玩法链路文档。 +- 验证方式:`UnifiedCreationPage` 测试应断言隐藏契约仍在但 UI 不再出现字段 chip;拼图和抓大鹅工作台测试应断言 `unifiedChrome=true` 时不再渲染旧巨大标题且仍保留表单输入;木鱼工作台测试或手测应确认敲击音效和功德词条不再停留在独立滚动窗内。 +- 关联文档:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。 + +## 2026-05-27 生成页总进度圆弧锁定固定 SVG 坐标系 + +- 背景:多轮圆环角度微调后,`GenerationProgressHero` 的 SVG 圆弧仍会出现底部开口偏斜的问题;后来窄屏验收又发现固定 `400px` 外层宽度会让等待页右侧被裁切。 +- 决策:共用 `GenerationProgressHero` 的 SVG 圆弧起始角固定为 `135deg`,轨道和橘黄色填充都从同一个对称起点 `rotate(135 200 200)` 出发;`270deg` 扫描角配合正下方 `90deg` 留空。SVG 内部坐标系固定为 `400x400`,圆弧使用 `r=166` 和 `strokeWidth=18`;外层显示宽度以 `400px` 为上限,窄屏按 `min(400px, calc(100vw - 2.5rem))` 等比收缩。预计等待 / 已耗时信息卡在窄屏下落到圆环下方两列,`sm` 及以上再回到左右悬浮。 - 影响范围:`src/components/GenerationProgressHero.tsx`、共用 `CustomWorldGenerationView`、汪汪声浪 `BarkBattleGeneratingView` 以及生成页圆环布局文档。 -- 验证方式:`CustomWorldGenerationView` 和 `BarkBattleGeneratingView` 测试断言 `data-ring-start-degrees=135`、`data-ring-fill-start-degrees=135`,且圆环容器固定为 `h-[400px] w-[400px]`,track / fill transform 都是 `rotate(135 200 200)`。 +- 验证方式:`CustomWorldGenerationView` 和 `BarkBattleGeneratingView` 测试断言 `data-ring-start-degrees=135`、`data-ring-fill-start-degrees=135`,且圆环容器包含 `w-[min(400px,calc(100vw-2.5rem))]`、`max-w-full` 与 `aspect-square`,track / fill transform 都是 `rotate(135 200 200)`;竖屏 smoke 至少覆盖 `280px / 320px / 360px / 390px` 宽度。 - 关联文档:`docs/【玩法创作】生成页圆环布局口径-2026-05-23.md`。 ## 2026-05-26 平台跨流程错误统一用可复制来源弹窗展示 diff --git a/.hermes/shared-memory/development-workflow.md b/.hermes/shared-memory/development-workflow.md index 23e61f20..6bafa510 100644 --- a/.hermes/shared-memory/development-workflow.md +++ b/.hermes/shared-memory/development-workflow.md @@ -256,7 +256,7 @@ npm run check:server-rs-ddd ## 提交前建议让 Hermes 执行 -涉及拼图、抓大鹅、敲木鱼统一创作 / 生成链路或本地 dev 栈时,先按 `quality-gates/README.md` 和对应门禁文档执行自动脚本与体验检查。 +涉及拼图、抓大鹅、敲木鱼统一创作 / 生成链路、Phase 2 之后的跨玩法回归或本地 dev 栈时,先按 `quality-gates/README.md`、`quality-gates/【玩法创作】跨玩法回归与冒烟门禁-2026-05-30.md` 和对应单项门禁文档执行自动脚本与体验检查。 ```text 请检查当前 git diff,指出: diff --git a/.hermes/shared-memory/document-map.md b/.hermes/shared-memory/document-map.md index 512c5949..62a5538f 100644 --- a/.hermes/shared-memory/document-map.md +++ b/.hermes/shared-memory/document-map.md @@ -11,6 +11,7 @@ | 产品、命名、UI、协作和废弃路线 | `docs/【项目基线】当前产品与工程约束-2026-05-15.md` | | 后端、DDD、API、SpacetimeDB schema 和表目录 | `docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md` | | 创作入口、草稿架和玩法链路 | `docs/【玩法创作】平台入口与玩法链路-2026-05-15.md` | +| 创作流程统一阶段计划 | `docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md` | | 本地启动、验证、部署、埋点和运营查询 | `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md` | | UI 像素资产与 9-slice 规范 | `UI_CODING_STANDARD.md` | @@ -32,8 +33,9 @@ 玩法 / 创作入口 / 运行态: 1. `docs/【玩法创作】平台入口与玩法链路-2026-05-15.md` -2. `docs/【项目基线】当前产品与工程约束-2026-05-15.md` -3. 相关前端组件、service、shared contract 和后端 module +2. 若任务涉及跨玩法创作流程统一,读取 `docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md` +3. `docs/【项目基线】当前产品与工程约束-2026-05-15.md` +4. 相关前端组件、service、shared contract 和后端 module 生产部署 / 服务器 / Jenkins: diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index 3dea8cd4..caca24d6 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -1537,6 +1537,13 @@ - 现象:移动端创作 Tab 里进入汪汪声浪表单后,页面右侧出现不自然的内层滚动条,最后的形象描述输入框容易被“生成草稿”按钮、键盘或底部 TabBar 挤压 / 遮挡;顶部玩法卡首尾也可能贴边显得被裁。 - 原因:外层 `.platform-tab-panel` 已经是纵向滚动容器,创作页中间又有多层 `overflow-hidden`,旧的 `BarkBattleConfigEditor` 根节点再加 `overflow-y-auto`,形成外层 Tab 面板 + 内层表单的套滚动;底部按钮只预留 safe-area,不预留真实操作区距离;顶部玩法卡横向滚动条隐藏且首尾没有 scroll padding。 - 处理:移动端让 Bark Battle 表单跟随父级滚动,`lg` 以上才恢复表单内滚动;创作页容器移动端使用 `overflow-visible` 和 safe-area 底部 padding;顶部模板 tablist 加 `scroll-px-3` / 横向 padding,移动端卡片宽度收窄,避免首尾 ring 和圆角贴边裁切。 + +## 统一创作页不要把竖屏滚动锁进内部内容区 + +- 现象:竖屏打开拼图、抓大鹅或敲木鱼创作页时,浏览器页面本身无法滚动,生成按钮或右侧表单面板落到视口外;木鱼的敲击音效和功德词条看起来像被塞进单独滑动窗口。 +- 原因:平台根壳固定一屏并隐藏溢出,`UnifiedCreationPage` 又使用 `h-full min-h-0 overflow-hidden` 和内容区 `overflow-y-auto`,导致滚动责任落到内部内容窗,而不是整个创作 stage。 +- 处理:`UnifiedCreationPage` 只保留统一标题、隐藏字段契约和内容包装,不再设置内部纵向滚动;拼图、抓大鹅和敲木鱼三个统一创作入口的 `motion.div` stage 负责 `overflow-y-auto overflow-x-hidden`。拼图和抓大鹅在 `unifiedChrome` 下收起旧 `h-full overflow-hidden` 外壳,让表单主体跟随 stage 滚动。 +- 验证:用竖屏浏览器视口打开 `/creation/wooden-fish`、`/creation/puzzle` 和 `/creation/match3d`,页面级 stage 应可滚动到生成按钮;`.unified-creation-page__content` 不应包含 `overflow-y-auto`,木鱼工作台内部也不应出现独立纵向滚动容器,拼图 / 抓大鹅可见标题不应重复。 - 验证:`npm run test -- src/components/bark-battle-creation/BarkBattleConfigEditor.test.tsx`、`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "create tab shows template tabs"`、移动端视口检查最后一个输入框与“生成草稿”按钮不重叠。 - 关联:`src/components/bark-battle-creation/BarkBattleConfigEditor.tsx`、`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。 @@ -1596,6 +1603,14 @@ - 验证:移动端视口检查视频 `rect` 应覆盖整个视口,`paused` 应最终变为 `false`,`currentTime` 应持续前进。 - 关联:`src/components/GenerationProgressHero.tsx`、`docs/【玩法创作】生成页圆环布局口径-2026-05-23.md`。 +## 跳一跳结果页直达时不要把恢复面板当成空白页 + +- 现象:浏览器直接打开 `/creation/jump-hop/result`,如果没有 `sessionId`、`profileId`、`draftId` 或 `workId`,页面以前会看起来像空白,容易误判成结果页坏了。 +- 原因:跳一跳结果页恢复原先只盯 `jumpHopSession.draft`,没有把“缺恢复信息”明确兜成可见恢复面板;直达结果页时也没有优先用 `profileId -> getWorkDetail` 补回完整作品。 +- 处理:`PlatformEntryFlowShellImpl` 的跳一跳恢复逻辑改成先尝试 `profileId -> getWorkDetail`,再尝试 `sessionId -> getSession`;两者都没有时显示 `跳一跳草稿未恢复` 和 `返回创作`,不再留空白页。 +- 验证:`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "direct jump hop result route"`,并手测 `/creation/jump-hop/result` 与 `/creation/jump-hop/result?profileId=` 两种情况。 +- 关联:`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、`src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`、`docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md`。 + 2026-05-24 补充:`GenerationPageBackdrop` 不要通过 portal 挂到 `document.body`。body 级 fixed 背景会逃离生成页自己的 stacking context,即使业务内容有局部 `z-10`,真实浏览器里也可能把整页 UI 压住。背景视频应作为生成页根容器子节点保留 `fixed inset-0 z-0`,生成页内容保持 `relative z-10`;相关测试应同时断言背景容器低层级、生成页根容器高层级,以及视频节点仍在生成页 DOM 内部。视觉调整时还要记住:空心圆环的中心块要抽掉,时间卡与总进度标题都应缩小,不要让生成页再回到“纯色底 + 大字号说明卡”的状态。顶部返回和右上状态也不能沿用 `text-lg` / `sm:text-2xl` 这类展示级字号;当前步骤名、步骤状态和底部玩法信息标题要维持普通 UI 字号档位,优先保持 `text-xs` 到 `text-sm` 区间。 2026-05-24 补充:生成页“预计等待 / 已耗时”卡片本身已经有标签,传给 `GenerationProgressHero` 的值只能是纯时间,例如 `4 分钟`、`1 分 15 秒`,不要再拼接“预计还需”或“已耗时”;两张时间卡也要和当前步骤卡一样保持半透明。拼图总进度初始帧必须允许显示 `0%`,不要再用 `Math.max(1, nextProgress)` 之类的保护把启动态抬到 `1%`。 diff --git a/apps/admin-web/src/api/adminApiTypes.ts b/apps/admin-web/src/api/adminApiTypes.ts index 6bcb7c11..3ba26abc 100644 --- a/apps/admin-web/src/api/adminApiTypes.ts +++ b/apps/admin-web/src/api/adminApiTypes.ts @@ -161,6 +161,7 @@ export interface AdminCreationEntryTypeConfigPayload { categoryLabel: string; categorySortOrder: number; updatedAtMicros: number; + unifiedCreationSpec?: UnifiedCreationSpecPayload | null; } export interface AdminUpsertCreationEntryTypeConfigRequest { @@ -175,6 +176,23 @@ export interface AdminUpsertCreationEntryTypeConfigRequest { categoryId: string; categoryLabel: string; categorySortOrder: number; + unifiedCreationSpec?: UnifiedCreationSpecPayload | null; +} + +export interface UnifiedCreationSpecPayload { + playId: string; + title: string; + workspaceStage: string; + generationStage: string; + resultStage: string; + fields: UnifiedCreationFieldPayload[]; +} + +export interface UnifiedCreationFieldPayload { + id: string; + kind: 'text' | 'select' | 'image' | 'audio'; + label: string; + required: boolean; } export interface AdminWorkVisibilityEntryPayload { diff --git a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx new file mode 100644 index 00000000..75c84504 --- /dev/null +++ b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx @@ -0,0 +1,112 @@ +/* @vitest-environment jsdom */ + +import {fireEvent, render, screen, waitFor} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import {beforeEach, expect, test, vi} from 'vitest'; + +import { + getAdminCreationEntryConfig, + upsertAdminCreationEntryConfig, +} from '../api/adminApiClient'; +import type { + AdminCreationEntryConfigResponse, + UnifiedCreationSpecPayload, +} from '../api/adminApiTypes'; +import {AdminCreationEntrySwitchPage} from './AdminCreationEntrySwitchPage'; + +vi.mock('../api/adminApiClient', () => ({ + formatAdminApiError: vi.fn((error: unknown) => + error instanceof Error ? error.message : '请求失败', + ), + getAdminCreationEntryConfig: vi.fn(), + isAdminApiError: vi.fn(() => false), + upsertAdminCreationEntryConfig: vi.fn(), +})); + +const puzzleSpec: UnifiedCreationSpecPayload = { + playId: 'puzzle', + title: '想做个什么玩法?', + workspaceStage: 'puzzle-agent-workspace', + generationStage: 'puzzle-generating', + resultStage: 'puzzle-result', + fields: [ + { + id: 'pictureDescription', + kind: 'text', + label: '画面描述', + required: true, + }, + ], +}; + +const configResponse: AdminCreationEntryConfigResponse = { + entries: [ + { + id: 'puzzle', + title: '拼图', + subtitle: '拼图关卡创作', + badge: '可创建', + imageSrc: '/creation-type-references/puzzle.webp', + visible: true, + open: true, + sortOrder: 30, + categoryId: 'recent', + categoryLabel: '最近创作', + categorySortOrder: 10, + updatedAtMicros: 1, + unifiedCreationSpec: puzzleSpec, + }, + ], +}; + +beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(getAdminCreationEntryConfig).mockResolvedValue(configResponse); + vi.mocked(upsertAdminCreationEntryConfig).mockResolvedValue(configResponse); +}); + +test('创作入口后台展示并保存统一创作契约', async () => { + const user = userEvent.setup(); + const {container} = render( + , + ); + + await screen.findByText('pictureDescription'); + expect(container.querySelector('.admin-subsection .admin-info-list')).not.toBeNull(); + expect(container.querySelector('.admin-panel .admin-panel')).toBeNull(); + expect(container.querySelector('.admin-muted')).toBeNull(); + + await user.click(screen.getByRole('button', {name: '保存入库'})); + await user.click(screen.getByRole('button', {name: '确认'})); + + await waitFor(() => { + expect(upsertAdminCreationEntryConfig).toHaveBeenCalledWith( + 'admin-token', + expect.objectContaining({ + id: 'puzzle', + unifiedCreationSpec: puzzleSpec, + }), + ); + }); +}); + +test('创作入口后台拒绝 playId 不一致的统一创作契约', async () => { + const user = userEvent.setup(); + render( + , + ); + + const textarea = await screen.findByLabelText('契约 JSON'); + fireEvent.change(textarea, { + target: { + value: JSON.stringify({ + ...puzzleSpec, + playId: 'match3d', + }), + }, + }); + await user.click(screen.getByRole('button', {name: '保存入库'})); + + expect(await screen.findByText('统一创作契约 playId 必须与入口 ID 一致')).toBeTruthy(); + expect(upsertAdminCreationEntryConfig).not.toHaveBeenCalled(); +}); diff --git a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx index fb817c65..4a06ddd9 100644 --- a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx +++ b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx @@ -5,7 +5,11 @@ import { getAdminCreationEntryConfig, upsertAdminCreationEntryConfig, } from '../api/adminApiClient'; -import type {AdminCreationEntryTypeConfigPayload} from '../api/adminApiTypes'; +import type { + AdminCreationEntryTypeConfigPayload, + UnifiedCreationFieldPayload, + UnifiedCreationSpecPayload, +} from '../api/adminApiTypes'; import {useAdminWriteConfirm} from '../components/useAdminWriteConfirm'; import {handlePageError} from './pageUtils'; @@ -30,6 +34,7 @@ export function AdminCreationEntrySwitchPage({ const [categoryId, setCategoryId] = useState('recent'); const [categoryLabel, setCategoryLabel] = useState('最近创作'); const [categorySortOrder, setCategorySortOrder] = useState('10'); + const [unifiedCreationSpecJson, setUnifiedCreationSpecJson] = useState(''); const [isLoading, setIsLoading] = useState(false); const [isSaving, setIsSaving] = useState(false); const [listErrorMessage, setListErrorMessage] = useState(''); @@ -66,6 +71,14 @@ export function AdminCreationEntrySwitchPage({ const targetId = selectedId.trim(); setErrorMessage(''); + const unifiedCreationSpecResult = parseUnifiedCreationSpecJson( + targetId, + unifiedCreationSpecJson, + ); + if (!unifiedCreationSpecResult.ok) { + setErrorMessage(unifiedCreationSpecResult.message); + return; + } const confirmed = await confirmWrite({ action: '保存创作入口开关', target: targetId, @@ -88,6 +101,7 @@ export function AdminCreationEntrySwitchPage({ categoryId: categoryId.trim(), categoryLabel: categoryLabel.trim(), categorySortOrder: parseInteger(categorySortOrder), + unifiedCreationSpec: unifiedCreationSpecResult.spec, }); const nextEntries = sortEntries(response.entries); setEntries(nextEntries); @@ -114,6 +128,7 @@ export function AdminCreationEntrySwitchPage({ setCategoryId(entry.categoryId); setCategoryLabel(entry.categoryLabel); setCategorySortOrder(String(entry.categorySortOrder)); + setUnifiedCreationSpecJson(formatUnifiedCreationSpecJson(entry.unifiedCreationSpec)); } return ( @@ -224,6 +239,26 @@ export function AdminCreationEntrySwitchPage({ /> +
+
+ 统一创作契约 + {unifiedCreationSpecJson.trim() ? '已配置' : '未配置'} +
+ {unifiedCreationSpecJson.trim() ? ( + + ) : ( +
未配置统一创作页契约
+ )} +