@theaiplatform/miniapp-sdk 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,248 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "bumpalo"
7
+ version = "3.20.3"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
10
+
11
+ [[package]]
12
+ name = "cfg-if"
13
+ version = "1.0.4"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
16
+
17
+ [[package]]
18
+ name = "futures-core"
19
+ version = "0.3.33"
20
+ source = "registry+https://github.com/rust-lang/crates.io-index"
21
+ checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
22
+
23
+ [[package]]
24
+ name = "futures-task"
25
+ version = "0.3.33"
26
+ source = "registry+https://github.com/rust-lang/crates.io-index"
27
+ checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
28
+
29
+ [[package]]
30
+ name = "futures-util"
31
+ version = "0.3.33"
32
+ source = "registry+https://github.com/rust-lang/crates.io-index"
33
+ checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
34
+ dependencies = [
35
+ "futures-core",
36
+ "futures-task",
37
+ "pin-project-lite",
38
+ "slab",
39
+ ]
40
+
41
+ [[package]]
42
+ name = "itoa"
43
+ version = "1.0.18"
44
+ source = "registry+https://github.com/rust-lang/crates.io-index"
45
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
46
+
47
+ [[package]]
48
+ name = "js-sys"
49
+ version = "0.3.103"
50
+ source = "registry+https://github.com/rust-lang/crates.io-index"
51
+ checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
52
+ dependencies = [
53
+ "cfg-if",
54
+ "futures-util",
55
+ "wasm-bindgen",
56
+ ]
57
+
58
+ [[package]]
59
+ name = "memchr"
60
+ version = "2.8.3"
61
+ source = "registry+https://github.com/rust-lang/crates.io-index"
62
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
63
+
64
+ [[package]]
65
+ name = "miniapp-sdk-wasm-ui-example"
66
+ version = "0.1.0"
67
+ dependencies = [
68
+ "js-sys",
69
+ "serde",
70
+ "serde-wasm-bindgen",
71
+ "serde_json",
72
+ "wasm-bindgen",
73
+ "web-sys",
74
+ ]
75
+
76
+ [[package]]
77
+ name = "once_cell"
78
+ version = "1.21.4"
79
+ source = "registry+https://github.com/rust-lang/crates.io-index"
80
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
81
+
82
+ [[package]]
83
+ name = "pin-project-lite"
84
+ version = "0.2.17"
85
+ source = "registry+https://github.com/rust-lang/crates.io-index"
86
+ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
87
+
88
+ [[package]]
89
+ name = "proc-macro2"
90
+ version = "1.0.106"
91
+ source = "registry+https://github.com/rust-lang/crates.io-index"
92
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
93
+ dependencies = [
94
+ "unicode-ident",
95
+ ]
96
+
97
+ [[package]]
98
+ name = "quote"
99
+ version = "1.0.46"
100
+ source = "registry+https://github.com/rust-lang/crates.io-index"
101
+ checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
102
+ dependencies = [
103
+ "proc-macro2",
104
+ ]
105
+
106
+ [[package]]
107
+ name = "rustversion"
108
+ version = "1.0.23"
109
+ source = "registry+https://github.com/rust-lang/crates.io-index"
110
+ checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
111
+
112
+ [[package]]
113
+ name = "serde"
114
+ version = "1.0.228"
115
+ source = "registry+https://github.com/rust-lang/crates.io-index"
116
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
117
+ dependencies = [
118
+ "serde_core",
119
+ "serde_derive",
120
+ ]
121
+
122
+ [[package]]
123
+ name = "serde-wasm-bindgen"
124
+ version = "0.6.5"
125
+ source = "registry+https://github.com/rust-lang/crates.io-index"
126
+ checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
127
+ dependencies = [
128
+ "js-sys",
129
+ "serde",
130
+ "wasm-bindgen",
131
+ ]
132
+
133
+ [[package]]
134
+ name = "serde_core"
135
+ version = "1.0.228"
136
+ source = "registry+https://github.com/rust-lang/crates.io-index"
137
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
138
+ dependencies = [
139
+ "serde_derive",
140
+ ]
141
+
142
+ [[package]]
143
+ name = "serde_derive"
144
+ version = "1.0.228"
145
+ source = "registry+https://github.com/rust-lang/crates.io-index"
146
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
147
+ dependencies = [
148
+ "proc-macro2",
149
+ "quote",
150
+ "syn",
151
+ ]
152
+
153
+ [[package]]
154
+ name = "serde_json"
155
+ version = "1.0.150"
156
+ source = "registry+https://github.com/rust-lang/crates.io-index"
157
+ checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
158
+ dependencies = [
159
+ "itoa",
160
+ "memchr",
161
+ "serde",
162
+ "serde_core",
163
+ "zmij",
164
+ ]
165
+
166
+ [[package]]
167
+ name = "slab"
168
+ version = "0.4.12"
169
+ source = "registry+https://github.com/rust-lang/crates.io-index"
170
+ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
171
+
172
+ [[package]]
173
+ name = "syn"
174
+ version = "2.0.119"
175
+ source = "registry+https://github.com/rust-lang/crates.io-index"
176
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
177
+ dependencies = [
178
+ "proc-macro2",
179
+ "quote",
180
+ "unicode-ident",
181
+ ]
182
+
183
+ [[package]]
184
+ name = "unicode-ident"
185
+ version = "1.0.24"
186
+ source = "registry+https://github.com/rust-lang/crates.io-index"
187
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
188
+
189
+ [[package]]
190
+ name = "wasm-bindgen"
191
+ version = "0.2.126"
192
+ source = "registry+https://github.com/rust-lang/crates.io-index"
193
+ checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
194
+ dependencies = [
195
+ "cfg-if",
196
+ "once_cell",
197
+ "rustversion",
198
+ "wasm-bindgen-macro",
199
+ "wasm-bindgen-shared",
200
+ ]
201
+
202
+ [[package]]
203
+ name = "wasm-bindgen-macro"
204
+ version = "0.2.126"
205
+ source = "registry+https://github.com/rust-lang/crates.io-index"
206
+ checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
207
+ dependencies = [
208
+ "quote",
209
+ "wasm-bindgen-macro-support",
210
+ ]
211
+
212
+ [[package]]
213
+ name = "wasm-bindgen-macro-support"
214
+ version = "0.2.126"
215
+ source = "registry+https://github.com/rust-lang/crates.io-index"
216
+ checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
217
+ dependencies = [
218
+ "bumpalo",
219
+ "proc-macro2",
220
+ "quote",
221
+ "syn",
222
+ "wasm-bindgen-shared",
223
+ ]
224
+
225
+ [[package]]
226
+ name = "wasm-bindgen-shared"
227
+ version = "0.2.126"
228
+ source = "registry+https://github.com/rust-lang/crates.io-index"
229
+ checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
230
+ dependencies = [
231
+ "unicode-ident",
232
+ ]
233
+
234
+ [[package]]
235
+ name = "web-sys"
236
+ version = "0.3.103"
237
+ source = "registry+https://github.com/rust-lang/crates.io-index"
238
+ checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
239
+ dependencies = [
240
+ "js-sys",
241
+ "wasm-bindgen",
242
+ ]
243
+
244
+ [[package]]
245
+ name = "zmij"
246
+ version = "1.0.23"
247
+ source = "registry+https://github.com/rust-lang/crates.io-index"
248
+ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
@@ -0,0 +1,18 @@
1
+ [package]
2
+ name = "miniapp-sdk-wasm-ui-example"
3
+ version = "0.1.0"
4
+ edition = "2024"
5
+ publish = false
6
+
7
+ [lib]
8
+ crate-type = ["cdylib", "rlib"]
9
+
10
+ [dependencies]
11
+ js-sys = "0.3.98"
12
+ serde = { version = "1.0.228", features = ["derive"] }
13
+ serde-wasm-bindgen = "0.6.5"
14
+ serde_json = "1.0.149"
15
+ wasm-bindgen = "0.2.121"
16
+ web-sys = { version = "0.3.98", features = ["Element"] }
17
+
18
+ [workspace]
@@ -0,0 +1,19 @@
1
+ # Rust/WASM UI example
2
+
3
+ This crate is a clean wasm-bindgen consumer of
4
+ `@theaiplatform/miniapp-sdk/ui/wasm`. It demonstrates the full lifecycle:
5
+ mount, controlled revision updates, focus, action validation, replay/stale
6
+ rejection, and idempotent teardown.
7
+
8
+ Build it with:
9
+
10
+ ```bash
11
+ cargo check --target wasm32-unknown-unknown
12
+ ```
13
+
14
+ The JavaScript application that loads the generated wasm must import the SDK
15
+ styles once:
16
+
17
+ ```ts
18
+ import '@theaiplatform/miniapp-sdk/ui/styles.css';
19
+ ```
@@ -0,0 +1,190 @@
1
+ //! Capability: miniapp-platform
2
+ //!
3
+ //! Clean wasm-bindgen consumer of `@theaiplatform/miniapp-sdk/ui/wasm`.
4
+
5
+ use std::{
6
+ cell::{Cell, RefCell},
7
+ collections::HashSet,
8
+ rc::Rc,
9
+ };
10
+
11
+ use js_sys::Function;
12
+ use serde::Deserialize;
13
+ use serde_json::{Value, json};
14
+ use wasm_bindgen::{JsCast, prelude::*};
15
+ use web_sys::Element;
16
+
17
+ #[wasm_bindgen(module = "@theaiplatform/miniapp-sdk/ui/wasm")]
18
+ extern "C" {
19
+ type JsMiniAppUiRoot;
20
+
21
+ #[wasm_bindgen(js_name = createMiniAppUiRoot, catch)]
22
+ fn create_miniapp_ui_root(
23
+ container: &Element,
24
+ model: &JsValue,
25
+ dispatch: &Function,
26
+ ) -> Result<JsMiniAppUiRoot, JsValue>;
27
+
28
+ #[wasm_bindgen(method, catch)]
29
+ fn update(this: &JsMiniAppUiRoot, model: &JsValue) -> Result<(), JsValue>;
30
+
31
+ #[wasm_bindgen(method, catch)]
32
+ fn focus(this: &JsMiniAppUiRoot, control_id: &str) -> Result<(), JsValue>;
33
+
34
+ #[wasm_bindgen(method, catch)]
35
+ fn unmount(this: &JsMiniAppUiRoot) -> Result<(), JsValue>;
36
+ }
37
+
38
+ #[derive(Deserialize)]
39
+ #[serde(rename_all = "camelCase")]
40
+ struct UiAction {
41
+ event_id: String,
42
+ revision: u64,
43
+ control_id: String,
44
+ action: String,
45
+ }
46
+
47
+ fn js_error(message: impl AsRef<str>) -> JsValue {
48
+ js_sys::Error::new(message.as_ref()).into()
49
+ }
50
+
51
+ fn model(revision: u64, name: &str, busy: bool) -> Value {
52
+ json!({
53
+ "revision": revision,
54
+ "state": if busy { "loading" } else { "idle" },
55
+ "rootIds": ["layout"],
56
+ "nodes": [
57
+ {
58
+ "type": "stack",
59
+ "id": "layout",
60
+ "gap": "md",
61
+ "children": ["title", "name", "run", "status"]
62
+ },
63
+ {
64
+ "type": "heading",
65
+ "id": "title",
66
+ "level": 1,
67
+ "text": "Rust/WASM mini-app"
68
+ },
69
+ {
70
+ "type": "input",
71
+ "id": "name",
72
+ "label": "Name",
73
+ "value": name,
74
+ "action": "name.change",
75
+ "required": true,
76
+ "disabled": false,
77
+ "busy": false,
78
+ "inputType": "text"
79
+ },
80
+ {
81
+ "type": "button",
82
+ "id": "run",
83
+ "label": if busy { "Running…" } else { "Run" },
84
+ "action": "run",
85
+ "variant": "default",
86
+ "disabled": busy,
87
+ "busy": busy
88
+ },
89
+ {
90
+ "type": "status-bar",
91
+ "id": "status",
92
+ "tone": "neutral",
93
+ "text": "All UI state is controlled by Rust."
94
+ }
95
+ ]
96
+ })
97
+ }
98
+
99
+ /// Mounted SDK UI retained by Rust. The closure field keeps the JS dispatcher
100
+ /// alive for exactly the lifetime of the imperative root.
101
+ #[wasm_bindgen]
102
+ pub struct MiniApp {
103
+ root: Option<JsMiniAppUiRoot>,
104
+ _dispatch: Closure<dyn FnMut(JsValue) -> Result<(), JsValue>>,
105
+ revision: Rc<Cell<u64>>,
106
+ }
107
+
108
+ #[wasm_bindgen]
109
+ impl MiniApp {
110
+ /// Mounts the initial controlled model and installs replay/stale checks on
111
+ /// every action delivered back from JavaScript.
112
+ pub fn mount(container: Element) -> Result<MiniApp, JsValue> {
113
+ let revision = Rc::new(Cell::new(1_u64));
114
+ let dispatch_revision = Rc::clone(&revision);
115
+ let received_event_ids = Rc::new(RefCell::new(HashSet::<String>::new()));
116
+ let dispatch_event_ids = Rc::clone(&received_event_ids);
117
+ let dispatch =
118
+ Closure::<dyn FnMut(JsValue) -> Result<(), JsValue>>::new(move |value: JsValue| {
119
+ let action: UiAction = serde_wasm_bindgen::from_value(value)
120
+ .map_err(|error| js_error(format!("Malformed SDK UI action: {error}")))?;
121
+ if action.revision != dispatch_revision.get() {
122
+ return Err(js_error(format!(
123
+ "Rejected stale action revision {} for current revision {}",
124
+ action.revision,
125
+ dispatch_revision.get()
126
+ )));
127
+ }
128
+ if !dispatch_event_ids
129
+ .borrow_mut()
130
+ .insert(action.event_id.clone())
131
+ {
132
+ return Err(js_error(format!("Rejected replayed action {}", action.event_id)));
133
+ }
134
+
135
+ // A real mini-app routes the validated action into its Rust
136
+ // reducer. Reading these fields demonstrates that no React
137
+ // callback or host object crosses the ABI.
138
+ let _action_target = (&action.control_id, &action.action);
139
+ Ok(())
140
+ });
141
+ let initial_model = serde_wasm_bindgen::to_value(&model(1, "Ada", false))
142
+ .map_err(|error| js_error(format!("Could not serialize initial model: {error}")))?;
143
+ let root =
144
+ create_miniapp_ui_root(&container, &initial_model, dispatch.as_ref().unchecked_ref())?;
145
+
146
+ Ok(MiniApp {
147
+ root: Some(root),
148
+ _dispatch: dispatch,
149
+ revision,
150
+ })
151
+ }
152
+
153
+ /// Replaces controlled state with a newer model revision.
154
+ pub fn update(&self, revision: u64, name: &str, busy: bool) -> Result<(), JsValue> {
155
+ let root = self
156
+ .root
157
+ .as_ref()
158
+ .ok_or_else(|| js_error("The mini-app UI is unmounted"))?;
159
+ let next_model = serde_wasm_bindgen::to_value(&model(revision, name, busy))
160
+ .map_err(|error| js_error(format!("Could not serialize updated model: {error}")))?;
161
+ root.update(&next_model)?;
162
+ self.revision.set(revision);
163
+ Ok(())
164
+ }
165
+
166
+ /// Focuses a stable control identifier and maps JavaScript exceptions into
167
+ /// a normal Rust `Result`.
168
+ pub fn focus(&self, control_id: &str) -> Result<(), JsValue> {
169
+ self.root
170
+ .as_ref()
171
+ .ok_or_else(|| js_error("The mini-app UI is unmounted"))?
172
+ .focus(control_id)
173
+ }
174
+
175
+ /// Releases the UI root. Repeated calls are intentionally harmless.
176
+ pub fn unmount(&mut self) -> Result<(), JsValue> {
177
+ if let Some(root) = self.root.take() {
178
+ root.unmount()?;
179
+ }
180
+ Ok(())
181
+ }
182
+ }
183
+
184
+ impl Drop for MiniApp {
185
+ fn drop(&mut self) {
186
+ if let Some(root) = self.root.take() {
187
+ let _ = root.unmount();
188
+ }
189
+ }
190
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theaiplatform/miniapp-sdk",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Public SDK for building portable miniapps that run in The AI Platform.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -23,6 +23,10 @@
23
23
  "types": "./dist/sdk.d.ts",
24
24
  "import": "./dist/sdk.js"
25
25
  },
