Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d9b6528
test(sdk): complete lifecycle error vectors
CN059 Aug 28, 2026
e2b06ff
test(sdk): share security conformance vectors
CN059 Aug 28, 2026
4e92155
feat(cli): add explicit SDK project migration
CN059 Aug 28, 2026
99c8988
docs(sdk): gate API docs and migrations
CN059 Aug 28, 2026
53d3efa
feat(sdk): expose the UI registry contract
CN059 Aug 28, 2026
1dfb224
feat(sdk): generate TypeScript UI builders
CN059 Aug 28, 2026
905d5cb
feat(sdk): align TypeScript lifecycle errors
CN059 Aug 28, 2026
e009d95
test(runtime): revalidate the QuickJS candidate
CN059 Aug 28, 2026
3269831
build(sdk): emit the TypeScript package boundary
CN059 Aug 28, 2026
3edb72e
feat(sdk): adapt TypeScript widgets to WIT
CN059 Aug 28, 2026
5385b0a
test(sdk): run TypeScript through the host
CN059 Aug 28, 2026
8409ae7
test(sdk): execute shared TypeScript security vectors
CN059 Aug 28, 2026
a73b7b0
fix(platform): aggregate Linux process CPU
CN059 Aug 28, 2026
ee52fd8
test(runtime): record TypeScript steady-state CPU
CN059 Aug 28, 2026
2f24451
ci(sdk): gate the QuickJS candidate on three systems
CN059 Aug 28, 2026
f2aa9b6
fix(ci): resolve the pnpm setup action
CN059 Aug 28, 2026
f659e19
fix(sdk): invoke pnpm portably on Windows
CN059 Aug 28, 2026
05a135b
fix(sdk): launch the pnpm shim through Windows shell
CN059 Aug 28, 2026
0b7e2a5
fix(sdk): launch local Node shims portably
CN059 Aug 28, 2026
e4b94f8
fix(sdk): normalize generated TypeScript output
CN059 Aug 28, 2026
33f58a3
fix(sdk): verify components through the Windows shim
CN059 Aug 28, 2026
5eca079
docs(sdk): close the PP-M7 implementation milestone
CN059 Aug 28, 2026
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
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ jobs:
run: cargo check --workspace --exclude floatile-clock-wasm --all-targets --locked
- name: Clippy
run: cargo clippy --workspace --exclude floatile-clock-wasm --all-targets --locked -- -D warnings
- name: Rust SDK API docs
if: runner.os == 'Linux'
env:
RUSTDOCFLAGS: -D warnings
run: cargo doc -p floatile-sdk -p floatile-sdk-macros -p floatile-ui-schema --no-deps --locked
- name: Set up TypeScript SDK toolchain
if: runner.os == 'Linux'
uses: actions/setup-node@v7
with:
node-version: '26.8.0'
- name: Set up pnpm
if: runner.os == 'Linux'
uses: pnpm/action-setup@v5
with:
version: '11.3.0'
- name: TypeScript SDK generated contract
if: runner.os == 'Linux'
run: |
pnpm install --dir sdk/typescript --frozen-lockfile
cargo run -p floatile-cli --locked -- schema ui target/floatile-ui-registry.json
node sdk/typescript/scripts/generate-components.mjs target/floatile-ui-registry.json sdk/typescript/src/generated/components.ts --check
pnpm --dir sdk/typescript typecheck
pnpm --dir sdk/typescript test
pnpm --dir sdk/typescript build
- name: Build WASI guest (hermetic integration tests)
# 集成测试读取 target/wasm32-wasip2/debug 下的组件;先构建保证干净
# checkout 上测试不依赖执行顺序或测试内并发构建。
Expand Down
98 changes: 98 additions & 0 deletions .github/workflows/typescript-runtime-candidate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: TypeScript runtime candidate

on:
workflow_dispatch:
pull_request:
paths:
- ".github/workflows/typescript-runtime-candidate.yml"
- "conformance/**"
- "crates/floatile-runtime/**"
- "sdk/typescript/**"
- "spikes/typescript-runtime/**"
- "wit/**"

permissions:
contents: read

concurrency:
group: typescript-runtime-${{ github.ref }}
cancel-in-progress: true

env:
COMPONENTIZE_QJS_SHA: 7788644697ed08a841ad0910d4e99772c6fe7132
CARGO_INCREMENTAL: 0

