@feltdb/core 0.4.11 → 0.4.13
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.
- package/dist/cli/commands.js +5 -2
- package/dist/cli/index.js +1 -1
- package/dist/create/cli.js +16 -1
- package/dist/create/create.js +30 -16
- package/dist/create/docker-compose-generator.js +48 -9
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +2238 -0
- package/dist/create/server-source/Cargo.toml +7 -0
- package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
- package/dist/flowspec.d.ts +2 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +28 -4
- package/dist/state-contract.d.ts +7 -1
- package/dist/state-contract.d.ts.map +1 -1
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
- package/dist/studio/index.js +31 -28
- package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
- package/dist/studio-app/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1086 @@
|
|
|
1
|
+
use feltdb::FeltDb;
|
|
2
|
+
use serde_json::Value;
|
|
3
|
+
use std::sync::Arc;
|
|
4
|
+
use wasm_bindgen::prelude::*;
|
|
5
|
+
|
|
6
|
+
/// Canonicalizes a typed application manifest using the same Rust implementation
|
|
7
|
+
/// used by the server. JavaScript never defines revision identity independently.
|
|
8
|
+
#[wasm_bindgen]
|
|
9
|
+
pub fn canonicalize_application_manifest(input: &str) -> std::result::Result<String, JsValue> {
|
|
10
|
+
let manifest: feltdb::application::ApplicationManifest =
|
|
11
|
+
serde_json::from_str(input).map_err(|error| JsValue::from_str(&error.to_string()))?;
|
|
12
|
+
let bytes = feltdb::application::canonical_bytes(&manifest)
|
|
13
|
+
.map_err(|error| JsValue::from_str(&error))?;
|
|
14
|
+
String::from_utf8(bytes).map_err(|error| JsValue::from_str(&error.to_string()))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[wasm_bindgen]
|
|
18
|
+
pub fn hash_application_manifest(input: &str) -> std::result::Result<String, JsValue> {
|
|
19
|
+
let manifest: feltdb::application::ApplicationManifest =
|
|
20
|
+
serde_json::from_str(input).map_err(|error| JsValue::from_str(&error.to_string()))?;
|
|
21
|
+
feltdb::application::manifest_hash(&manifest).map_err(|error| JsValue::from_str(&error))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[wasm_bindgen]
|
|
25
|
+
pub fn resolve_application_runtime(
|
|
26
|
+
revision: &str,
|
|
27
|
+
environment: &str,
|
|
28
|
+
) -> std::result::Result<String, JsValue> {
|
|
29
|
+
let revision: feltdb::application::ApplicationRevision =
|
|
30
|
+
serde_json::from_str(revision).map_err(|error| JsValue::from_str(&error.to_string()))?;
|
|
31
|
+
let contract =
|
|
32
|
+
feltdb::application_runtime::resolve_runtime(&revision, environment, &Default::default())
|
|
33
|
+
.map_err(|report| {
|
|
34
|
+
JsValue::from_str(
|
|
35
|
+
&serde_json::to_string(&report)
|
|
36
|
+
.unwrap_or_else(|_| "runtime resolution failed".into()),
|
|
37
|
+
)
|
|
38
|
+
})?;
|
|
39
|
+
serde_json::to_string(&contract).map_err(|error| JsValue::from_str(&error.to_string()))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[wasm_bindgen]
|
|
43
|
+
pub fn hash_application_runtime(
|
|
44
|
+
revision: &str,
|
|
45
|
+
environment: &str,
|
|
46
|
+
) -> std::result::Result<String, JsValue> {
|
|
47
|
+
let revision: feltdb::application::ApplicationRevision =
|
|
48
|
+
serde_json::from_str(revision).map_err(|error| JsValue::from_str(&error.to_string()))?;
|
|
49
|
+
let contract =
|
|
50
|
+
feltdb::application_runtime::resolve_runtime(&revision, environment, &Default::default())
|
|
51
|
+
.map_err(|report| {
|
|
52
|
+
JsValue::from_str(
|
|
53
|
+
&serde_json::to_string(&report)
|
|
54
|
+
.unwrap_or_else(|_| "runtime resolution failed".into()),
|
|
55
|
+
)
|
|
56
|
+
})?;
|
|
57
|
+
feltdb::application_runtime::runtime_hash(&contract).map_err(|error| JsValue::from_str(&error))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[wasm_bindgen]
|
|
61
|
+
pub fn diff_application_revisions(
|
|
62
|
+
from: Option<String>,
|
|
63
|
+
to: &str,
|
|
64
|
+
) -> std::result::Result<String, JsValue> {
|
|
65
|
+
let before = from
|
|
66
|
+
.as_deref()
|
|
67
|
+
.map(serde_json::from_str::<feltdb::application::ApplicationRevision>)
|
|
68
|
+
.transpose()
|
|
69
|
+
.map_err(|error| JsValue::from_str(&error.to_string()))?;
|
|
70
|
+
let after: feltdb::application::ApplicationRevision =
|
|
71
|
+
serde_json::from_str(to).map_err(|error| JsValue::from_str(&error.to_string()))?;
|
|
72
|
+
let diff = feltdb::application::application_revision_diff(before.as_ref(), &after)
|
|
73
|
+
.map_err(|error| JsValue::from_str(&error))?;
|
|
74
|
+
serde_json::to_string(&diff).map_err(|error| JsValue::from_str(&error.to_string()))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[wasm_bindgen]
|
|
78
|
+
pub fn validate_state_schema(schema: &str) -> std::result::Result<String, JsValue> {
|
|
79
|
+
let schema: feltdb::state_contract::StateSchema =
|
|
80
|
+
serde_json::from_str(schema).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
81
|
+
serde_json::to_string(&feltdb::state_contract::validate_schema(&schema))
|
|
82
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))
|
|
83
|
+
}
|
|
84
|
+
#[wasm_bindgen]
|
|
85
|
+
pub fn hash_state_schema(schema: &str) -> std::result::Result<String, JsValue> {
|
|
86
|
+
let schema: feltdb::state_contract::StateSchema =
|
|
87
|
+
serde_json::from_str(schema).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
88
|
+
feltdb::state_contract::schema_hash(&schema).map_err(|e| JsValue::from_str(&e))
|
|
89
|
+
}
|
|
90
|
+
#[wasm_bindgen]
|
|
91
|
+
pub fn compare_state_schemas(before: &str, after: &str) -> std::result::Result<String, JsValue> {
|
|
92
|
+
let before: feltdb::state_contract::StateSchema =
|
|
93
|
+
serde_json::from_str(before).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
94
|
+
let after: feltdb::state_contract::StateSchema =
|
|
95
|
+
serde_json::from_str(after).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
96
|
+
serde_json::to_string(&feltdb::state_contract::compare_schemas(&before, &after))
|
|
97
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Verify a portable signed grant with the exact Rust canonicalization used by
|
|
101
|
+
/// the server. The verification key is provisioned with the offline app shell.
|
|
102
|
+
#[wasm_bindgen]
|
|
103
|
+
pub fn verify_signed_grant(
|
|
104
|
+
signed_grant: &str,
|
|
105
|
+
key_id: &str,
|
|
106
|
+
verification_key: &str,
|
|
107
|
+
request: &str,
|
|
108
|
+
grant_chain: &str,
|
|
109
|
+
revocations: &str,
|
|
110
|
+
) -> std::result::Result<String, JsValue> {
|
|
111
|
+
use feltdb::authorization::{AuthorizationRequest, GrantSigner, RevocationState, SignedGrant};
|
|
112
|
+
use std::collections::BTreeMap;
|
|
113
|
+
let signed: SignedGrant =
|
|
114
|
+
serde_json::from_str(signed_grant).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
115
|
+
let request: AuthorizationRequest =
|
|
116
|
+
serde_json::from_str(request).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
117
|
+
let grants: BTreeMap<String, SignedGrant> =
|
|
118
|
+
serde_json::from_str(grant_chain).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
119
|
+
let revoked: RevocationState =
|
|
120
|
+
serde_json::from_str(revocations).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
121
|
+
let signer = GrantSigner::verifier_hex(key_id, verification_key)
|
|
122
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
123
|
+
feltdb::authorization::verify_grant(&signed, &signer, &request, &grants, &revoked).map_err(
|
|
124
|
+
|e| JsValue::from_str(&serde_json::to_string(&e).unwrap_or_else(|_| e.to_string())),
|
|
125
|
+
)?;
|
|
126
|
+
Ok(signed
|
|
127
|
+
.grant
|
|
128
|
+
.digest()
|
|
129
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#[wasm_bindgen]
|
|
133
|
+
pub fn authorize_offline(
|
|
134
|
+
signed_grant: &str,
|
|
135
|
+
key_id: &str,
|
|
136
|
+
verification_key: &str,
|
|
137
|
+
request: &str,
|
|
138
|
+
grant_chain: &str,
|
|
139
|
+
revocations: &str,
|
|
140
|
+
) -> std::result::Result<String, JsValue> {
|
|
141
|
+
use feltdb::authorization::{AuthorizationRequest, GrantSigner, RevocationState, SignedGrant};
|
|
142
|
+
use std::collections::BTreeMap;
|
|
143
|
+
let signed: SignedGrant =
|
|
144
|
+
serde_json::from_str(signed_grant).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
145
|
+
let request: AuthorizationRequest =
|
|
146
|
+
serde_json::from_str(request).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
147
|
+
let grants: BTreeMap<String, SignedGrant> =
|
|
148
|
+
serde_json::from_str(grant_chain).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
149
|
+
let revoked: RevocationState =
|
|
150
|
+
serde_json::from_str(revocations).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
151
|
+
let signer = GrantSigner::verifier_hex(key_id, verification_key)
|
|
152
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
153
|
+
serde_json::to_string(&feltdb::authorization::authorize(
|
|
154
|
+
&request,
|
|
155
|
+
Some(&signed),
|
|
156
|
+
&signer,
|
|
157
|
+
&grants,
|
|
158
|
+
&revoked,
|
|
159
|
+
))
|
|
160
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#[wasm_bindgen]
|
|
164
|
+
pub fn validate_sync_operation(operation: &str) -> std::result::Result<String, JsValue> {
|
|
165
|
+
let operation: feltdb::sync_contract::SyncOperation =
|
|
166
|
+
serde_json::from_str(operation).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
167
|
+
operation.validate_identity().map_err(|e| {
|
|
168
|
+
JsValue::from_str(&serde_json::to_string(&e).unwrap_or_else(|_| e.to_string()))
|
|
169
|
+
})?;
|
|
170
|
+
Ok(operation.hash())
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[wasm_bindgen]
|
|
174
|
+
pub fn apply_sync_result(
|
|
175
|
+
local_runtime: &str,
|
|
176
|
+
result: &str,
|
|
177
|
+
) -> std::result::Result<String, JsValue> {
|
|
178
|
+
use feltdb::sync_contract::{OutboxStatus, SyncResult};
|
|
179
|
+
use std::collections::BTreeMap;
|
|
180
|
+
let mut outbox: BTreeMap<String, OutboxStatus> =
|
|
181
|
+
serde_json::from_str(local_runtime).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
182
|
+
let result: SyncResult =
|
|
183
|
+
serde_json::from_str(result).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
184
|
+
for ack in result.acknowledgements {
|
|
185
|
+
outbox.insert(ack.operation_id, OutboxStatus::Acknowledged);
|
|
186
|
+
}
|
|
187
|
+
for rejection in result.rejections {
|
|
188
|
+
outbox.insert(
|
|
189
|
+
rejection.operation_id,
|
|
190
|
+
if rejection.retryable {
|
|
191
|
+
OutboxStatus::Retryable
|
|
192
|
+
} else {
|
|
193
|
+
OutboxStatus::Rejected
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
for conflict in result.conflicts {
|
|
198
|
+
outbox.insert(conflict.operation_id, OutboxStatus::Conflicted);
|
|
199
|
+
}
|
|
200
|
+
serde_json::to_string(&outbox).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#[wasm_bindgen]
|
|
204
|
+
pub fn validate_workload_transition(from: &str, to: &str) -> std::result::Result<bool, JsValue> {
|
|
205
|
+
let from: feltdb::workload::WorkloadState = serde_json::from_str(&format!("\"{from}\""))
|
|
206
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
207
|
+
let to: feltdb::workload::WorkloadState = serde_json::from_str(&format!("\"{to}\""))
|
|
208
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
209
|
+
Ok(feltdb::workload::can_transition(from, to))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#[wasm_bindgen]
|
|
213
|
+
pub fn validate_worker_transition(from: &str, to: &str) -> std::result::Result<bool, JsValue> {
|
|
214
|
+
let from: feltdb::worker_mesh::WorkerLifecycle =
|
|
215
|
+
serde_json::from_str(&format!("\"{from}\""))
|
|
216
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
217
|
+
let to: feltdb::worker_mesh::WorkerLifecycle = serde_json::from_str(&format!("\"{to}\""))
|
|
218
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
219
|
+
Ok(feltdb::worker_mesh::worker_transition(from, to))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
#[wasm_bindgen]
|
|
223
|
+
pub fn validate_mesh_claim(
|
|
224
|
+
claim: &str,
|
|
225
|
+
worker: &str,
|
|
226
|
+
workload: &str,
|
|
227
|
+
now: i64,
|
|
228
|
+
) -> std::result::Result<(), JsValue> {
|
|
229
|
+
let claim: feltdb::worker_mesh::MeshExecutionClaim =
|
|
230
|
+
serde_json::from_str(claim).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
231
|
+
let worker: feltdb::worker_mesh::Worker =
|
|
232
|
+
serde_json::from_str(worker).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
233
|
+
let workload: feltdb::workload::Workload =
|
|
234
|
+
serde_json::from_str(workload).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
235
|
+
feltdb::worker_mesh::validate_mesh_claim(&claim, &worker, &workload, now).map_err(|e| {
|
|
236
|
+
JsValue::from_str(&serde_json::to_string(&e).unwrap_or_else(|_| e.to_string()))
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/// Wrapper around FeltDb for JavaScript interop
|
|
241
|
+
#[wasm_bindgen]
|
|
242
|
+
pub struct JsDb {
|
|
243
|
+
db: Arc<FeltDb>,
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/// Result type for WASM operations
|
|
247
|
+
#[wasm_bindgen]
|
|
248
|
+
pub struct JsResult {
|
|
249
|
+
success: bool,
|
|
250
|
+
data: Option<String>,
|
|
251
|
+
error: Option<String>,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
#[wasm_bindgen]
|
|
255
|
+
impl JsResult {
|
|
256
|
+
#[wasm_bindgen(getter)]
|
|
257
|
+
pub fn success(&self) -> bool {
|
|
258
|
+
self.success
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#[wasm_bindgen(getter)]
|
|
262
|
+
pub fn data(&self) -> Option<String> {
|
|
263
|
+
self.data.clone()
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#[wasm_bindgen(getter)]
|
|
267
|
+
pub fn error(&self) -> Option<String> {
|
|
268
|
+
self.error.clone()
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
fn feltdb_error_to_js(err: feltdb::FlowError) -> JsValue {
|
|
273
|
+
JsValue::from_str(&format!("FeltDB error: {}", err))
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/// Opens or creates a FeltDB database
|
|
277
|
+
///
|
|
278
|
+
/// # Arguments
|
|
279
|
+
/// * `path` - Path to the database file
|
|
280
|
+
///
|
|
281
|
+
/// # Returns
|
|
282
|
+
/// JsDb instance or error
|
|
283
|
+
#[wasm_bindgen]
|
|
284
|
+
pub fn open(path: &str) -> std::result::Result<JsDb, JsValue> {
|
|
285
|
+
let db = FeltDb::open(path).map_err(feltdb_error_to_js)?;
|
|
286
|
+
Ok(JsDb { db: Arc::new(db) })
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
#[wasm_bindgen]
|
|
290
|
+
impl JsDb {
|
|
291
|
+
pub fn execute_canonical_query(
|
|
292
|
+
&self,
|
|
293
|
+
schema: &str,
|
|
294
|
+
authorization: &str,
|
|
295
|
+
state_namespace: &str,
|
|
296
|
+
query: &str,
|
|
297
|
+
) -> JsResult {
|
|
298
|
+
let result = (|| {
|
|
299
|
+
let schema: feltdb::state_contract::StateSchema =
|
|
300
|
+
serde_json::from_str(schema).map_err(|e| e.to_string())?;
|
|
301
|
+
let authorization: feltdb::state_contract::AuthorizationContext =
|
|
302
|
+
serde_json::from_str(authorization).map_err(|e| e.to_string())?;
|
|
303
|
+
let query: feltdb::state_contract::CanonicalQuery =
|
|
304
|
+
serde_json::from_str(query).map_err(|e| e.to_string())?;
|
|
305
|
+
let context = feltdb::state_contract::begin_read(
|
|
306
|
+
&self.db,
|
|
307
|
+
&schema,
|
|
308
|
+
state_namespace,
|
|
309
|
+
authorization,
|
|
310
|
+
)
|
|
311
|
+
.map_err(|e| serde_json::to_string(&e).unwrap_or(e.message))?;
|
|
312
|
+
feltdb::state_contract::execute_query(&self.db, &schema, &context, &query)
|
|
313
|
+
.map_err(|e| serde_json::to_string(&e).unwrap_or(e.message))
|
|
314
|
+
})()
|
|
315
|
+
.and_then(|v| serde_json::to_string(&v).map_err(|e| e.to_string()));
|
|
316
|
+
match result {
|
|
317
|
+
Ok(data) => JsResult {
|
|
318
|
+
success: true,
|
|
319
|
+
data: Some(data),
|
|
320
|
+
error: None,
|
|
321
|
+
},
|
|
322
|
+
Err(error) => JsResult {
|
|
323
|
+
success: false,
|
|
324
|
+
data: None,
|
|
325
|
+
error: Some(error),
|
|
326
|
+
},
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
pub fn execute_canonical_transaction(&self, schema: &str, request: &str) -> JsResult {
|
|
330
|
+
let result = (|| {
|
|
331
|
+
let schema: feltdb::state_contract::StateSchema =
|
|
332
|
+
serde_json::from_str(schema).map_err(|e| e.to_string())?;
|
|
333
|
+
let request: feltdb::state_contract::TransactionRequest =
|
|
334
|
+
serde_json::from_str(request).map_err(|e| e.to_string())?;
|
|
335
|
+
feltdb::state_contract::execute_transaction(&self.db, &schema, &request)
|
|
336
|
+
.map_err(|e| serde_json::to_string(&e).unwrap_or(e.message))
|
|
337
|
+
})()
|
|
338
|
+
.and_then(|v| serde_json::to_string(&v).map_err(|e| e.to_string()));
|
|
339
|
+
match result {
|
|
340
|
+
Ok(data) => JsResult {
|
|
341
|
+
success: true,
|
|
342
|
+
data: Some(data),
|
|
343
|
+
error: None,
|
|
344
|
+
},
|
|
345
|
+
Err(error) => JsResult {
|
|
346
|
+
success: false,
|
|
347
|
+
data: None,
|
|
348
|
+
error: Some(error),
|
|
349
|
+
},
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/// Insert a record into the database
|
|
353
|
+
///
|
|
354
|
+
/// # Arguments
|
|
355
|
+
/// * `key` - Key for the record (e.g., "users:123")
|
|
356
|
+
/// * `value` - JSON object as a string
|
|
357
|
+
///
|
|
358
|
+
/// # Returns
|
|
359
|
+
/// JsResult with success status
|
|
360
|
+
pub fn insert(&self, key: &str, value: &str) -> JsResult {
|
|
361
|
+
match serde_json::from_str::<Value>(value) {
|
|
362
|
+
Ok(json_value) => match self.db.insert(key, &json_value) {
|
|
363
|
+
Ok(_) => JsResult {
|
|
364
|
+
success: true,
|
|
365
|
+
data: Some(key.to_string()),
|
|
366
|
+
error: None,
|
|
367
|
+
},
|
|
368
|
+
Err(e) => JsResult {
|
|
369
|
+
success: false,
|
|
370
|
+
data: None,
|
|
371
|
+
error: Some(format!("Insert failed: {}", e)),
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
Err(e) => JsResult {
|
|
375
|
+
success: false,
|
|
376
|
+
data: None,
|
|
377
|
+
error: Some(format!("Invalid JSON: {}", e)),
|
|
378
|
+
},
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/// Update an existing record through the canonical update operation.
|
|
383
|
+
pub fn update(&self, key: &str, value: &str) -> JsResult {
|
|
384
|
+
match serde_json::from_str::<Value>(value) {
|
|
385
|
+
Ok(json_value) => match self.db.update(key, &json_value) {
|
|
386
|
+
Ok(_) => JsResult {
|
|
387
|
+
success: true,
|
|
388
|
+
data: Some(key.to_string()),
|
|
389
|
+
error: None,
|
|
390
|
+
},
|
|
391
|
+
Err(e) => JsResult {
|
|
392
|
+
success: false,
|
|
393
|
+
data: None,
|
|
394
|
+
error: Some(format!("Update failed: {}", e)),
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
Err(e) => JsResult {
|
|
398
|
+
success: false,
|
|
399
|
+
data: None,
|
|
400
|
+
error: Some(format!("Invalid JSON: {}", e)),
|
|
401
|
+
},
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/// Delete a record from the database.
|
|
406
|
+
pub fn delete(&self, key: &str) -> JsResult {
|
|
407
|
+
match self.db.delete(key) {
|
|
408
|
+
Ok(_) => JsResult {
|
|
409
|
+
success: true,
|
|
410
|
+
data: Some(key.to_string()),
|
|
411
|
+
error: None,
|
|
412
|
+
},
|
|
413
|
+
Err(e) => JsResult {
|
|
414
|
+
success: false,
|
|
415
|
+
data: None,
|
|
416
|
+
error: Some(format!("Delete failed: {}", e)),
|
|
417
|
+
},
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/// Retrieve a record from the database
|
|
422
|
+
///
|
|
423
|
+
/// # Arguments
|
|
424
|
+
/// * `key` - Key for the record
|
|
425
|
+
///
|
|
426
|
+
/// # Returns
|
|
427
|
+
/// JSON string of the record or error
|
|
428
|
+
pub fn get(&self, key: &str) -> JsResult {
|
|
429
|
+
match self.db.get::<Value>(key) {
|
|
430
|
+
Ok(Some(value)) => JsResult {
|
|
431
|
+
success: true,
|
|
432
|
+
data: Some(value.to_string()),
|
|
433
|
+
error: None,
|
|
434
|
+
},
|
|
435
|
+
Ok(None) => JsResult {
|
|
436
|
+
success: true,
|
|
437
|
+
data: None,
|
|
438
|
+
error: None,
|
|
439
|
+
},
|
|
440
|
+
Err(e) => JsResult {
|
|
441
|
+
success: false,
|
|
442
|
+
data: None,
|
|
443
|
+
error: Some(format!("Get failed: {}", e)),
|
|
444
|
+
},
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/// Query records in the database with a predicate
|
|
449
|
+
///
|
|
450
|
+
/// For now, this returns all records of a given type namespace as a simplified implementation.
|
|
451
|
+
/// The full closure-based predicate from Rust cannot be directly represented in WASM bindings.
|
|
452
|
+
///
|
|
453
|
+
/// # Arguments
|
|
454
|
+
/// * `capability` - Capability/namespace to query (e.g., "users")
|
|
455
|
+
///
|
|
456
|
+
/// # Returns
|
|
457
|
+
/// JSON array string of matching records
|
|
458
|
+
pub fn query(&self, capability: &str) -> JsResult {
|
|
459
|
+
// Get the capability and find all records in it
|
|
460
|
+
let cap = self.db.capability(capability);
|
|
461
|
+
match cap.find::<Value, _>(|_| true) {
|
|
462
|
+
Ok(values) => {
|
|
463
|
+
let json_array = Value::Array(values);
|
|
464
|
+
JsResult {
|
|
465
|
+
success: true,
|
|
466
|
+
data: Some(json_array.to_string()),
|
|
467
|
+
error: None,
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
Err(e) => JsResult {
|
|
471
|
+
success: false,
|
|
472
|
+
data: None,
|
|
473
|
+
error: Some(format!("Query failed: {}", e)),
|
|
474
|
+
},
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/// Get all records in a capability namespace
|
|
479
|
+
///
|
|
480
|
+
/// # Arguments
|
|
481
|
+
/// * `capability` - Capability/namespace name
|
|
482
|
+
///
|
|
483
|
+
/// # Returns
|
|
484
|
+
/// JSON array string of all records in the capability
|
|
485
|
+
pub fn get_capability_records(&self, capability: &str) -> JsResult {
|
|
486
|
+
let cap = self.db.capability(capability);
|
|
487
|
+
match cap.find::<Value, _>(|_| true) {
|
|
488
|
+
Ok(values) => {
|
|
489
|
+
let json_array = Value::Array(values);
|
|
490
|
+
JsResult {
|
|
491
|
+
success: true,
|
|
492
|
+
data: Some(json_array.to_string()),
|
|
493
|
+
error: None,
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
Err(e) => JsResult {
|
|
497
|
+
success: false,
|
|
498
|
+
data: None,
|
|
499
|
+
error: Some(format!("Get capability records failed: {}", e)),
|
|
500
|
+
},
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/// Check if a type is auto-indexed
|
|
505
|
+
///
|
|
506
|
+
/// # Returns
|
|
507
|
+
/// Whether the default (generic JSON) type is auto-indexed
|
|
508
|
+
pub fn is_auto_indexed(&self) -> bool {
|
|
509
|
+
self.db.is_auto_indexed::<Value>()
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/// Get current sync state information
|
|
513
|
+
///
|
|
514
|
+
/// # Returns
|
|
515
|
+
/// JSON string containing sync state metrics
|
|
516
|
+
pub fn sync_info(&self) -> JsResult {
|
|
517
|
+
match self.db.sync_info() {
|
|
518
|
+
Ok(sync_state) => match serde_json::to_string(&sync_state) {
|
|
519
|
+
Ok(json) => JsResult {
|
|
520
|
+
success: true,
|
|
521
|
+
data: Some(json),
|
|
522
|
+
error: None,
|
|
523
|
+
},
|
|
524
|
+
Err(e) => JsResult {
|
|
525
|
+
success: false,
|
|
526
|
+
data: None,
|
|
527
|
+
error: Some(format!("Serialization failed: {}", e)),
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
Err(e) => JsResult {
|
|
531
|
+
success: false,
|
|
532
|
+
data: None,
|
|
533
|
+
error: Some(format!("Sync info failed: {}", e)),
|
|
534
|
+
},
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/// Add a peer for synchronization
|
|
539
|
+
///
|
|
540
|
+
/// # Arguments
|
|
541
|
+
/// * `peer_id` - Unique identifier for the peer
|
|
542
|
+
///
|
|
543
|
+
/// # Returns
|
|
544
|
+
/// JsResult with success status
|
|
545
|
+
pub fn add_sync_peer(&self, peer_id: &str) -> JsResult {
|
|
546
|
+
match self.db.add_sync_peer(peer_id.to_string()) {
|
|
547
|
+
Ok(_) => JsResult {
|
|
548
|
+
success: true,
|
|
549
|
+
data: Some(format!("Added peer: {}", peer_id)),
|
|
550
|
+
error: None,
|
|
551
|
+
},
|
|
552
|
+
Err(e) => JsResult {
|
|
553
|
+
success: false,
|
|
554
|
+
data: None,
|
|
555
|
+
error: Some(format!("Add peer failed: {}", e)),
|
|
556
|
+
},
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/// Remove a peer from synchronization
|
|
561
|
+
///
|
|
562
|
+
/// # Arguments
|
|
563
|
+
/// * `peer_id` - Unique identifier for the peer
|
|
564
|
+
///
|
|
565
|
+
/// # Returns
|
|
566
|
+
/// JsResult with success status
|
|
567
|
+
pub fn remove_sync_peer(&self, peer_id: &str) -> JsResult {
|
|
568
|
+
match self.db.remove_sync_peer(peer_id) {
|
|
569
|
+
Ok(_) => JsResult {
|
|
570
|
+
success: true,
|
|
571
|
+
data: Some(format!("Removed peer: {}", peer_id)),
|
|
572
|
+
error: None,
|
|
573
|
+
},
|
|
574
|
+
Err(e) => JsResult {
|
|
575
|
+
success: false,
|
|
576
|
+
data: None,
|
|
577
|
+
error: Some(format!("Remove peer failed: {}", e)),
|
|
578
|
+
},
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/// Get pending operations for a peer since a given sequence
|
|
583
|
+
///
|
|
584
|
+
/// # Arguments
|
|
585
|
+
/// * `peer_id` - Unique identifier for the peer
|
|
586
|
+
/// * `since_sequence` - Get operations after this sequence number
|
|
587
|
+
///
|
|
588
|
+
/// # Returns
|
|
589
|
+
/// JSON array of operations as a string
|
|
590
|
+
pub fn get_pending_for_peer(&self, peer_id: &str, since_sequence: u64) -> JsResult {
|
|
591
|
+
match self.db.get_pending_for_peer(peer_id, since_sequence) {
|
|
592
|
+
Ok(operations) => match serde_json::to_string(&operations) {
|
|
593
|
+
Ok(json) => JsResult {
|
|
594
|
+
success: true,
|
|
595
|
+
data: Some(json),
|
|
596
|
+
error: None,
|
|
597
|
+
},
|
|
598
|
+
Err(e) => JsResult {
|
|
599
|
+
success: false,
|
|
600
|
+
data: None,
|
|
601
|
+
error: Some(format!("Serialization failed: {}", e)),
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
Err(e) => JsResult {
|
|
605
|
+
success: false,
|
|
606
|
+
data: None,
|
|
607
|
+
error: Some(format!("Get pending failed: {}", e)),
|
|
608
|
+
},
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/// Acknowledge receipt of operations from a peer
|
|
613
|
+
///
|
|
614
|
+
/// # Arguments
|
|
615
|
+
/// * `peer_id` - Unique identifier for the peer
|
|
616
|
+
/// * `sequence` - Acknowledge operations up to this sequence number
|
|
617
|
+
///
|
|
618
|
+
/// # Returns
|
|
619
|
+
/// JsResult with success status
|
|
620
|
+
pub fn acknowledge_peer_operations(&self, peer_id: &str, sequence: u64) -> JsResult {
|
|
621
|
+
match self
|
|
622
|
+
.db
|
|
623
|
+
.acknowledge_peer_operations(peer_id.to_string(), sequence)
|
|
624
|
+
{
|
|
625
|
+
Ok(_) => JsResult {
|
|
626
|
+
success: true,
|
|
627
|
+
data: Some(format!("Acknowledged sequence {}", sequence)),
|
|
628
|
+
error: None,
|
|
629
|
+
},
|
|
630
|
+
Err(e) => JsResult {
|
|
631
|
+
success: false,
|
|
632
|
+
data: None,
|
|
633
|
+
error: Some(format!("Acknowledgement failed: {}", e)),
|
|
634
|
+
},
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/// Get the instance ID for this FeltDB instance
|
|
639
|
+
///
|
|
640
|
+
/// # Returns
|
|
641
|
+
/// The unique instance ID as a string
|
|
642
|
+
pub fn instance_id(&self) -> String {
|
|
643
|
+
self.db
|
|
644
|
+
.instance_id()
|
|
645
|
+
.unwrap_or_else(|_| "unknown".to_string())
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/// Get the current sequence number for this instance
|
|
649
|
+
///
|
|
650
|
+
/// # Returns
|
|
651
|
+
/// The current sequence number
|
|
652
|
+
pub fn get_sequence(&self) -> u64 {
|
|
653
|
+
self.db.sequence().unwrap_or(0)
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Note: Live queries require async/await support which requires special handling in WASM.
|
|
658
|
+
// For now, the synchronous query methods above are sufficient for frontend integration.
|
|
659
|
+
// Live query subscriptions can be added using a message-passing pattern or WebWorkers.
|
|
660
|
+
|
|
661
|
+
#[wasm_bindgen]
|
|
662
|
+
extern "C" {
|
|
663
|
+
#[wasm_bindgen(js_namespace = console)]
|
|
664
|
+
fn log(s: &str);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
fn canonical_json(value: &serde_json::Value) -> serde_json::Value {
|
|
668
|
+
match value {
|
|
669
|
+
serde_json::Value::Object(map) => serde_json::Value::Object(
|
|
670
|
+
map.iter()
|
|
671
|
+
.map(|(k, v)| (k.clone(), canonical_json(v)))
|
|
672
|
+
.collect::<std::collections::BTreeMap<_, _>>()
|
|
673
|
+
.into_iter()
|
|
674
|
+
.collect(),
|
|
675
|
+
),
|
|
676
|
+
serde_json::Value::Array(values) => {
|
|
677
|
+
serde_json::Value::Array(values.iter().map(canonical_json).collect())
|
|
678
|
+
}
|
|
679
|
+
value => value.clone(),
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
#[wasm_bindgen]
|
|
683
|
+
pub fn canonical_bundle_hash(bundle_json: &str) -> Result<String, JsValue> {
|
|
684
|
+
use sha2::{Digest, Sha256};
|
|
685
|
+
let value: serde_json::Value =
|
|
686
|
+
serde_json::from_str(bundle_json).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
687
|
+
let bytes = serde_json::to_vec(&canonical_json(&value))
|
|
688
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
689
|
+
Ok(format!("sha256:{:x}", Sha256::digest(bytes)))
|
|
690
|
+
}
|
|
691
|
+
#[wasm_bindgen]
|
|
692
|
+
pub fn verify_bundle_integrity(bundle_json: &str) -> Result<bool, JsValue> {
|
|
693
|
+
use sha2::{Digest, Sha256};
|
|
694
|
+
let value: serde_json::Value =
|
|
695
|
+
serde_json::from_str(bundle_json).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
696
|
+
if value.get("format").and_then(|v| v.as_str()) != Some("feltdb-bundle/v1") {
|
|
697
|
+
return Ok(false);
|
|
698
|
+
}
|
|
699
|
+
let checksums = value
|
|
700
|
+
.get("checksums")
|
|
701
|
+
.ok_or_else(|| JsValue::from_str("checksums missing"))?;
|
|
702
|
+
let bytes = serde_json::to_vec(&canonical_json(checksums))
|
|
703
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
704
|
+
let root = format!("sha256:{:x}", Sha256::digest(bytes));
|
|
705
|
+
Ok(value
|
|
706
|
+
.pointer("/bundle/integrity_root")
|
|
707
|
+
.and_then(|v| v.as_str())
|
|
708
|
+
== Some(&root))
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/// High-performance index manager for collections.
|
|
712
|
+
/// Wraps Rust IndexManager for optimal query performance.
|
|
713
|
+
#[wasm_bindgen]
|
|
714
|
+
pub struct WasmIndexManager {
|
|
715
|
+
manager: feltdb::IndexManager,
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
#[wasm_bindgen]
|
|
719
|
+
impl WasmIndexManager {
|
|
720
|
+
#[wasm_bindgen(constructor)]
|
|
721
|
+
pub fn new() -> WasmIndexManager {
|
|
722
|
+
WasmIndexManager {
|
|
723
|
+
manager: feltdb::IndexManager::new(),
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/// Create a new index on the collection.
|
|
728
|
+
#[wasm_bindgen]
|
|
729
|
+
pub fn create_index(&mut self, config: &str) -> Result<(), JsValue> {
|
|
730
|
+
let index_config: feltdb::IndexConfig =
|
|
731
|
+
serde_json::from_str(config).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
732
|
+
self.manager.create_index(index_config)
|
|
733
|
+
.map_err(|e| JsValue::from_str(&e))
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/// Update a record's index entries.
|
|
737
|
+
#[wasm_bindgen]
|
|
738
|
+
pub fn update_record(
|
|
739
|
+
&mut self,
|
|
740
|
+
record_id: &str,
|
|
741
|
+
old_value: Option<String>,
|
|
742
|
+
new_value: &str,
|
|
743
|
+
) -> Result<(), JsValue> {
|
|
744
|
+
self.manager
|
|
745
|
+
.update_record(record_id, old_value.as_deref(), new_value)
|
|
746
|
+
.map_err(|e| JsValue::from_str(&e))
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/// Query an index.
|
|
750
|
+
#[wasm_bindgen]
|
|
751
|
+
pub fn query_index(
|
|
752
|
+
&mut self,
|
|
753
|
+
index_name: &str,
|
|
754
|
+
operator: &str,
|
|
755
|
+
value: &str,
|
|
756
|
+
) -> Result<String, JsValue> {
|
|
757
|
+
let results = self.manager
|
|
758
|
+
.query_index(index_name, operator, value)
|
|
759
|
+
.map_err(|e| JsValue::from_str(&e))?;
|
|
760
|
+
serde_json::to_string(&results).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/// List all indexes.
|
|
764
|
+
#[wasm_bindgen]
|
|
765
|
+
pub fn list_indexes(&self) -> Result<String, JsValue> {
|
|
766
|
+
let indexes = self.manager.list_indexes();
|
|
767
|
+
serde_json::to_string(&indexes).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/// Get statistics for an index.
|
|
771
|
+
#[wasm_bindgen]
|
|
772
|
+
pub fn get_stats(&self, name: &str) -> Result<String, JsValue> {
|
|
773
|
+
let stats = self.manager
|
|
774
|
+
.get_stats(name)
|
|
775
|
+
.ok_or_else(|| JsValue::from_str("Index not found"))?;
|
|
776
|
+
serde_json::to_string(&stats).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/// Shard manager for horizontal scaling.
|
|
781
|
+
/// Distributes data across shards and handles rebalancing.
|
|
782
|
+
#[wasm_bindgen]
|
|
783
|
+
pub struct WasmShardManager {
|
|
784
|
+
manager: feltdb::ShardManager,
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
#[wasm_bindgen]
|
|
788
|
+
impl WasmShardManager {
|
|
789
|
+
#[wasm_bindgen(constructor)]
|
|
790
|
+
pub fn new(shard_field: &str, strategy: &str) -> WasmShardManager {
|
|
791
|
+
let sharding_key = feltdb::ShardKey {
|
|
792
|
+
field: shard_field.to_string(),
|
|
793
|
+
hash_function: "xxhash".to_string(),
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
let strat = match strategy {
|
|
797
|
+
"range" => feltdb::ShardingStrategy::RangeBasedHash,
|
|
798
|
+
"modulo" => feltdb::ShardingStrategy::KeyModulo,
|
|
799
|
+
_ => feltdb::ShardingStrategy::ConsistentHash,
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
WasmShardManager {
|
|
803
|
+
manager: feltdb::ShardManager::new(sharding_key, strat),
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/// Initialize shards
|
|
808
|
+
#[wasm_bindgen]
|
|
809
|
+
pub fn initialize_shards(&mut self, shard_ids_json: &str) -> Result<(), JsValue> {
|
|
810
|
+
let shard_ids: Vec<String> = serde_json::from_str(shard_ids_json)
|
|
811
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
812
|
+
|
|
813
|
+
let shard_ids: Vec<_> = shard_ids
|
|
814
|
+
.into_iter()
|
|
815
|
+
.map(|id| feltdb::ShardId(id))
|
|
816
|
+
.collect();
|
|
817
|
+
|
|
818
|
+
self.manager
|
|
819
|
+
.initialize_shards(shard_ids, std::collections::HashMap::new());
|
|
820
|
+
Ok(())
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/// Get shard for a key
|
|
824
|
+
#[wasm_bindgen]
|
|
825
|
+
pub fn get_shard_for_key(&self, key: &str) -> Result<String, JsValue> {
|
|
826
|
+
let shard = self
|
|
827
|
+
.manager
|
|
828
|
+
.get_shard_for_key(key)
|
|
829
|
+
.ok_or_else(|| JsValue::from_str("No shard found for key"))?;
|
|
830
|
+
Ok(shard.shard_id.0.clone())
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/// Record a shard operation
|
|
834
|
+
#[wasm_bindgen]
|
|
835
|
+
pub fn record_shard_operation(
|
|
836
|
+
&mut self,
|
|
837
|
+
shard_id: &str,
|
|
838
|
+
operation: &str,
|
|
839
|
+
time_ms: f64,
|
|
840
|
+
records_affected: u32,
|
|
841
|
+
size_bytes: u64,
|
|
842
|
+
) {
|
|
843
|
+
self.manager.record_shard_operation(
|
|
844
|
+
&feltdb::ShardId(shard_id.to_string()),
|
|
845
|
+
operation,
|
|
846
|
+
time_ms,
|
|
847
|
+
records_affected as usize,
|
|
848
|
+
size_bytes,
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/// Get all shard metrics
|
|
853
|
+
#[wasm_bindgen]
|
|
854
|
+
pub fn get_all_metrics(&self) -> Result<String, JsValue> {
|
|
855
|
+
let metrics = self.manager.get_all_metrics();
|
|
856
|
+
serde_json::to_string(&metrics).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/// Detect hotspots
|
|
860
|
+
#[wasm_bindgen]
|
|
861
|
+
pub fn detect_hotspots(&self) -> Result<String, JsValue> {
|
|
862
|
+
let hotspots = self.manager.detect_hotspots();
|
|
863
|
+
serde_json::to_string(&hotspots).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/// Generate rebalance operations
|
|
867
|
+
#[wasm_bindgen]
|
|
868
|
+
pub fn generate_rebalance_ops(&self) -> Result<String, JsValue> {
|
|
869
|
+
let ops = self.manager.generate_rebalance_ops();
|
|
870
|
+
serde_json::to_string(&ops).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/// Get distribution summary
|
|
874
|
+
#[wasm_bindgen]
|
|
875
|
+
pub fn get_distribution_summary(&self) -> Result<String, JsValue> {
|
|
876
|
+
let summary = self.manager.get_distribution_summary();
|
|
877
|
+
serde_json::to_string(&summary).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/// Distributed index manager for multi-node synchronization.
|
|
882
|
+
/// Coordinates index replication, consistency, and conflict resolution.
|
|
883
|
+
#[wasm_bindgen]
|
|
884
|
+
pub struct WasmDistributedIndexManager {
|
|
885
|
+
manager: feltdb::DistributedIndexManager,
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
#[wasm_bindgen]
|
|
889
|
+
impl WasmDistributedIndexManager {
|
|
890
|
+
#[wasm_bindgen(constructor)]
|
|
891
|
+
pub fn new(peer_id: &str) -> WasmDistributedIndexManager {
|
|
892
|
+
WasmDistributedIndexManager {
|
|
893
|
+
manager: feltdb::DistributedIndexManager::new(peer_id.to_string()),
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/// Register a peer for replication
|
|
898
|
+
#[wasm_bindgen]
|
|
899
|
+
pub fn register_peer(&mut self, peer_id: &str) {
|
|
900
|
+
self.manager.register_peer(peer_id.to_string());
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/// Create a replicated index
|
|
904
|
+
#[wasm_bindgen]
|
|
905
|
+
pub fn create_replicated_index(
|
|
906
|
+
&mut self,
|
|
907
|
+
name: &str,
|
|
908
|
+
field: &str,
|
|
909
|
+
index_type: &str,
|
|
910
|
+
) -> Result<(), JsValue> {
|
|
911
|
+
self.manager
|
|
912
|
+
.create_replicated_index(name.to_string(), field.to_string(), index_type.to_string())
|
|
913
|
+
.map_err(|e| JsValue::from_str(&e))
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/// Get replication status for an index
|
|
917
|
+
#[wasm_bindgen]
|
|
918
|
+
pub fn get_replication_status(&self, index_name: &str) -> Result<String, JsValue> {
|
|
919
|
+
let status = self
|
|
920
|
+
.manager
|
|
921
|
+
.get_replication_status(index_name)
|
|
922
|
+
.ok_or_else(|| JsValue::from_str("Index not found"))?;
|
|
923
|
+
serde_json::to_string(&status).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/// Get list of peers needing replication for an index
|
|
927
|
+
#[wasm_bindgen]
|
|
928
|
+
pub fn get_replication_targets(&self, index_name: &str) -> Result<String, JsValue> {
|
|
929
|
+
let targets = self.manager.get_replication_targets(index_name);
|
|
930
|
+
serde_json::to_string(&targets).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/// Detect version conflicts
|
|
934
|
+
#[wasm_bindgen]
|
|
935
|
+
pub fn detect_conflicts(&self, index_name: &str) -> Result<String, JsValue> {
|
|
936
|
+
let conflicts = self.manager.detect_conflicts(index_name);
|
|
937
|
+
serde_json::to_string(&conflicts).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/// Merge concurrent versions
|
|
941
|
+
#[wasm_bindgen]
|
|
942
|
+
pub fn merge_versions(&mut self, index_name: &str) -> Result<(), JsValue> {
|
|
943
|
+
self.manager
|
|
944
|
+
.merge_versions(index_name)
|
|
945
|
+
.map_err(|e| JsValue::from_str(&e))
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/// Set peer reachability
|
|
949
|
+
#[wasm_bindgen]
|
|
950
|
+
pub fn set_peer_reachable(&mut self, peer_id: &str, reachable: bool) {
|
|
951
|
+
self.manager.set_peer_reachable(peer_id, reachable);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/// Get overall synchronization status
|
|
955
|
+
#[wasm_bindgen]
|
|
956
|
+
pub fn get_sync_status(&self) -> Result<String, JsValue> {
|
|
957
|
+
let status = self.manager.get_sync_status();
|
|
958
|
+
serde_json::to_string(&status).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/// High-performance analytics engine for index monitoring.
|
|
963
|
+
/// Tracks metrics, generates reports, and provides tuning recommendations.
|
|
964
|
+
#[wasm_bindgen]
|
|
965
|
+
pub struct WasmAnalytics {
|
|
966
|
+
analytics: feltdb::analytics::IndexAnalytics,
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
#[wasm_bindgen]
|
|
970
|
+
impl WasmAnalytics {
|
|
971
|
+
#[wasm_bindgen(constructor)]
|
|
972
|
+
pub fn new() -> WasmAnalytics {
|
|
973
|
+
WasmAnalytics {
|
|
974
|
+
analytics: feltdb::analytics::IndexAnalytics::new(),
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
/// Record an index usage event.
|
|
979
|
+
#[wasm_bindgen]
|
|
980
|
+
pub fn record_index_usage(&mut self, index_name: &str, operation: &str, time_ms: f64) {
|
|
981
|
+
self.analytics.record_index_usage(index_name, operation, time_ms);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/// Record a query execution with performance metrics.
|
|
985
|
+
#[wasm_bindgen]
|
|
986
|
+
pub fn record_query(
|
|
987
|
+
&mut self,
|
|
988
|
+
fields_json: &str,
|
|
989
|
+
operator: &str,
|
|
990
|
+
execution_time_ms: f64,
|
|
991
|
+
rows_scanned: u64,
|
|
992
|
+
result_count: u64,
|
|
993
|
+
index_used: Option<String>,
|
|
994
|
+
) -> Result<(), JsValue> {
|
|
995
|
+
let fields: Vec<String> = serde_json::from_str(fields_json)
|
|
996
|
+
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
|
997
|
+
self.analytics.record_query(
|
|
998
|
+
fields,
|
|
999
|
+
operator.to_string(),
|
|
1000
|
+
execution_time_ms,
|
|
1001
|
+
rows_scanned,
|
|
1002
|
+
result_count,
|
|
1003
|
+
index_used,
|
|
1004
|
+
);
|
|
1005
|
+
Ok(())
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/// Get metrics for a specific index.
|
|
1009
|
+
#[wasm_bindgen]
|
|
1010
|
+
pub fn get_index_metrics(&self, index_name: &str) -> Result<String, JsValue> {
|
|
1011
|
+
let metrics = self
|
|
1012
|
+
.analytics
|
|
1013
|
+
.get_index_metrics(index_name)
|
|
1014
|
+
.ok_or_else(|| JsValue::from_str("Index not found"))?;
|
|
1015
|
+
serde_json::to_string(&metrics).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/// Get metrics for all indexes.
|
|
1019
|
+
#[wasm_bindgen]
|
|
1020
|
+
pub fn get_all_metrics(&self) -> Result<String, JsValue> {
|
|
1021
|
+
let metrics = self.analytics.get_all_metrics();
|
|
1022
|
+
serde_json::to_string(&metrics).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/// Get slowest queries.
|
|
1026
|
+
#[wasm_bindgen]
|
|
1027
|
+
pub fn get_slowest_queries(&self, limit: usize) -> Result<String, JsValue> {
|
|
1028
|
+
let traces = self.analytics.get_slowest_queries(limit);
|
|
1029
|
+
serde_json::to_string(&traces).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/// Get most frequently accessed fields.
|
|
1033
|
+
#[wasm_bindgen]
|
|
1034
|
+
pub fn get_frequent_fields(&self, limit: usize) -> Result<String, JsValue> {
|
|
1035
|
+
let fields = self.analytics.get_frequent_fields(limit);
|
|
1036
|
+
serde_json::to_string(&fields).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/// Generate performance report for a collection.
|
|
1040
|
+
#[wasm_bindgen]
|
|
1041
|
+
pub fn generate_report(&self, collection_name: &str, period: &str) -> Result<String, JsValue> {
|
|
1042
|
+
let report = self.analytics.generate_report(collection_name, period);
|
|
1043
|
+
serde_json::to_string(&report).map_err(|e| JsValue::from_str(&e.to_string()))
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/// Reset all collected metrics.
|
|
1047
|
+
#[wasm_bindgen]
|
|
1048
|
+
pub fn reset(&mut self) {
|
|
1049
|
+
self.analytics.reset();
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
#[cfg(test)]
|
|
1054
|
+
mod tests {
|
|
1055
|
+
use super::*;
|
|
1056
|
+
use std::fs;
|
|
1057
|
+
|
|
1058
|
+
#[test]
|
|
1059
|
+
fn test_wasm_open() {
|
|
1060
|
+
let test_path = "test_wasm.db";
|
|
1061
|
+
let _db = open(test_path).expect("open should succeed");
|
|
1062
|
+
assert!(std::path::Path::new(test_path).exists());
|
|
1063
|
+
let _ = fs::remove_file(test_path);
|
|
1064
|
+
}
|
|
1065
|
+
#[test]
|
|
1066
|
+
fn wasm_schema_hash_uses_the_canonical_rust_contract() {
|
|
1067
|
+
let schema = feltdb::state_contract::StateSchema {
|
|
1068
|
+
contract_version: 1,
|
|
1069
|
+
schema_version: 2,
|
|
1070
|
+
application_id: "app".into(),
|
|
1071
|
+
revision_id: "rev".into(),
|
|
1072
|
+
collections: vec![],
|
|
1073
|
+
};
|
|
1074
|
+
let json = serde_json::to_string(&schema).unwrap();
|
|
1075
|
+
assert_eq!(
|
|
1076
|
+
hash_state_schema(&json).unwrap(),
|
|
1077
|
+
feltdb::state_contract::schema_hash(&schema).unwrap()
|
|
1078
|
+
);
|
|
1079
|
+
let validation = validate_state_schema(&json).unwrap();
|
|
1080
|
+
assert!(
|
|
1081
|
+
serde_json::from_str::<feltdb::state_contract::SchemaValidation>(&validation)
|
|
1082
|
+
.unwrap()
|
|
1083
|
+
.valid
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
}
|