26
+ "./mcp": {
27
+ "types": "./dist/mcp.d.ts",
28
+ "import": "./dist/mcp.js"
29
+ },
26
30
  "./web": {
27
31
  "types": "./dist/web.d.ts",
28
32
  "import": "./dist/web.js"
@@ -31,6 +35,10 @@
31
35
  "types": "./dist/ui.d.ts",
32
36
  "import": "./dist/ui.js"
33
37
  },
38
+ "./ui/wasm": {
39
+ "types": "./dist/ui/wasm.d.ts",
40
+ "import": "./dist/ui/wasm.js"
41
+ },
34
42
  "./ui/styles.css": "./dist/ui/styles.css",
35
43
  "./ui/tailwind.css": "./dist/ui/tailwind.css",
36
44
  "./ui-components.json": "./ui-components.json",
@@ -52,6 +60,7 @@
52
60
  "types": "./dist/index.d.ts",
53
61
  "files": [
54
62
  "dist",
63
+ "examples",
55
64
  "config-schema.json",
56
65
  "ui-components.json",
57
66
  "README.md",
@@ -106,7 +115,11 @@
106
115
  "@rslib/core": "^0.23.2",
107
116
  "@rstest/core": "^0.9.10",
108
117
  "@tailwindcss/postcss": "^4.3.0",
118
+ "@types/jsdom": "^28.0.3",
109
119
  "@types/node": "^25.7.0",
120
+ "@types/react": "19.2.14",
121
+ "@types/react-dom": "19.2.3",
122
+ "jsdom": "^29.1.1",
110
123
  "postcss": "^8.5.6",
111
124
  "tailwindcss": "^4.3.0",
112
125
  "tw-animate-css": "^1.4.0",
@@ -114,6 +127,7 @@
114
127
  },
