Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/interactive-capabilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ OpenBitFun Playbook currently contains **22 features**, **21 settings pages**, a
- Generated per-item interaction audit: `docs/interactive-capabilities/technical/product-control-open-audit.json`
- Generated low-level audit map: `docs/interactive-capabilities/technical/tauri-command-map.json`

说明书、网站、搜索和 Agent 只看“功能 + 设置 + 子能力”。每项子能力都必须引用已注册 Tauri Command 或可解析的源码标记;这些证据不会进入公开目录。当前 **644** 个 Tauri 命令只用于实现覆盖审计。产品 UI 交互源码会在生成和检查时扫描并校验,但不会保存成随普通 UI 改动频繁变化的版本化快照。
说明书、网站、搜索和 Agent 只看“功能 + 设置 + 子能力”。每项子能力都必须引用已注册 Tauri Command 或可解析的源码标记;这些证据不会进入公开目录。当前 **645** 个 Tauri 命令只用于实现覆盖审计。产品 UI 交互源码会在生成和检查时扫描并校验,但不会保存成随普通 UI 改动频繁变化的版本化快照。

Docs, website, search, and agents see only features, settings, and documented sub-capabilities. Every sub-capability must reference a registered Tauri command or a resolvable source marker; evidence is stripped from public projections. The **644** Tauri commands remain implementation-audit evidence only. Product UI interaction sources are scanned and validated during generation and checks, but are not stored as a versioned snapshot that churns with ordinary UI changes.
Docs, website, search, and agents see only features, settings, and documented sub-capabilities. Every sub-capability must reference a registered Tauri command or a resolvable source marker; evidence is stripped from public projections. The **645** Tauri commands remain implementation-audit evidence only. Product UI interaction sources are scanned and validated during generation and checks, but are not stored as a versioned snapshot that churns with ordinary UI changes.

## 控制边界 / Control boundary