jobs:
quickjs:
name: QuickJS candidate (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Checkout Floatile
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: floatile
persist-credentials: false

- name: Checkout fixed componentize-qjs candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: andreiltd/componentize-qjs
ref: refs/pull/76/head
path: componentize-qjs
persist-credentials: false

- name: Verify candidate identity
shell: bash
working-directory: componentize-qjs
run: test "$(git rev-parse HEAD)" = "$COMPONENTIZE_QJS_SHA"

- name: Install Rust
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
toolchain: 1.97.1
targets: wasm32-wasip2

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 26.8.0

- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
version: 11.3.0

- name: Build fixed componentize-qjs CLI
working-directory: componentize-qjs
run: cargo build --release -p componentize-qjs-cli --features opt-size

- name: Install locked TypeScript toolchains
shell: bash
working-directory: floatile
run: |
pnpm install --dir sdk/typescript --frozen-lockfile
pnpm install --dir spikes/typescript-runtime --frozen-lockfile

- name: Build Floatile TypeScript component
shell: bash
working-directory: floatile
run: |
if [[ "$RUNNER_OS" == "Windows" ]]; then
candidate="$(cd ../componentize-qjs && pwd -W)/target/release/componentize-qjs.exe"
else
candidate="$(cd ../componentize-qjs && pwd)/target/release/componentize-qjs"
fi
FLOATILE_SPIKE_DISABLE_RUSTC_WRAPPER=1 \
FLOATILE_COMPONENTIZE_QJS_BIN="$candidate" \
pnpm --dir spikes/typescript-runtime build:quickjs

- name: Run Linux behavior and security vectors
if: runner.os == 'Linux'
working-directory: floatile
env:
FLOATILE_SPIKE_DISABLE_RUSTC_WRAPPER: "1"
run: pnpm --dir spikes/typescript-runtime test:quickjs
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# 本机 cargo 配置(sccache 路径、wrapper 等本机专属,不入库)
.cargo/
node_modules/
sdk/typescript/dist/
spikes/typescript-runtime/generated/
**/*.rs.bk
*.log
Expand Down Expand Up @@ -31,4 +32,3 @@ Desktop.ini
*~
*.swp
*.swo

21 changes: 21 additions & 0 deletions conformance/sdk-lifecycle-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,38 @@
"schemaVersion": 1,
"engineApiVersion": "1.2.0",
"vectors": [
{
"id": "start-invalid-input",
"callback": "start",
"guestError": "invalid-input",
"message": "conformance start invalid input",
"expectedHostOutcome": "rejected"
},
{
"id": "start-rejected",
"callback": "start",
"guestError": "rejected",
"message": "conformance start rejection",
"expectedHostOutcome": "rejected"
},
{
"id": "start-internal",
"callback": "start",
"guestError": "internal",
"message": null,
"expectedHostOutcome": "rejected"
},
{
"id": "event-invalid-input",
"callback": "event",
"guestError": "invalid-input",
"message": "conformance event invalid input",
"expectedHostOutcome": "rejected"
},
{
"id": "event-rejected",
"callback": "event",
"guestError": "rejected",
"message": "conformance event rejection",
"expectedHostOutcome": "rejected"
},
Expand Down
41 changes: 41 additions & 0 deletions conformance/sdk-security-v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"schemaVersion": 1,
"engineApiVersion": "1.2.0",
"vectors": [
{
"id": "broker-deny",
"mode": "deny",
"trigger": "start",
"expectedHostOutcome": "completed",
"hostSurvives": true
},
{
"id": "invalid-state-patch",
"mode": "bad-patch",
"trigger": "start",
"expectedHostOutcome": "completed-without-state-update",
"hostSurvives": true
},
{
"id": "fuel-exhaustion",
"mode": "loop",
"trigger": "event",
"expectedHostOutcome": "failed",
"hostSurvives": true
},
{
"id": "wall-clock-timeout",
"mode": "loop",
"trigger": "event",
"expectedHostOutcome": "timed-out",
"hostSurvives": true
},
{
"id": "memory-limit",
"mode": "alloc",
"trigger": "start",
"expectedHostOutcome": "failed",
"hostSurvives": true
}
]
}
69 changes: 68 additions & 1 deletion crates/floatile-cli/src/conformance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ pub const LIFECYCLE_SUITE_JSON: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../conformance/sdk-lifecycle-v1.json"
));
pub const SECURITY_SUITE_JSON: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../conformance/sdk-security-v1.json"
));

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
Expand All @@ -30,13 +34,32 @@ pub struct LifecycleVector {
pub expected_host_outcome: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SecuritySuite {
pub schema_version: u32,
pub engine_api_version: String,
pub vectors: Vec<SecurityVector>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SecurityVector {
pub id: String,
pub mode: String,
pub trigger: String,
pub expected_host_outcome: String,
pub host_survives: bool,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ConformanceReport {
pub schema_version: u32,
pub status: &'static str,
pub suite: &'static str,
pub contract: LifecycleSuite,
pub security_contract: SecuritySuite,
pub warnings: Vec<crate::CommandWarning>,
}

Expand Down Expand Up @@ -64,15 +87,57 @@ pub fn lifecycle_report() -> Result<ConformanceReport, ConformanceError> {
let contract: LifecycleSuite =
serde_json::from_str(LIFECYCLE_SUITE_JSON).map_err(|_| ConformanceError::InvalidJson)?;
validate(&contract)?;
let security_contract: SecuritySuite =
serde_json::from_str(SECURITY_SUITE_JSON).map_err(|_| ConformanceError::InvalidJson)?;
validate_security(&security_contract)?;
if security_contract.engine_api_version != contract.engine_api_version {
return Err(ConformanceError::InvalidVector(
"conformance contracts 的 engineApiVersion 不一致".to_owned(),
));
}
Ok(ConformanceReport {
schema_version: OUTPUT_SCHEMA_VERSION,
status: "ok",
suite: "sdk-lifecycle-v1",
contract,
security_contract,
warnings: Vec::new(),
})
}

fn validate_security(suite: &SecuritySuite) -> Result<(), ConformanceError> {
if suite.schema_version != 1 {
return Err(ConformanceError::UnsupportedSchema(suite.schema_version));
}
let mut ids = BTreeSet::new();
for vector in &suite.vectors {
if !ids.insert(vector.id.as_str()) {
return Err(ConformanceError::InvalidVector(
"security vector id 重复".to_owned(),
));
}
if !matches!(vector.trigger.as_str(), "start" | "event") {
return Err(ConformanceError::InvalidVector(
"security trigger 不受支持".to_owned(),
));
}
if !matches!(
vector.expected_host_outcome.as_str(),
"completed" | "completed-without-state-update" | "failed" | "timed-out"
) {
return Err(ConformanceError::InvalidVector(
"security expectedHostOutcome 不受支持".to_owned(),
));
}
if !vector.host_survives {
return Err(ConformanceError::InvalidVector(
"security vector 必须要求 hostSurvives".to_owned(),
));
}
}
Ok(())
}

fn validate(suite: &LifecycleSuite) -> Result<(), ConformanceError> {
if suite.schema_version != 1 {
return Err(ConformanceError::UnsupportedSchema(suite.schema_version));
Expand Down Expand Up @@ -121,7 +186,9 @@ mod tests {
assert_eq!(report.suite, "sdk-lifecycle-v1");
assert_eq!(report.contract.schema_version, 1);
assert_eq!(report.contract.engine_api_version, "1.2.0");
assert_eq!(report.contract.vectors.len(), 3);
assert_eq!(report.contract.vectors.len(), 6);
assert_eq!(report.security_contract.schema_version, 1);
assert_eq!(report.security_contract.vectors.len(), 5);
Ok(())
}
}
4 changes: 3 additions & 1 deletion crates/floatile-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod dev;
pub mod inspect;
pub mod install;
pub mod instance;
pub mod migrate;
pub mod output;
pub mod package;
pub mod preview;
Expand All @@ -31,11 +32,12 @@ pub use instance::{
InstanceCommandError, InstanceView, configure_instance, create_instance, delete_instance,
get_instance, list_instances, rollback_instance, set_instance_desired_state,
};
pub use migrate::{MigrationError, MigrationReport, migrate_project};
pub use output::{CommandErrorReport, CommandWarning, OUTPUT_SCHEMA_VERSION};
pub use package::{PackageError, PackageLimits, ValidatedPackage, validate_package};
pub use preview::{PreviewError, PreviewReport, PreviewSession, preview_project};
pub use project::{
ProjectConfig, ProjectError, generate_manifest, generate_template, parse_floatile_toml,
ProjectConfig, ProjectError, SdkCfg, generate_manifest, generate_template, parse_floatile_toml,
};
pub use run::{RunError, RunReport, default_run_paths, run_project};
pub use test::{
Expand Down
Loading