115
128
  "dependencies": {
116
129
  "@radix-ui/react-alert-dialog": "^1.1.15",
130
+ "@radix-ui/react-avatar": "1.1.11",
117
131
  "@radix-ui/react-checkbox": "^1.3.3",
118
132
  "@radix-ui/react-compose-refs": "^1.1.2",
119
133
  "@radix-ui/react-dialog": "^1.1.15",
@@ -136,7 +150,8 @@
136
150
  "prism-react-renderer": "^2.4.1",
137
151
  "react-resizable-panels": "^4.11.1",
138
152
  "saxes": "^6.0.0",
139
- "tailwind-merge": "^3.6.0"
153
+ "tailwind-merge": "^3.6.0",
154
+ "zod": "^4.4.3"
140
155
  },
141
156
  "scripts": {
142
157
  "build": "rm -rf dist && rslib build && node scripts/copy-rspack-loaders.mjs && node scripts/build-ui-styles.mjs",
@@ -8,6 +8,7 @@
8
8
  },
9
9
  "groups": {
10
10
  "foundations": [
11
+ "Avatar",
11
12
  "Badge",
12
13
  "Button",
13
14
  "ButtonGroup",
@@ -20,7 +21,8 @@
20
21
  "Icon",
21
22
  "Progress",
22
23
  "Separator",
23
- "Skeleton"
24
+ "Skeleton",
25
+ "StatusIndicator"
24
26
  ],
25
27
  "layout": [
26
28
  "Alert",
@@ -51,6 +53,9 @@
51
53
  "miniapp": [
52
54
  "CodeBlock",
53
55
  "MiniAppIconButton",
56
+ "MiniAppMetric",
57
+ "MiniAppPageHeader",
58
+ "MiniAppSectionHeader",
54
59
  "MiniAppStatusBar",
55
60
  "MiniAppToolbar"
56
61
  ],