Expand Down
20 changes: 16 additions & 4 deletions docs/interactive-capabilities/technical/tauri-command-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"schemaVersion": 2,
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
"catalogDigest": "896281a3cd5cac2b50ec607988e04624224444911ddb2d58ba59a5d7d06493c5",
"commandCount": 644,
"commandCount": 645,
"coverage": {
"commandCount": 644,
"commandCount": 645,
"documentedCommandCount": 608,
"implementationCommandCount": 36,
"implementationDigest": "c9bbc0f2ca3695d8c18cff285386edeba7bcf3b11120adb57509a80b09ee3297"
"implementationCommandCount": 37,
"implementationDigest": "3c5e64b6ff16d55d95c2a6b4f77046be009a554b395b4a52bf8ed7c162ab1093"
},
"commands": [
{
Expand Down Expand Up @@ -5256,6 +5256,18 @@
"signature": "fn mark_openbitfun_control_surface_unready()",
"remoteWorkspacePolicy": "WorkspaceAgnostic"
},
{
"id": "market_image_load",
"moduleId": "market_image",
"capabilityId": null,
"capabilityIds": [],
"documentedItemIds": [],
"visibility": "internal",
"rustPath": "api::market_image_api::market_image_load",
"sourceFile": "src/apps/desktop/src/api/market_image_api.rs",
"signature": "fn market_image_load( app: tauri::AppHandle, request: MarketImageRequest, ) -> Result<tauri::ipc::Response, String>",
"remoteWorkspacePolicy": "WorkspaceAgnostic"
},
{
"id": "miniapp_agent_cancel",
"moduleId": "miniapp_agent",
Expand Down
41 changes: 41 additions & 0 deletions src/apps/desktop/src/api/market_image_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! Controller-owned public image cache shared by the two marketplace surfaces.

use openbitfun_services_integrations::{
appearance_market::AppearanceMarketClient, market_image::MarketImageCache,
miniapp_market::MarketClient,
};
use serde::Deserialize;
use tauri::Manager;
use tokio::sync::OnceCell;

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MarketImageRequest {
pub source: String,
}

#[tauri::command]
pub async fn market_image_load(
app: tauri::AppHandle,
request: MarketImageRequest,
) -> Result<tauri::ipc::Response, String> {
static CACHE: OnceCell<MarketImageCache> = OnceCell::const_new();
let cache = CACHE
.get_or_try_init(|| async {
let root = app
.path()
.app_cache_dir()
.map_err(|error| error.to_string())?
.join("market-images-v1");
MarketImageCache::new(
root,
&MarketClient::configured_base_url(),
&AppearanceMarketClient::configured_base_url(),
)
})
.await?;
cache
.load(&request.source)
.await
.map(tauri::ipc::Response::new)
}
1 change: 1 addition & 0 deletions src/apps/desktop/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod git_api;
pub mod html_preview_api;
pub mod i18n_api;
pub mod insights_api;
pub mod market_image_api;
pub mod mcp_api;
pub mod miniapp_agent_api;
pub mod miniapp_api;
Expand Down
1 change: 1 addition & 0 deletions src/apps/desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,7 @@ pub async fn run() {
api::miniapp_api::miniapp_get_customization_metadata,
api::miniapp_api::miniapp_decline_builtin_update,
api::miniapp_market_api::miniapp_market_browse,
api::market_image_api::market_image_load,
api::miniapp_market_api::miniapp_market_get_listing,
api::miniapp_market_api::miniapp_market_capture_window,
api::miniapp_market_api::miniapp_market_set_rating,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"digest": "fnv1a64:6c2c8c606588ee3f",
"digest": "fnv1a64:7976cf996632e304",
"retiredCommandPrefixes": [
{
"prefix": "lsp_",
Expand Down Expand Up @@ -4126,6 +4126,18 @@
"reason": "the controller keeps this command; peer hosts refuse it before dispatch"
}
},
{
"id": "market_image_load",
"surface": "tauri_command",
"remoteWorkspace": "WorkspaceAgnostic",
"peer": {
"kind": "controller_local"
},
"cliPeer": {
"kind": "unsupported",
"reason": "the controller keeps this command; peer hosts refuse it before dispatch"
}
},
{
"id": "miniapp_agent_cancel",
"surface": "tauri_command",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ pub(super) const OPERATIONS: &[OperationDefinition] = &[
op("mark_announcement_seen", Agnostic, ControllerLocal, REFUSED),
op("mark_openbitfun_control_surface_ready", Agnostic, ControllerLocal, REFUSED),
op("mark_openbitfun_control_surface_unready", Agnostic, ControllerLocal, REFUSED),
op("market_image_load", Agnostic, ControllerLocal, REFUSED),
op("miniapp_agent_cancel", Unaudited, Proxied, CLI_NOT_IMPLEMENTED),
op("miniapp_agent_cancel_stale_runs", Unaudited, Proxied, CLI_NOT_IMPLEMENTED),
op("miniapp_agent_ensure_session", LocalOnly, Proxied, CLI_NOT_IMPLEMENTED),
Expand Down
7 changes: 7 additions & 0 deletions src/crates/services/services-integrations/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ pnpm run check:core-boundaries
Other family-specific targets remain in `Cargo.toml`; add a guide command only
for a recurring workflow, not to mirror every test target.

For persistent public marketplace image caching (restart/offline reuse, URL
boundaries, and bounded disk storage), run:

```bash
cargo test --locked -p openbitfun-services-integrations --no-default-features --features miniapp-market --lib market_image::tests
```

On Windows with an initialized WSL distribution, set `OPENBITFUN_TEST_WSL_DISTRO`
and run `cargo test -p openbitfun-services-integrations --no-default-features
--features remote-ssh-concrete --lib wsl_windows_workspace_transport -- --ignored`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ pub struct AppearanceMarketClient {
}

impl AppearanceMarketClient {
pub fn configured_base_url() -> String {
std::env::var("OPENBITFUN_APPEARANCE_MARKET_API_URL")
.unwrap_or_else(|_| DEFAULT_APPEARANCE_MARKET_API_URL.to_string())
}

pub async fn from_environment() -> Result<Self, MarketClientError> {
let base_url = std::env::var("OPENBITFUN_APPEARANCE_MARKET_API_URL")
.unwrap_or_else(|_| DEFAULT_APPEARANCE_MARKET_API_URL.to_string());
let identity = AccountIdentityClient::from_environment().await?;
Self::with_identity(base_url, identity)
Self::with_identity(Self::configured_base_url(), identity)
}

pub async fn new(
Expand Down
3 changes: 3 additions & 0 deletions src/crates/services/services-integrations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ pub mod miniapp;
#[cfg(feature = "miniapp-market")]
pub mod miniapp_market;

#[cfg(feature = "miniapp-market")]
pub mod market_image;

#[cfg(feature = "plugin-source")]
pub mod plugin_source;

Expand Down
Loading
Loading