类型化(会员错误):会员业务拒绝改用机器可读 error_code

- module-runtime 新增 RuntimeProfileMembershipErrorCode 与 RuntimeProfileMembershipDomainError
- 会员报价 / 充值中心 / 后台档位 upsert 的 procedure 结果末尾追加 error_code
- spacetime-module 在拒绝点显式赋码,中文 error_message 逐字保持不变
- spacetime-client 新增 SpacetimeClientError::ProcedureRejected 并映射生成绑定
- api-server 删除会员中文前缀分类,改按 error_code 返回 400,基础设施错误仍 502
- 重生成 module_bindings,并同步设计文档 5.8 与决策日志
This commit is contained in:
2026-10-04 12:41:26 +08:00
parent 75766824f6
commit 68c8544a15
14 changed files with 601 additions and 143 deletions
@@ -9585,3 +9585,12 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 影响范围:`server-rs/crates/shared-contracts/src/admin.rs`、`server-rs/crates/api-server/src/admin_recharge.rs`、`apps/admin-web/src/{api/adminApiTypes.ts,config/membershipDisplay.ts,pages/AdminMembershipPlanPage.tsx,pages/AdminRechargeOrderPage.tsx,components/AdminUserDetailDialog.tsx}`、`scripts/admin-web-fake-api.mjs`、设计文档 §5.6/§10.2、本文件。
- 验证:`cargo check -p api-server`;`npm run admin-web:typecheck`;`npx vitest run apps/admin-web` → 26 files / 248 tests passed(新增「会员订单在发放泥点列展示会员变更快照」及用户详情会员断言)。
- 边界:`/admin/api/*` 不在 `/api/external/v1` OpenAPI 门禁内,本次未补接口级契约测试,会员快照只在管理端页面用例层面取证。
## 2026-10-03 会员链路错误分类改为机器可读错误码(typed error)
- 背景:`api-server/src/runtime_profile.rs` 的 `is_runtime_profile_membership_domain_error` 用中文 `error_message` 前缀 / 精确匹配决定返回 400 还是 502;文案一改(或新增拒绝点)就静默退化,且分类逻辑与 module 的错误文案跨层重复。
- 决策(错误码随 procedure 结果透传):`module-runtime` 新增 `RuntimeProfileMembershipErrorCode`(`UpgradeRejected` / `NotMember` / `AlreadyActive` / `CycleKindLocked` / `MembershipExpired` / `StateChanged` / `PlanNotPurchasable` / `PlanCatalogMissing` / `ProductIdUnparsable` / `MembershipProductRetired` / `InvalidPlanConfig`)与内部 `RuntimeProfileMembershipDomainError { code, message }`;三个会员 procedure 结果(升级报价、充值中心 / 下单、后台档位 upsert)末尾追加 `error_code: Option<...>`,拒绝点显式赋码,不再做字符串分类。
- 决策(客户端错误类型):`spacetime-client` 新增 `SpacetimeClientError::ProcedureRejected { code, message }`;`api-server` 据此返回 400(provider `runtime-profile`),基础设施错误保持 502。字段校验类错误不产码,仍落 502。
- 决策(行为变化):`会员目录缺少档位 ...` 与「已迁移的会员商品」原先落 502,现在明确 400;兑换码链路本轮未改造,仍保留一个文案匹配函数。procedure result 新增字段属 wire 契约变更,要求 module 与 api-server 同版本部署。
- 影响范围:`server-rs/crates/module-runtime/src/domain.rs`、`server-rs/crates/spacetime-module/src/runtime/active/profile.rs`、`server-rs/crates/spacetime-client/src/{active.rs,active/mapper/runtime_profile.rs}`、生成绑定、`server-rs/crates/api-server/src/{runtime_profile.rs,asset_billing.rs,editor_project.rs}`、`docs/technical/【技术设计】泥点三池与会员计费后端设计-2026-10-02.md` §5.8、本文件。
- 验证:`npm run spacetime:generate`;`cargo check --workspace`;`api-server runtime_profile::tests` 41 passed;`module-runtime --lib membership::` 39 passed;`npm run check:encoding`、`npm run check:spacetime-schema`、`cargo fmt -- --check`、`git diff --check` 通过。
@@ -433,6 +433,24 @@ flowchart TD
- `npm run check:generated-bindings` 以「重新生成并与工作区逐字节比较」做门禁,防止 Rust 改了而生成文件没重跑。
- 需要展示用派生字段(如 `totalPoints` 合计)时,在前端 `utils/mudPoints.ts` 里派生,不改 DTO。
### 5.8 会员错误码契约(typed error,已落地)
- 会员链路的业务拒绝不再靠中文 `error_message` 前缀分类。`module-runtime` 新增
`RuntimeProfileMembershipErrorCode`(`UpgradeRejected` / `NotMember` / `AlreadyActive` /
`CycleKindLocked` / `MembershipExpired` / `StateChanged` / `PlanNotPurchasable` /
`PlanCatalogMissing` / `ProductIdUnparsable` / `MembershipProductRetired` / `InvalidPlanConfig`),
在拒绝点显式产出,`RuntimeProfileMembershipUpgradeQuoteProcedureResult` /
`RuntimeProfileRechargeCenterProcedureResult` / `RuntimeProfileMembershipPlanAdminProcedureResult`
末尾追加 `error_code: Option<RuntimeProfileMembershipErrorCode>`(`error_message` 保留人读文案)。
- `spacetime-client` 的 `SpacetimeClientError` 新增
`ProcedureRejected { code, message }`;`api-server` 的 `runtime_profile` 映射据此返回 400
(`provider = runtime-profile`),基础设施错误保持 502。字段校验类错误(如 user_id 缺失)
不产出 `error_code`,仍按字符串错误落到 502。
- 行为变化:`会员目录缺少档位 ...` 与「已迁移的会员商品」原先落到 502,现在有明确错误码,统一 400。
- 兼容边界:procedure result 是 wire 结构,新增字段要求 module 与 api-server 同版本部署;
旧 module 不返回 `error_code` 时,新 client 绑定反序列化会失败。兑换码链路本轮未改造,
`api-server` 仍保留一个兑换码文案匹配函数。
---
## 6. 计算规则(后端唯一真相源)
@@ -695,6 +695,8 @@ fn should_use_wallet_refund_emergency_spool(error: &SpacetimeClientError) -> boo
|| message.contains("连接已断开")
|| message.contains("连接在返回结果前已断开")
}
// 业务拒绝是服务端已明确应答,不应触发退款应急 spool。
SpacetimeClientError::ProcedureRejected { .. } => false,
}
}
@@ -1149,6 +1149,7 @@ fn is_editor_generation_retryable_transport_error(error: &SpacetimeClientError)
|| message.contains("连接在返回结果前已断开")
}
SpacetimeClientError::Procedure(_) => false,
SpacetimeClientError::ProcedureRejected { .. } => false,
}
}
@@ -1160,6 +1161,7 @@ fn is_editor_generation_unknown_result_error(
&& !matches!(
error,
SpacetimeClientError::Procedure(_)
| SpacetimeClientError::ProcedureRejected { .. }
| SpacetimeClientError::Timeout(
SpacetimeClientStage::PoolAcquire
| SpacetimeClientStage::ConnectBuild
@@ -1463,13 +1463,12 @@ pub async fn get_profile_play_stats(
}
fn map_runtime_profile_client_error(error: SpacetimeClientError) -> AppError {
let is_domain_error = matches!(
&error,
SpacetimeClientError::Procedure(message)
if is_runtime_profile_domain_error(message)
);
let is_domain_error = is_runtime_profile_domain_error(&error);
let (status, provider) = match &error {
SpacetimeClientError::Runtime(_) => (StatusCode::BAD_REQUEST, "runtime-profile"),
SpacetimeClientError::ProcedureRejected { .. } => {
(StatusCode::BAD_REQUEST, "runtime-profile")
}
SpacetimeClientError::Procedure(_) if is_domain_error => {
(StatusCode::BAD_REQUEST, "runtime-profile")
}
@@ -1487,24 +1486,18 @@ fn map_runtime_profile_client_error(error: SpacetimeClientError) -> AppError {
}
/// 模块侧的可读业务拒绝以 400 返回,基础设施错误保持 502。
fn is_runtime_profile_domain_error(message: &str) -> bool {
is_runtime_profile_redeem_code_domain_error(message)
|| is_runtime_profile_membership_domain_error(message)
}
fn is_runtime_profile_membership_domain_error(message: &str) -> bool {
message.starts_with("会员升级被拒绝: ")
|| message.starts_with("会员档位")
|| message.starts_with("会员商品 product_id 无法解析: ")
|| message.starts_with("充值商品类型无效:会员商品已迁移到会员档位目录")
|| matches!(
message,
"当前不是会员,请直接选择套餐购买"
| "当前套餐已生效,无需重复购买"
| "当前会员有效期内不支持月付 / 年付转换,到期后可重新选择"
| "会员已到期,请按新购价格重新下单"
| "会员状态已变化,请重新下单"
)
///
/// 会员链路的拒绝已由 SpacetimeDB procedure 透传机器可读错误码,走
/// [`SpacetimeClientError::ProcedureRejected`];兑换码尚未改造,仍按可读文案匹配(见
/// [`is_runtime_profile_redeem_code_domain_error`])。
fn is_runtime_profile_domain_error(error: &SpacetimeClientError) -> bool {
match error {
SpacetimeClientError::ProcedureRejected { .. } => true,
SpacetimeClientError::Procedure(message) => {
is_runtime_profile_redeem_code_domain_error(message)
}
_ => false,
}
}
fn is_runtime_profile_redeem_code_domain_error(message: &str) -> bool {
@@ -2534,12 +2527,12 @@ mod tests {
use module_runtime::{
PROFILE_RECHARGE_PAYMENT_CHANNEL_WECHAT_MINI_PROGRAM_VIRTUAL,
RuntimeProfileDailyFreePointsRecord, RuntimeProfileMembershipCycleKind,
RuntimeProfileMembershipModelAccess, RuntimeProfileMembershipPlan,
RuntimeProfileMembershipPlanRecord, RuntimeProfileMembershipRecord,
RuntimeProfileMembershipStatus, RuntimeProfileRechargeCenterRecord,
RuntimeProfileRechargeOrderRecord, RuntimeProfileRechargeOrderStatus,
RuntimeProfileRechargeProductKind, RuntimeProfileRechargeProductRecord,
RuntimeProfileWalletLedgerSourceType,
RuntimeProfileMembershipErrorCode, RuntimeProfileMembershipModelAccess,
RuntimeProfileMembershipPlan, RuntimeProfileMembershipPlanRecord,
RuntimeProfileMembershipRecord, RuntimeProfileMembershipStatus,
RuntimeProfileRechargeCenterRecord, RuntimeProfileRechargeOrderRecord,
RuntimeProfileRechargeOrderStatus, RuntimeProfileRechargeProductKind,
RuntimeProfileRechargeProductRecord, RuntimeProfileWalletLedgerSourceType,
};
use super::{
@@ -2587,20 +2580,48 @@ mod tests {
#[test]
fn membership_business_rejections_map_to_bad_request() {
// 中文注释:会员商品迁档位目录后的业务拒绝必须按 400 返回;漏掉前缀匹配会落到 502,
// 让后台与下单端把可读的业务提示当成基础设施故障。目录缺行属于部署配置错误,保持 502。
for message in [
"会员升级被拒绝: cycle_kind_change_unsupported",
"会员商品 product_id 无法解析: membership-pro-yearly",
"充值商品类型无效:会员商品已迁移到会员档位目录",
// 中文注释:会员业务拒绝由 procedure 透传机器可读 error_code,统一按 400 返回;
// 中文文案不再参与分类,普通 Procedure 字符串错误保持 502。
for (code, message) in [
(
RuntimeProfileMembershipErrorCode::UpgradeRejected,
"会员升级被拒绝: cycle_kind_change_unsupported",
),
(
RuntimeProfileMembershipErrorCode::ProductIdUnparsable,
"会员商品 product_id 无法解析: membership-pro-yearly",
),
(
RuntimeProfileMembershipErrorCode::MembershipProductRetired,
"充值商品类型无效:会员商品已迁移到会员档位目录",
),
(
RuntimeProfileMembershipErrorCode::PlanCatalogMissing,
"会员目录缺少档位 pro",
),
] {
let error = map_runtime_profile_client_error(SpacetimeClientError::Procedure(
message.to_string(),
));
let error = map_runtime_profile_client_error(SpacetimeClientError::ProcedureRejected {
code,
message: message.to_string(),
});
assert_eq!(error.status_code(), StatusCode::BAD_REQUEST, "{message}");
assert_eq!(error.message(), message);
assert_eq!(
error
.details()
.and_then(|details| details.get("provider"))
.and_then(Value::as_str),
Some("runtime-profile")
);
}
// 中文注释:删掉字符串前缀分类后,同样的文案若没有 error_code 必须落到 502。
let legacy_string_error =
map_runtime_profile_client_error(SpacetimeClientError::Procedure(
"会员升级被拒绝: cycle_kind_change_unsupported".to_string(),
));
assert_eq!(legacy_string_error.status_code(), StatusCode::BAD_GATEWAY);
}
#[test]
@@ -1467,6 +1467,82 @@ impl From<shared_contracts::runtime::ProfileMembershipChangeKindToken>
}
}
/// 会员业务拒绝的机器可读错误码。
///
/// 会员链路的人读 `error_message` 会随文案调整,调用方不得再按中文字符串判断 HTTP 状态;
/// 每个拒绝点显式产出本枚举,随 procedure 结果透传到 Axum 侧。
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeProfileMembershipErrorCode {
/// 补差升级报价 / 下单被升级规则拒绝。
UpgradeRejected,
/// 当前不是会员,应直接购买套餐。
NotMember,
/// 当前套餐已生效,无需重复购买。
AlreadyActive,
/// 有效期内不支持月付 / 年付转换。
CycleKindLocked,
/// 会员已到期,需按新购价格重新下单。
MembershipExpired,
/// 下单后会员状态已变化,需要重新下单。
StateChanged,
/// 目标档位当前不可购买。
PlanNotPurchasable,
/// 代码内档位目录缺少该档位。
PlanCatalogMissing,
/// 会员商品 product_id 无法解析。
ProductIdUnparsable,
/// 会员商品已迁移到档位目录,旧商品不再可用。
MembershipProductRetired,
/// 后台会员档位改价 / 改权益配置校验失败。
InvalidPlanConfig,
}
impl RuntimeProfileMembershipErrorCode {
pub fn as_str(&self) -> &'static str {
match self {
Self::UpgradeRejected => "upgrade_rejected",
Self::NotMember => "not_member",
Self::AlreadyActive => "already_active",
Self::CycleKindLocked => "cycle_kind_locked",
Self::MembershipExpired => "membership_expired",
Self::StateChanged => "state_changed",
Self::PlanNotPurchasable => "plan_not_purchasable",
Self::PlanCatalogMissing => "plan_catalog_missing",
Self::ProductIdUnparsable => "product_id_unparsable",
Self::MembershipProductRetired => "membership_product_retired",
Self::InvalidPlanConfig => "invalid_plan_config",
}
}
}
/// 会员领域错误:机器可读 `code` + 人读 `message`。
///
/// 只在模块内部与 procedure 结果装载之间传递,不落 SpacetimeDB 表,因此不派生 `SpacetimeType`。
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RuntimeProfileMembershipDomainError {
pub code: RuntimeProfileMembershipErrorCode,
pub message: String,
}
impl RuntimeProfileMembershipDomainError {
pub fn new(code: RuntimeProfileMembershipErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
}
}
}
impl std::fmt::Display for RuntimeProfileMembershipDomainError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.message)
}
}
impl std::error::Error for RuntimeProfileMembershipDomainError {}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum RuntimeProfileRechargeOrderStatus {
@@ -1888,6 +1964,7 @@ pub struct RuntimeProfileRechargeCenterProcedureResult {
pub record: Option<RuntimeProfileRechargeCenterSnapshot>,
pub order: Option<RuntimeProfileRechargeOrderSnapshot>,
pub error_message: Option<String>,
pub error_code: Option<RuntimeProfileMembershipErrorCode>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
@@ -1969,6 +2046,7 @@ pub struct RuntimeProfileMembershipPlanAdminProcedureResult {
pub ok: bool,
pub record: Option<RuntimeProfileMembershipPlanRecord>,
pub error_message: Option<String>,
pub error_code: Option<RuntimeProfileMembershipErrorCode>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
@@ -2019,6 +2097,7 @@ pub struct RuntimeProfileMembershipUpgradeQuoteProcedureResult {
pub ok: bool,
pub quote: Option<RuntimeProfileMembershipUpgradeQuoteSnapshot>,
pub error_message: Option<String>,
pub error_code: Option<RuntimeProfileMembershipErrorCode>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
@@ -233,6 +233,11 @@ pub enum SpacetimeClientError {
Build(String),
ConnectDropped,
Procedure(String),
/// 会员 procedure 返回了带机器可读错误码的业务拒绝。
ProcedureRejected {
code: module_runtime::RuntimeProfileMembershipErrorCode,
message: String,
},
Runtime(String),
Timeout(SpacetimeClientStage),
}
@@ -991,6 +996,16 @@ impl SpacetimeClientError {
Self::Procedure(message.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()))
}
pub(crate) fn procedure_rejected(
code: module_runtime::RuntimeProfileMembershipErrorCode,
message: Option<String>,
) -> Self {
Self::ProcedureRejected {
code,
message: message.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
}
}
pub(crate) fn missing_snapshot(label: &'static str) -> Self {
Self::Procedure(format!("SpacetimeDB procedure 未返回{label}"))
}
@@ -1073,6 +1088,7 @@ impl fmt::Display for SpacetimeClientError {
Self::Build(message) | Self::Procedure(message) | Self::Runtime(message) => {
f.write_str(message)
}
Self::ProcedureRejected { message, .. } => f.write_str(message),
Self::ConnectDropped => f.write_str("SpacetimeDB 连接在返回结果前已断开"),
Self::Timeout(stage) => {
f.write_str(&format!("SpacetimeDB {} 调用超时", stage.as_str()))
@@ -1,5 +1,19 @@
use super::*;
/// 会员 procedure 失败统一落错误:有机器可读 `error_code` 时走 `ProcedureRejected`,否则回退字符串错误。
pub(crate) fn map_runtime_profile_membership_procedure_failure(
error_code: Option<crate::module_bindings::RuntimeProfileMembershipErrorCode>,
error_message: Option<String>,
) -> SpacetimeClientError {
match error_code {
Some(code) => SpacetimeClientError::procedure_rejected(
map_runtime_profile_membership_error_code_back(code),
error_message,
),
None => SpacetimeClientError::procedure_failed(error_message),
}
}
impl From<module_runtime::RuntimeProfileDashboardGetInput> for RuntimeProfileDashboardGetInput {
fn from(input: module_runtime::RuntimeProfileDashboardGetInput) -> Self {
Self {
@@ -736,7 +750,10 @@ pub(crate) fn map_runtime_profile_recharge_center_procedure_result(
result: RuntimeProfileRechargeCenterProcedureResult,
) -> Result<RuntimeProfileRechargeCenterRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
return Err(map_runtime_profile_membership_procedure_failure(
result.error_code,
result.error_message,
));
}
let snapshot = result
@@ -772,7 +789,10 @@ pub(crate) fn map_runtime_profile_recharge_order_procedure_result(
SpacetimeClientError,
> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
return Err(map_runtime_profile_membership_procedure_failure(
result.error_code,
result.error_message,
));
}
let center = result
@@ -2032,6 +2052,46 @@ pub(crate) fn map_runtime_profile_membership_change_kind_back(
}
}
pub(crate) fn map_runtime_profile_membership_error_code_back(
value: crate::module_bindings::RuntimeProfileMembershipErrorCode,
) -> module_runtime::RuntimeProfileMembershipErrorCode {
match value {
crate::module_bindings::RuntimeProfileMembershipErrorCode::UpgradeRejected => {
module_runtime::RuntimeProfileMembershipErrorCode::UpgradeRejected
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::NotMember => {
module_runtime::RuntimeProfileMembershipErrorCode::NotMember
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::AlreadyActive => {
module_runtime::RuntimeProfileMembershipErrorCode::AlreadyActive
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::CycleKindLocked => {
module_runtime::RuntimeProfileMembershipErrorCode::CycleKindLocked
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::MembershipExpired => {
module_runtime::RuntimeProfileMembershipErrorCode::MembershipExpired
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::StateChanged => {
module_runtime::RuntimeProfileMembershipErrorCode::StateChanged
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::PlanNotPurchasable => {
module_runtime::RuntimeProfileMembershipErrorCode::PlanNotPurchasable
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::PlanCatalogMissing => {
module_runtime::RuntimeProfileMembershipErrorCode::PlanCatalogMissing
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::ProductIdUnparsable => {
module_runtime::RuntimeProfileMembershipErrorCode::ProductIdUnparsable
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::MembershipProductRetired => {
module_runtime::RuntimeProfileMembershipErrorCode::MembershipProductRetired
}
crate::module_bindings::RuntimeProfileMembershipErrorCode::InvalidPlanConfig => {
module_runtime::RuntimeProfileMembershipErrorCode::InvalidPlanConfig
}
}
}
pub(crate) fn map_runtime_profile_membership_model_access(
value: module_runtime::RuntimeProfileMembershipModelAccess,
) -> crate::module_bindings::RuntimeProfileMembershipModelAccess {
@@ -2131,7 +2191,10 @@ pub(crate) fn map_runtime_profile_membership_upgrade_quote_procedure_result(
result: RuntimeProfileMembershipUpgradeQuoteProcedureResult,
) -> Result<module_runtime::RuntimeProfileMembershipUpgradeQuoteRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
return Err(map_runtime_profile_membership_procedure_failure(
result.error_code,
result.error_message,
));
}
let quote = result
@@ -2173,7 +2236,10 @@ pub(crate) fn map_runtime_profile_membership_plan_admin_procedure_result(
result: RuntimeProfileMembershipPlanAdminProcedureResult,
) -> Result<module_runtime::RuntimeProfileMembershipPlanRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
return Err(map_runtime_profile_membership_procedure_failure(
result.error_code,
result.error_message,
));
}
let record = result
@@ -705,6 +705,7 @@ pub mod runtime_profile_invite_code_admin_upsert_input_type;
pub mod runtime_profile_invite_code_snapshot_type;
pub mod runtime_profile_membership_change_kind_type;
pub mod runtime_profile_membership_cycle_kind_type;
pub mod runtime_profile_membership_error_code_type;
pub mod runtime_profile_membership_get_input_type;
pub mod runtime_profile_membership_model_access_type;
pub mod runtime_profile_membership_order_change_snapshot_type;
@@ -1579,6 +1580,7 @@ pub use runtime_profile_invite_code_admin_upsert_input_type::RuntimeProfileInvit
pub use runtime_profile_invite_code_snapshot_type::RuntimeProfileInviteCodeSnapshot;
pub use runtime_profile_membership_change_kind_type::RuntimeProfileMembershipChangeKind;
pub use runtime_profile_membership_cycle_kind_type::RuntimeProfileMembershipCycleKind;
pub use runtime_profile_membership_error_code_type::RuntimeProfileMembershipErrorCode;
pub use runtime_profile_membership_get_input_type::RuntimeProfileMembershipGetInput;
pub use runtime_profile_membership_model_access_type::RuntimeProfileMembershipModelAccess;
pub use runtime_profile_membership_order_change_snapshot_type::RuntimeProfileMembershipOrderChangeSnapshot;
@@ -0,0 +1,36 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
#[derive(Copy, Eq, Hash)]
pub enum RuntimeProfileMembershipErrorCode {
UpgradeRejected,
NotMember,
AlreadyActive,
CycleKindLocked,
MembershipExpired,
StateChanged,
PlanNotPurchasable,
PlanCatalogMissing,
ProductIdUnparsable,
MembershipProductRetired,
InvalidPlanConfig,
}
impl __sdk::InModule for RuntimeProfileMembershipErrorCode {
type Module = super::RemoteModule;
}
@@ -4,6 +4,7 @@
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::runtime_profile_membership_error_code_type::RuntimeProfileMembershipErrorCode;
use super::runtime_profile_membership_plan_record_type::RuntimeProfileMembershipPlanRecord;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
@@ -12,6 +13,7 @@ pub struct RuntimeProfileMembershipPlanAdminProcedureResult {
pub ok: bool,
pub record: Option<RuntimeProfileMembershipPlanRecord>,
pub error_message: Option<String>,
pub error_code: Option<RuntimeProfileMembershipErrorCode>,
}
impl __sdk::InModule for RuntimeProfileMembershipPlanAdminProcedureResult {
@@ -4,6 +4,7 @@
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::runtime_profile_membership_error_code_type::RuntimeProfileMembershipErrorCode;
use super::runtime_profile_membership_upgrade_quote_snapshot_type::RuntimeProfileMembershipUpgradeQuoteSnapshot;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
@@ -12,6 +13,7 @@ pub struct RuntimeProfileMembershipUpgradeQuoteProcedureResult {
pub ok: bool,
pub quote: Option<RuntimeProfileMembershipUpgradeQuoteSnapshot>,
pub error_message: Option<String>,
pub error_code: Option<RuntimeProfileMembershipErrorCode>,
}
impl __sdk::InModule for RuntimeProfileMembershipUpgradeQuoteProcedureResult {
@@ -4,6 +4,7 @@
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::runtime_profile_membership_error_code_type::RuntimeProfileMembershipErrorCode;
use super::runtime_profile_recharge_center_snapshot_type::RuntimeProfileRechargeCenterSnapshot;
use super::runtime_profile_recharge_order_snapshot_type::RuntimeProfileRechargeOrderSnapshot;
@@ -14,6 +15,7 @@ pub struct RuntimeProfileRechargeCenterProcedureResult {
pub record: Option<RuntimeProfileRechargeCenterSnapshot>,
pub order: Option<RuntimeProfileRechargeOrderSnapshot>,
pub error_message: Option<String>,
pub error_code: Option<RuntimeProfileMembershipErrorCode>,
}
impl __sdk::InModule for RuntimeProfileRechargeCenterProcedureResult {
File diff suppressed because it is too large Load Diff