@feltdb/core 0.8.0 → 0.8.1
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/application-development.d.ts +7 -2
- package/dist/application-development.d.ts.map +1 -1
- package/dist/application-development.js +7 -13
- package/dist/application-manifest.d.ts +1 -0
- package/dist/application-manifest.d.ts.map +1 -1
- package/dist/application-manifest.js +1 -1
- package/dist/application-understanding.d.ts +76 -0
- package/dist/application-understanding.d.ts.map +1 -0
- package/dist/application-understanding.js +282 -0
- package/dist/cli/ai-model-config.js +3 -3
- package/dist/cli/commands.js +131 -38
- package/dist/cli/proposal-client.js +5 -1
- package/dist/cli/publish-engine.js +1 -1
- package/dist/cli/repository-evidence.js +55 -0
- package/dist/cli/source-sync.js +190 -75
- package/dist/convergence.d.ts +55 -0
- package/dist/convergence.d.ts.map +1 -0
- package/dist/convergence.js +63 -0
- package/dist/create/managed-account.js +1 -0
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/crates/feltdb/src/application.rs +4 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +14 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +174 -24
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +8 -1
- package/dist/create/template/default-project/src/context/AuthContext.tsx +9 -1
- package/dist/create/template/default-project/src/pages/SignUp.tsx +1 -1
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +6 -1
- package/dist/http-client.d.ts +32 -1
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +14 -2
- package/dist/http-db.d.ts +3 -0
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +28 -3
- package/dist/index-core.d.ts +3 -0
- package/dist/index-core.d.ts.map +1 -1
- package/dist/index-core.js +3 -0
- package/dist/intent.d.ts +98 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +343 -0
- package/dist/module-intent.d.ts +19 -5
- package/dist/module-intent.d.ts.map +1 -1
- package/dist/module-intent.js +211 -62
- package/dist/module.d.ts +41 -12
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +543 -38
- package/dist/proposal.d.ts +13 -1
- package/dist/proposal.d.ts.map +1 -1
- package/dist/proposal.js +21 -4
- package/dist/studio/components/AskFeltDB.d.ts.map +1 -1
- package/dist/studio/components/ProposalBrowser.d.ts +1 -1
- package/dist/studio/components/ProposalBrowser.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-CNSNrmA9.js → components-Duq2xQWt.js} +251 -193
- package/dist/studio/index.js +1 -1
- package/dist/studio/studio.css +1 -1
- package/dist/studio/utils/proposal-api.d.ts +4 -1
- package/dist/studio/utils/proposal-api.d.ts.map +1 -1
- package/dist/studio/utils/proposal-api.js +3 -0
- package/dist/studio-app/assets/{feltdb_wasm-CSB6KVgw.js → feltdb_wasm-bIqcRzAr.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-BE79okwX.wasm +0 -0
- package/dist/studio-app/assets/{index-yazaWMUN.css → index-Cd_NPw14.css} +1 -1
- package/dist/studio-app/assets/index-XGYdlElN.js +29 -0
- package/dist/studio-app/index.html +2 -2
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/workspace/local-development-authority.d.ts +2 -0
- package/dist/workspace/local-development-authority.d.ts.map +1 -1
- package/dist/workspace/local-development-authority.js +65 -2
- package/package.json +1 -1
- package/dist/studio-app/assets/dist-CCOk39Uc.js +0 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-Dd1fnO9U.wasm +0 -0
- package/dist/studio-app/assets/index-Bncji3aN.js +0 -43
- package/dist/studio-app/assets/lib-B2_7fcn7.js +0 -69
- package/dist/studio-app/assets/worker-CARZ5g7K.js +0 -69
|
@@ -448,6 +448,8 @@ struct ProposalScopeRequest {
|
|
|
448
448
|
limit: Option<usize>,
|
|
449
449
|
#[serde(default)]
|
|
450
450
|
cursor: Option<String>,
|
|
451
|
+
#[serde(default)]
|
|
452
|
+
current_evidence_hash: Option<String>,
|
|
451
453
|
}
|
|
452
454
|
#[derive(Deserialize)]
|
|
453
455
|
struct CreateProposalRequest {
|
|
@@ -472,6 +474,26 @@ struct CreateProposalRequest {
|
|
|
472
474
|
expires_at: Option<String>,
|
|
473
475
|
#[serde(default)]
|
|
474
476
|
status: Option<String>,
|
|
477
|
+
#[serde(default)]
|
|
478
|
+
understanding: Option<Value>,
|
|
479
|
+
#[serde(default)]
|
|
480
|
+
evidence_hash: Option<String>,
|
|
481
|
+
#[serde(default)]
|
|
482
|
+
understanding_hash: Option<String>,
|
|
483
|
+
}
|
|
484
|
+
#[derive(Deserialize, Serialize)]
|
|
485
|
+
struct ExecuteIntentRequest {
|
|
486
|
+
application_id: String,
|
|
487
|
+
#[serde(default = "production_environment")]
|
|
488
|
+
environment: String,
|
|
489
|
+
#[serde(alias = "raw_request")]
|
|
490
|
+
request: String,
|
|
491
|
+
}
|
|
492
|
+
#[derive(Deserialize)]
|
|
493
|
+
struct IntentHashRequest {
|
|
494
|
+
application_id: String,
|
|
495
|
+
environment: String,
|
|
496
|
+
intent_hash: String,
|
|
475
497
|
}
|
|
476
498
|
#[derive(Deserialize)]
|
|
477
499
|
struct ProposalActorRequest {
|
|
@@ -518,6 +540,7 @@ struct SignUpRequest {
|
|
|
518
540
|
}
|
|
519
541
|
#[derive(Deserialize)]
|
|
520
542
|
struct SignInRequest {
|
|
543
|
+
application_id: Option<String>,
|
|
521
544
|
email: String,
|
|
522
545
|
password: String,
|
|
523
546
|
}
|
|
@@ -2219,6 +2242,7 @@ async fn platform_overview(
|
|
|
2219
2242
|
let (users, tenants, applications, tenant_memberships, application_memberships) =
|
|
2220
2243
|
state.tenancy.platform_inventory().map_err(control_error)?;
|
|
2221
2244
|
let identities = state.identities.list().map_err(control_error)?;
|
|
2245
|
+
let runtime_metrics = state.metrics.snapshot();
|
|
2222
2246
|
Ok(Json(json!({
|
|
2223
2247
|
"owner": principal.identity_id,
|
|
2224
2248
|
"users": users,
|
|
@@ -2227,6 +2251,11 @@ async fn platform_overview(
|
|
|
2227
2251
|
"tenant_memberships": tenant_memberships,
|
|
2228
2252
|
"application_memberships": application_memberships,
|
|
2229
2253
|
"identities": identities,
|
|
2254
|
+
"adoption": {
|
|
2255
|
+
"measured_at": unix_seconds_i64().max(0) as u64,
|
|
2256
|
+
"runtime_process_started_seconds_ago": state.started_at.elapsed().as_secs(),
|
|
2257
|
+
"runtime": runtime_metrics,
|
|
2258
|
+
},
|
|
2230
2259
|
})))
|
|
2231
2260
|
}
|
|
2232
2261
|
async fn platform_update_user(
|
|
@@ -3793,6 +3822,9 @@ fn application_scope(
|
|
|
3793
3822
|
StatusCode::NOT_FOUND,
|
|
3794
3823
|
"application not found".into(),
|
|
3795
3824
|
))?;
|
|
3825
|
+
if std::env::var("FELTDB_INTENT_AUTHORITY_KEY_ID").as_deref() == Ok(actor) {
|
|
3826
|
+
return Ok(tenant_id);
|
|
3827
|
+
}
|
|
3796
3828
|
if !state
|
|
3797
3829
|
.tenancy
|
|
3798
3830
|
.authorize_application(actor, &tenant_id, application_id, capability)
|
|
@@ -4449,13 +4481,13 @@ async fn import_application_draft(
|
|
|
4449
4481
|
|
|
4450
4482
|
fn runtime_inventory(
|
|
4451
4483
|
state: &AppState,
|
|
4452
|
-
|
|
4484
|
+
_actor: &str,
|
|
4453
4485
|
application_id: &str,
|
|
4454
4486
|
manifest: &ApplicationManifest,
|
|
4455
4487
|
) -> Result<RuntimeInventory, ApiError> {
|
|
4456
4488
|
let connections = state
|
|
4457
4489
|
.connections
|
|
4458
|
-
.
|
|
4490
|
+
.application_connections(application_id)
|
|
4459
4491
|
.map_err(control_error)?;
|
|
4460
4492
|
let connection_ids = connections
|
|
4461
4493
|
.into_iter()
|
|
@@ -5046,6 +5078,49 @@ async fn inspect_record(
|
|
|
5046
5078
|
const PROPOSAL_COLLECTION: &str = "_feltdb_proposals";
|
|
5047
5079
|
const PROPOSAL_EVENT_COLLECTION: &str = "_feltdb_proposal_events";
|
|
5048
5080
|
const PROPOSAL_PREVIEW_COLLECTION: &str = "_feltdb_proposal_previews";
|
|
5081
|
+
const CONVERGENCE_COLLECTION: &str = "_feltdb_convergence";
|
|
5082
|
+
const INTENT_COLLECTION: &str = "_feltdb_intents";
|
|
5083
|
+
const INTENT_EVENT_COLLECTION: &str = "_feltdb_intent_events";
|
|
5084
|
+
|
|
5085
|
+
fn require_intent_service(headers: &HeaderMap) -> Result<(), ApiError> {
|
|
5086
|
+
let expected = std::env::var("FELTDB_INTENT_SERVICE_SECRET").map_err(|_| inspection_error(StatusCode::SERVICE_UNAVAILABLE, "intent_service_unconfigured", "Intent Engine service authentication is not configured"))?;
|
|
5087
|
+
let supplied = headers.get("x-feltdb-intent-service").and_then(|value| value.to_str().ok()).unwrap_or_default();
|
|
5088
|
+
if Sha256::digest(supplied.as_bytes()) != Sha256::digest(expected.as_bytes()) {
|
|
5089
|
+
return Err(inspection_error(StatusCode::FORBIDDEN, "forbidden", "invalid Intent Engine service credential"));
|
|
5090
|
+
}
|
|
5091
|
+
Ok(())
|
|
5092
|
+
}
|
|
5093
|
+
|
|
5094
|
+
async fn execute_intent(
|
|
5095
|
+
State(state): State<AppState>, Extension(principal): Extension<Principal>, headers: HeaderMap,
|
|
5096
|
+
Json(input): Json<ExecuteIntentRequest>,
|
|
5097
|
+
) -> Result<Json<Value>, ApiError> {
|
|
5098
|
+
application_scope(&state, &principal.key_id, &input.application_id, "application:write")?;
|
|
5099
|
+
if input.request.trim().is_empty() { return Err(inspection_error(StatusCode::BAD_REQUEST, "invalid_intent", "request is required")); }
|
|
5100
|
+
let endpoint = std::env::var("FELTDB_INTENT_ENGINE_URL").map_err(|_| inspection_error(StatusCode::SERVICE_UNAVAILABLE, "intent_engine_unavailable", "managed Intent Engine is not configured"))?;
|
|
5101
|
+
let secret = std::env::var("FELTDB_INTENT_SERVICE_SECRET").map_err(|_| inspection_error(StatusCode::SERVICE_UNAVAILABLE, "intent_engine_unavailable", "managed Intent Engine authentication is not configured"))?;
|
|
5102
|
+
let mut request = state.peer_client.post(format!("{}/internal/v1/intents", endpoint.trim_end_matches('/'))).header("x-feltdb-intent-service", secret).json(&input);
|
|
5103
|
+
if let Some(value) = headers.get("idempotency-key") { request = request.header("idempotency-key", value); }
|
|
5104
|
+
let response = request.send().await.map_err(|error| inspection_error(StatusCode::BAD_GATEWAY, "intent_engine_unavailable", error.to_string()))?;
|
|
5105
|
+
let status = response.status(); let value: Value = response.json().await.map_err(|error| inspection_error(StatusCode::BAD_GATEWAY, "invalid_intent_engine_response", error.to_string()))?;
|
|
5106
|
+
if !status.is_success() { let republish=value.get("error").and_then(Value::as_str)==Some("APPLICATION_REPUBLISH_REQUIRED");return Err(inspection_error(if republish {StatusCode::CONFLICT}else{StatusCode::BAD_GATEWAY},if republish{"application_republish_required"}else{"intent_execution_failed"},value.get("message").and_then(Value::as_str).unwrap_or("Intent Engine failed"))); }
|
|
5107
|
+
Ok(Json(value))
|
|
5108
|
+
}
|
|
5109
|
+
|
|
5110
|
+
async fn list_intents(State(state): State<AppState>, Extension(principal): Extension<Principal>, Query(input): Query<ProposalScopeRequest>) -> Result<Json<Value>, ApiError> {
|
|
5111
|
+
application_scope(&state,&principal.key_id,&input.application_id,"application:read")?;
|
|
5112
|
+
let mut intents=state.db.list_collection(INTENT_COLLECTION)?.into_iter().map(|row|row.value).filter(|value|proposal_scope_matches(value,&input.application_id,&input.environment)).collect::<Vec<_>>();
|
|
5113
|
+
intents.sort_by(|a,b|a.get("created_at").and_then(Value::as_str).cmp(&b.get("created_at").and_then(Value::as_str)));for value in &mut intents{if let Some(object)=value.as_object_mut(){object.remove("execution_result");}redact_inspection_value(value);}Ok(Json(json!({"intents":intents})))
|
|
5114
|
+
}
|
|
5115
|
+
async fn get_intent(State(state): State<AppState>, Extension(principal): Extension<Principal>, Path((id,operation)): Path<(String,String)>, Query(input): Query<ProposalScopeRequest>) -> Result<Json<Value>,ApiError>{
|
|
5116
|
+
application_scope(&state,&principal.key_id,&input.application_id,"application:read")?;let intent=required_value(&state,INTENT_COLLECTION,&id,"intent not found")?;if !proposal_scope_matches(&intent,&input.application_id,&input.environment){return Err(ApiError(StatusCode::NOT_FOUND,"intent not found".into()));}
|
|
5117
|
+
let value=match operation.as_str(){"understanding"=>intent.get("understanding").cloned().unwrap_or(Value::Null),"plan"=>intent.get("plan").cloned().unwrap_or(Value::Null),"proposal"=>intent.get("proposal_id").and_then(Value::as_str).map(|id|proposal_value(&state,id)).transpose()?.unwrap_or(Value::Null),"history"=>{let mut events=state.db.list_collection(INTENT_EVENT_COLLECTION)?.into_iter().map(|row|row.value).filter(|value|value.get("intent_id").and_then(Value::as_str)==Some(id.as_str())).collect::<Vec<_>>();events.sort_by(|a,b|a.get("created_at").and_then(Value::as_str).cmp(&b.get("created_at").and_then(Value::as_str)));json!({"events":events})},_=>return Err(ApiError(StatusCode::NOT_FOUND,"intent resource not found".into()))};Ok(Json(value))
|
|
5118
|
+
}
|
|
5119
|
+
async fn get_intent_root(State(state): State<AppState>, Extension(principal): Extension<Principal>, Path(id):Path<String>, Query(input):Query<ProposalScopeRequest>)->Result<Json<Value>,ApiError>{application_scope(&state,&principal.key_id,&input.application_id,"application:read")?;let mut value=required_value(&state,INTENT_COLLECTION,&id,"intent not found")?;if !proposal_scope_matches(&value,&input.application_id,&input.environment){return Err(ApiError(StatusCode::NOT_FOUND,"intent not found".into()));}if let Some(object)=value.as_object_mut(){object.remove("execution_result");}Ok(Json(value))}
|
|
5120
|
+
async fn internal_find_intent(State(state):State<AppState>,headers:HeaderMap,Query(input):Query<IntentHashRequest>)->Result<Json<Value>,ApiError>{require_intent_service(&headers)?;let value=state.db.list_collection(INTENT_COLLECTION)?.into_iter().map(|row|row.value).find(|value|proposal_scope_matches(value,&input.application_id,&input.environment)&&value.get("intent_hash").and_then(Value::as_str)==Some(input.intent_hash.as_str())).unwrap_or(Value::Null);Ok(Json(value))}
|
|
5121
|
+
async fn internal_create_intent(State(state):State<AppState>,headers:HeaderMap,Json(value):Json<Value>)->Result<(StatusCode,Json<Value>),ApiError>{require_intent_service(&headers)?;let id=value.get("id").and_then(Value::as_str).ok_or_else(||inspection_error(StatusCode::BAD_REQUEST,"invalid_intent","intent id is required"))?;insert_canonical(&state,INTENT_COLLECTION,id,value.clone())?;Ok((StatusCode::CREATED,Json(value)))}
|
|
5122
|
+
async fn internal_replace_intent(State(state):State<AppState>,headers:HeaderMap,Path(id):Path<String>,Json(value):Json<Value>)->Result<Json<Value>,ApiError>{require_intent_service(&headers)?;let _=put_canonical(&state,INTENT_COLLECTION,&id,value.clone())?;Ok(Json(value))}
|
|
5123
|
+
async fn internal_create_intent_event(State(state):State<AppState>,headers:HeaderMap,Json(value):Json<Value>)->Result<(StatusCode,Json<Value>),ApiError>{require_intent_service(&headers)?;let id=value.get("id").and_then(Value::as_str).ok_or_else(||inspection_error(StatusCode::BAD_REQUEST,"invalid_intent_event","event id is required"))?;insert_canonical(&state,INTENT_EVENT_COLLECTION,id,value.clone())?;Ok((StatusCode::CREATED,Json(value)))}
|
|
5049
5124
|
|
|
5050
5125
|
fn proposal_contract_snapshot(
|
|
5051
5126
|
revision: &ApplicationRevision,
|
|
@@ -5165,6 +5240,24 @@ async fn create_proposal(
|
|
|
5165
5240
|
"proposed_flow and base_flow_hash are required".into(),
|
|
5166
5241
|
));
|
|
5167
5242
|
}
|
|
5243
|
+
if input.metadata.get("created_from").and_then(Value::as_str) == Some("module-intent")
|
|
5244
|
+
&& input.understanding.is_none()
|
|
5245
|
+
{
|
|
5246
|
+
return Err(inspection_error(StatusCode::UNPROCESSABLE_ENTITY, "understanding_required", "module proposals require an evidence-backed understanding snapshot"));
|
|
5247
|
+
}
|
|
5248
|
+
if input.understanding.is_some()
|
|
5249
|
+
&& (input.evidence_hash.as_deref().is_none_or(|value| !value.starts_with("sha256:"))
|
|
5250
|
+
|| input.understanding_hash.as_deref().is_none_or(|value| !value.starts_with("sha256:")))
|
|
5251
|
+
{
|
|
5252
|
+
return Err(inspection_error(StatusCode::UNPROCESSABLE_ENTITY, "invalid_understanding", "understanding requires evidence_hash and understanding_hash fingerprints"));
|
|
5253
|
+
}
|
|
5254
|
+
if let Some(understanding) = input.understanding.as_ref() {
|
|
5255
|
+
if understanding.get("evidence_hash").and_then(Value::as_str) != input.evidence_hash.as_deref()
|
|
5256
|
+
|| understanding.get("understanding_hash").and_then(Value::as_str) != input.understanding_hash.as_deref()
|
|
5257
|
+
{
|
|
5258
|
+
return Err(inspection_error(StatusCode::UNPROCESSABLE_ENTITY, "invalid_understanding", "understanding fingerprints must match the Proposal fingerprints"));
|
|
5259
|
+
}
|
|
5260
|
+
}
|
|
5168
5261
|
let id = format!("p_{}", uuid::Uuid::new_v4().simple());
|
|
5169
5262
|
let now = unix_seconds_i64();
|
|
5170
5263
|
let mut value = json!({ "id":id, "application_id":input.application_id, "environment":input.environment,
|
|
@@ -5173,6 +5266,7 @@ async fn create_proposal(
|
|
|
5173
5266
|
"contract_diff":input.contract_diff.unwrap_or_else(||json!([])), "source_plan":input.source_plan.unwrap_or_else(||json!({"files":[]})), "summary":input.summary, "warnings":input.warnings,
|
|
5174
5267
|
"created_by":principal.key_id, "created_at":now, "expires_at":input.expires_at, "metadata":input.metadata,
|
|
5175
5268
|
"parent_proposal_id":input.parent_proposal_id,
|
|
5269
|
+
"understanding":input.understanding, "evidence_hash":input.evidence_hash, "understanding_hash":input.understanding_hash,
|
|
5176
5270
|
"base_module_versions": revision.manifest.modules.iter().filter_map(|module| Some(json!({
|
|
5177
5271
|
"id": module.get("id")?, "provider": module.get("provider")?, "version": module.get("version")?
|
|
5178
5272
|
}))).collect::<Vec<_>>(),
|
|
@@ -5325,6 +5419,7 @@ fn proposal_readiness_value(
|
|
|
5325
5419
|
state: &AppState,
|
|
5326
5420
|
tenant: &str,
|
|
5327
5421
|
value: &Value,
|
|
5422
|
+
current_evidence_hash: Option<&str>,
|
|
5328
5423
|
) -> Result<Value, ApiError> {
|
|
5329
5424
|
let application_id = value.get("application_id").and_then(Value::as_str).unwrap_or("");
|
|
5330
5425
|
let environment = value.get("environment").and_then(Value::as_str).unwrap_or("production");
|
|
@@ -5338,13 +5433,15 @@ fn proposal_readiness_value(
|
|
|
5338
5433
|
let contract_changed = current_contract_hash != proposal_contract_hash;
|
|
5339
5434
|
let flow_changed = current_flow_hash.as_deref().is_some_and(|hash| hash != proposal_flow_hash);
|
|
5340
5435
|
let modules_changed = value.get("base_module_versions").and_then(Value::as_array).is_some_and(|modules| modules != ¤t_modules);
|
|
5436
|
+
let evidence_changed = current_evidence_hash.is_some_and(|current| value.get("evidence_hash").and_then(Value::as_str).is_some_and(|base| base != current));
|
|
5341
5437
|
let expired = proposal_is_expired(value);
|
|
5342
5438
|
let mut blockers = Vec::new();
|
|
5343
5439
|
if contract_changed { blockers.push("contract_changed"); }
|
|
5344
5440
|
if flow_changed { blockers.push("flow_changed"); }
|
|
5345
5441
|
if modules_changed { blockers.push("module_versions_changed"); }
|
|
5442
|
+
if evidence_changed { blockers.push("evidence_changed"); }
|
|
5346
5443
|
if expired { blockers.push("expired"); }
|
|
5347
|
-
let stale = contract_changed || flow_changed || modules_changed;
|
|
5444
|
+
let stale = contract_changed || flow_changed || modules_changed || evidence_changed;
|
|
5348
5445
|
Ok(json!({
|
|
5349
5446
|
"status":value.get("status"), "readiness":if blockers.is_empty(){"ready"}else{"blocked"},
|
|
5350
5447
|
"blockers":blockers, "notes":[], "current_contract_hash":current_contract_hash,
|
|
@@ -5364,7 +5461,29 @@ async fn proposal_status(
|
|
|
5364
5461
|
if !proposal_scope_matches(&value, &input.application_id, &input.environment) {
|
|
5365
5462
|
return Err(inspection_error(StatusCode::NOT_FOUND, "proposal_not_found", "proposal not found"));
|
|
5366
5463
|
}
|
|
5367
|
-
Ok(Json(proposal_readiness_value(&state, &tenant, &value)?))
|
|
5464
|
+
Ok(Json(proposal_readiness_value(&state, &tenant, &value, input.current_evidence_hash.as_deref())?))
|
|
5465
|
+
}
|
|
5466
|
+
async fn record_proposal_convergence(
|
|
5467
|
+
State(state): State<AppState>, Extension(principal): Extension<Principal>, Path(id): Path<String>, Json(mut input): Json<Value>,
|
|
5468
|
+
) -> Result<(StatusCode, Json<Value>), ApiError> {
|
|
5469
|
+
let application_id=input.get("application_id").and_then(Value::as_str).ok_or_else(||inspection_error(StatusCode::BAD_REQUEST,"invalid_convergence","application_id is required"))?.to_string();
|
|
5470
|
+
let environment=input.get("environment").and_then(Value::as_str).unwrap_or("production").to_string();
|
|
5471
|
+
application_scope(&state,&principal.key_id,&application_id,"application:write")?;let proposal=proposal_value(&state,&id)?;
|
|
5472
|
+
if !proposal_scope_matches(&proposal,&application_id,&environment){return Err(inspection_error(StatusCode::NOT_FOUND,"proposal_not_found","proposal not found"));}
|
|
5473
|
+
if proposal.get("status").and_then(Value::as_str)!=Some("applied"){return Err(inspection_error(StatusCode::CONFLICT,"proposal_not_applied","only an applied Proposal can record convergence"));}
|
|
5474
|
+
if input.get("proposal_id").and_then(Value::as_str)!=Some(id.as_str()){return Err(inspection_error(StatusCode::UNPROCESSABLE_ENTITY,"invalid_convergence","proposal_id must match the route"));}
|
|
5475
|
+
let valid_status=input.get("status").and_then(Value::as_str).is_some_and(|value|matches!(value,"pending"|"checking"|"converged"|"partially_converged"|"diverged"|"blocked"|"unverified"));
|
|
5476
|
+
if !valid_status||input.get("findings").is_none_or(|value|!value.is_array())||input.get("evidence_hash").and_then(Value::as_str).is_none_or(|value|!value.starts_with("sha256:")){return Err(inspection_error(StatusCode::UNPROCESSABLE_ENTITY,"invalid_convergence","status, findings, and evidence_hash are required"));}
|
|
5477
|
+
let convergence_id=format!("cv_{}",uuid::Uuid::new_v4().simple());input["id"]=json!(convergence_id);input["created_at"]=json!(unix_seconds_i64());input["verifier_version"]=json!(1);
|
|
5478
|
+
redact_inspection_value(&mut input);insert_canonical(&state,CONVERGENCE_COLLECTION,&convergence_id,input.clone())?;Ok((StatusCode::CREATED,Json(input)))
|
|
5479
|
+
}
|
|
5480
|
+
async fn proposal_convergence(
|
|
5481
|
+
State(state): State<AppState>, Extension(principal): Extension<Principal>, Path(id): Path<String>, Query(input): Query<ProposalScopeRequest>,
|
|
5482
|
+
) -> Result<Json<Value>, ApiError> {
|
|
5483
|
+
application_scope(&state,&principal.key_id,&input.application_id,"application:read")?;let proposal=proposal_value(&state,&id)?;
|
|
5484
|
+
if !proposal_scope_matches(&proposal,&input.application_id,&input.environment){return Err(inspection_error(StatusCode::NOT_FOUND,"proposal_not_found","proposal not found"));}
|
|
5485
|
+
let mut values=state.db.list_collection(CONVERGENCE_COLLECTION)?.into_iter().map(|row|row.value).filter(|value|value.get("proposal_id").and_then(Value::as_str)==Some(id.as_str())&&proposal_scope_matches(value,&input.application_id,&input.environment)).collect::<Vec<_>>();
|
|
5486
|
+
values.sort_by_key(|value|value.get("created_at").and_then(Value::as_i64).unwrap_or_default());values.reverse();Ok(Json(json!({"convergence":values})))
|
|
5368
5487
|
}
|
|
5369
5488
|
async fn validate_proposal(
|
|
5370
5489
|
State(state): State<AppState>,
|
|
@@ -5501,7 +5620,9 @@ async fn validate_proposal(
|
|
|
5501
5620
|
value["proposed_contract"] = serde_json::to_value(&proposed.manifest)
|
|
5502
5621
|
.map_err(|e| ApiError(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
|
5503
5622
|
}
|
|
5504
|
-
value
|
|
5623
|
+
if !value.pointer("/source_plan/files").and_then(Value::as_array).is_some_and(|files| !files.is_empty()) {
|
|
5624
|
+
value["source_plan"] = json!({"files":[{"path":"feltdb.flow","operation":"modify"},{"path":"src/feltdb/generated-contract.ts","operation":"modify"}]});
|
|
5625
|
+
}
|
|
5505
5626
|
Ok(Json(move_proposal(
|
|
5506
5627
|
&state,
|
|
5507
5628
|
&id,
|
|
@@ -5546,7 +5667,7 @@ async fn preview_proposal(
|
|
|
5546
5667
|
let proposed_manifest: ApplicationManifest = serde_json::from_value(value.get("proposed_contract").cloned().ok_or_else(|| inspection_error(StatusCode::UNPROCESSABLE_ENTITY, "missing_required_semantics", "validated proposal has no proposed contract snapshot"))?).map_err(|error| inspection_error(StatusCode::UNPROCESSABLE_ENTITY, "invalid_proposal", error.to_string()))?;
|
|
5547
5668
|
let current_revision_id = state.applications.pointers(&input.application_id).get(&input.environment).cloned().ok_or_else(|| inspection_error(StatusCode::NOT_FOUND, "application_not_found", "active application contract not found"))?;
|
|
5548
5669
|
let current_revision = state.applications.revision(&tenant, &input.application_id, ¤t_revision_id).ok_or_else(|| inspection_error(StatusCode::NOT_FOUND, "application_not_found", "active application revision not found"))?;
|
|
5549
|
-
let readiness = proposal_readiness_value(&state, &tenant, &value)?;
|
|
5670
|
+
let readiness = proposal_readiness_value(&state, &tenant, &value, None)?;
|
|
5550
5671
|
if readiness.get("readiness").and_then(Value::as_str) != Some("ready") {
|
|
5551
5672
|
return Err(ApiError::structured(StatusCode::CONFLICT, json!({"code":"preview_not_ready","message":"proposal cannot be previewed","readiness":readiness})));
|
|
5552
5673
|
}
|
|
@@ -5616,7 +5737,7 @@ async fn get_proposal_preview(
|
|
|
5616
5737
|
if proposal.get("preview_id") != artifact.get("preview_id") {
|
|
5617
5738
|
return Err(inspection_error(StatusCode::CONFLICT, "preview_invalidated", "preview has been replaced"));
|
|
5618
5739
|
}
|
|
5619
|
-
if proposal_readiness_value(&state, &tenant, &proposal)?.get("stale").and_then(Value::as_bool) == Some(true) {
|
|
5740
|
+
if proposal_readiness_value(&state, &tenant, &proposal, None)?.get("stale").and_then(Value::as_bool) == Some(true) {
|
|
5620
5741
|
return Err(inspection_error(StatusCode::CONFLICT, "preview_invalidated", "the application authority changed after preview creation"));
|
|
5621
5742
|
}
|
|
5622
5743
|
redact_inspection_value(&mut artifact);
|
|
@@ -5696,7 +5817,7 @@ async fn transition_proposal(
|
|
|
5696
5817
|
return Err(inspection_error(StatusCode::CONFLICT, "proposal_expired", "proposal has expired"));
|
|
5697
5818
|
}
|
|
5698
5819
|
if input.status == "approved" {
|
|
5699
|
-
let readiness = proposal_readiness_value(&state, &tenant, &value)?;
|
|
5820
|
+
let readiness = proposal_readiness_value(&state, &tenant, &value, None)?;
|
|
5700
5821
|
if readiness.get("readiness").and_then(Value::as_str) != Some("ready") {
|
|
5701
5822
|
return Err(ApiError::structured(StatusCode::CONFLICT, json!({"code":"stale_proposal","message":"proposal is no longer applicable","readiness":readiness})));
|
|
5702
5823
|
}
|
|
@@ -5795,19 +5916,17 @@ async fn auth_sign_up(
|
|
|
5795
5916
|
"application not found".into(),
|
|
5796
5917
|
));
|
|
5797
5918
|
}
|
|
5798
|
-
let (identity, session, token) = state
|
|
5919
|
+
let (identity, session, token) = match state
|
|
5799
5920
|
.identities
|
|
5800
5921
|
.sign_up(&input.email, &input.password, input.display_name)
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
)
|
|
5810
|
-
})?;
|
|
5922
|
+
{
|
|
5923
|
+
Ok(created) => created,
|
|
5924
|
+
Err(error) if error == "identity already exists" => state
|
|
5925
|
+
.identities
|
|
5926
|
+
.sign_in(&input.email, &input.password)
|
|
5927
|
+
.map_err(|_| ApiError(StatusCode::UNAUTHORIZED, "invalid credentials".into()))?,
|
|
5928
|
+
Err(error) => return Err(ApiError(StatusCode::BAD_REQUEST, error)),
|
|
5929
|
+
};
|
|
5811
5930
|
state
|
|
5812
5931
|
.tenancy
|
|
5813
5932
|
.register_platform_user(
|
|
@@ -5829,6 +5948,22 @@ async fn auth_sign_in(
|
|
|
5829
5948
|
.identities
|
|
5830
5949
|
.sign_in(&input.email, &input.password)
|
|
5831
5950
|
.map_err(|_| ApiError(StatusCode::UNAUTHORIZED, "invalid credentials".into()))?;
|
|
5951
|
+
if let Some(application_id) = input.application_id {
|
|
5952
|
+
if state.tenancy.application_tenant(&application_id).is_none() {
|
|
5953
|
+
return Err(ApiError(StatusCode::NOT_FOUND, "application not found".into()));
|
|
5954
|
+
}
|
|
5955
|
+
state
|
|
5956
|
+
.tenancy
|
|
5957
|
+
.register_platform_user(
|
|
5958
|
+
&identity.subject_id,
|
|
5959
|
+
identity.email.as_deref().unwrap_or(&identity.identity_id),
|
|
5960
|
+
)
|
|
5961
|
+
.map_err(control_error)?;
|
|
5962
|
+
state
|
|
5963
|
+
.tenancy
|
|
5964
|
+
.register_application_actor(&identity.subject_id, &application_id)
|
|
5965
|
+
.map_err(control_error)?;
|
|
5966
|
+
}
|
|
5832
5967
|
Ok(auth_response(identity, session, token))
|
|
5833
5968
|
}
|
|
5834
5969
|
async fn auth_session(Extension(principal): Extension<Principal>) -> Json<Value> {
|
|
@@ -5872,6 +6007,13 @@ async fn application_openapi() -> Json<Value> {
|
|
|
5872
6007
|
"/query": { "post": { "responses": { "200": { "description": "Bounded authorized query" } } } },
|
|
5873
6008
|
"/transactions": { "post": { "responses": { "200": { "description": "Atomic idempotent mutation" } } } },
|
|
5874
6009
|
"/events": { "get": { "responses": { "200": { "description": "Application event stream" } } } },
|
|
6010
|
+
"/intents": {
|
|
6011
|
+
"get": { "responses": { "200": { "description": "Durable application Intents" } } },
|
|
6012
|
+
"post": { "parameters": [{ "name":"Idempotency-Key", "in":"header", "required":false, "schema":{"type":"string"} }], "responses": { "200": { "description": "Canonical Intent execution result" } } }
|
|
6013
|
+
},
|
|
6014
|
+
"/intents/{id}": { "get": { "responses": { "200": { "description": "Canonical Intent" } } } },
|
|
6015
|
+
"/intents/{id}/{artifact}": { "get": { "responses": { "200": { "description": "Intent understanding, plan, Proposal, or history" } } } },
|
|
6016
|
+
"/proposals": { "get": { "responses": { "200": { "description": "Durable Proposals" } } }, "post": { "responses": { "201": { "description": "Created Proposal" } } } },
|
|
5875
6017
|
"/workflows/{name}/run": { "post": { "responses": { "201": { "description": "Workflow execution" } } } },
|
|
5876
6018
|
"/agents/{name}/run": { "post": { "responses": { "201": { "description": "Agent execution" } } } },
|
|
5877
6019
|
"/capabilities/{name}/run": { "post": { "responses": { "200": { "description": "Public capability result" } } } }
|
|
@@ -7547,6 +7689,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
7547
7689
|
.route("/v1/application/schema", get(inspect_application_schema))
|
|
7548
7690
|
.route("/v1/data/{collection}", get(inspect_collection))
|
|
7549
7691
|
.route("/v1/data/{collection}/{id}", get(inspect_record))
|
|
7692
|
+
.route("/v1/intents", get(list_intents).post(execute_intent))
|
|
7693
|
+
.route("/v1/intents/{id}", get(get_intent_root))
|
|
7694
|
+
.route("/v1/intents/{id}/{operation}", get(get_intent))
|
|
7550
7695
|
.route("/v1/proposals", get(list_proposals).post(create_proposal))
|
|
7551
7696
|
.route("/v1/proposals/{id}", get(get_proposal))
|
|
7552
7697
|
.route("/v1/proposals/{id}/history", get(proposal_history))
|
|
@@ -7570,6 +7715,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
7570
7715
|
"/v1/proposals/{id}/status",
|
|
7571
7716
|
get(proposal_status).patch(transition_proposal),
|
|
7572
7717
|
)
|
|
7718
|
+
.route("/v1/proposals/{id}/convergence", get(proposal_convergence).post(record_proposal_convergence))
|
|
7573
7719
|
.route("/v1/previews/{id}", get(get_proposal_preview))
|
|
7574
7720
|
.route("/v1/previews/{id}/data/{collection}", get(inspect_proposal_preview_data))
|
|
7575
7721
|
.route("/v1/previews/{id}/simulate", axum::routing::post(simulate_proposal_preview))
|
|
@@ -7956,6 +8102,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
7956
8102
|
.route("/v1/openapi.json", get(application_openapi))
|
|
7957
8103
|
.route("/v1/auth/signup", axum::routing::post(auth_sign_up))
|
|
7958
8104
|
.route("/v1/auth/signin", axum::routing::post(auth_sign_in))
|
|
8105
|
+
.route("/internal/intents/by-hash", get(internal_find_intent))
|
|
8106
|
+
.route("/internal/intents", axum::routing::post(internal_create_intent))
|
|
8107
|
+
.route("/internal/intents/{id}", put(internal_replace_intent))
|
|
8108
|
+
.route("/internal/intent-events", axum::routing::post(internal_create_intent_event))
|
|
7959
8109
|
.route("/ready", get(readiness))
|
|
7960
8110
|
.route("/runtime", get(runtime))
|
|
7961
8111
|
.route("/metrics", get(network_metrics))
|
|
@@ -10937,7 +11087,7 @@ async fn list_records(
|
|
|
10937
11087
|
State(state): State<AppState>,
|
|
10938
11088
|
Path(collection): Path<String>,
|
|
10939
11089
|
) -> Result<Json<Vec<RecordResponse>>, ApiError> {
|
|
10940
|
-
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION {
|
|
11090
|
+
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION || collection == CONVERGENCE_COLLECTION || collection == INTENT_COLLECTION || collection == INTENT_EVENT_COLLECTION {
|
|
10941
11091
|
return Err(ApiError(
|
|
10942
11092
|
StatusCode::FORBIDDEN,
|
|
10943
11093
|
"system collection requires proposal service".into(),
|
|
@@ -10952,7 +11102,7 @@ async fn get_record(
|
|
|
10952
11102
|
State(state): State<AppState>,
|
|
10953
11103
|
Path((collection, id)): Path<(String, String)>,
|
|
10954
11104
|
) -> Result<Json<RecordResponse>, ApiError> {
|
|
10955
|
-
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION {
|
|
11105
|
+
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION || collection == CONVERGENCE_COLLECTION || collection == INTENT_COLLECTION || collection == INTENT_EVENT_COLLECTION {
|
|
10956
11106
|
return Err(ApiError(
|
|
10957
11107
|
StatusCode::FORBIDDEN,
|
|
10958
11108
|
"system collection requires proposal service".into(),
|
|
@@ -11198,7 +11348,7 @@ async fn create_record(
|
|
|
11198
11348
|
Path(collection): Path<String>,
|
|
11199
11349
|
Json(mut record): Json<CreateRecord>,
|
|
11200
11350
|
) -> Result<(StatusCode, Json<RecordResponse>), ApiError> {
|
|
11201
|
-
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION {
|
|
11351
|
+
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION || collection == CONVERGENCE_COLLECTION || collection == INTENT_COLLECTION || collection == INTENT_EVENT_COLLECTION {
|
|
11202
11352
|
return Err(ApiError(
|
|
11203
11353
|
StatusCode::FORBIDDEN,
|
|
11204
11354
|
"system collection requires proposal service".into(),
|
|
@@ -11237,7 +11387,7 @@ async fn update_record(
|
|
|
11237
11387
|
Path((collection, id)): Path<(String, String)>,
|
|
11238
11388
|
Json(changes): Json<Map<String, Value>>,
|
|
11239
11389
|
) -> Result<Json<RecordResponse>, ApiError> {
|
|
11240
|
-
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION {
|
|
11390
|
+
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION || collection == CONVERGENCE_COLLECTION || collection == INTENT_COLLECTION || collection == INTENT_EVENT_COLLECTION {
|
|
11241
11391
|
return Err(ApiError(
|
|
11242
11392
|
StatusCode::FORBIDDEN,
|
|
11243
11393
|
"system collection requires proposal service".into(),
|
|
@@ -11358,7 +11508,7 @@ async fn delete_record(
|
|
|
11358
11508
|
State(state): State<AppState>,
|
|
11359
11509
|
Path((collection, id)): Path<(String, String)>,
|
|
11360
11510
|
) -> Result<StatusCode, ApiError> {
|
|
11361
|
-
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION {
|
|
11511
|
+
if collection == PROPOSAL_COLLECTION || collection == PROPOSAL_EVENT_COLLECTION || collection == CONVERGENCE_COLLECTION || collection == INTENT_COLLECTION || collection == INTENT_EVENT_COLLECTION {
|
|
11362
11512
|
return Err(ApiError(
|
|
11363
11513
|
StatusCode::FORBIDDEN,
|
|
11364
11514
|
"system collection requires proposal service".into(),
|
|
@@ -609,7 +609,7 @@ impl TenancyStore {
|
|
|
609
609
|
.find(|app| app.id == application_id)?
|
|
610
610
|
.clone();
|
|
611
611
|
drop(records);
|
|
612
|
-
self.authorize_application(user_id, &app.tenant_id, &app.id, "
|
|
612
|
+
self.authorize_application(user_id, &app.tenant_id, &app.id, "application:read")
|
|
613
613
|
.then_some(app)
|
|
614
614
|
}
|
|
615
615
|
pub fn application_tenant(&self, application_id: &str) -> Option<String> {
|
|
@@ -1322,7 +1322,14 @@ mod tests {
|
|
|
1322
1322
|
.unwrap();
|
|
1323
1323
|
|
|
1324
1324
|
assert!(store.authorize_application("key_runtime", &tenant.id, &app.id, "state:read"));
|
|
1325
|
+
assert_eq!(
|
|
1326
|
+
store
|
|
1327
|
+
.application_for("key_runtime", &app.id)
|
|
1328
|
+
.map(|application| application.id),
|
|
1329
|
+
Some(app.id.clone())
|
|
1330
|
+
);
|
|
1325
1331
|
assert!(!store.authorize_application("key_runtime", &tenant.id, &app.id, "state:write"));
|
|
1332
|
+
assert!(store.application_for("key_runtime", &other.id).is_none());
|
|
1326
1333
|
assert!(!store.authorize_application("key_runtime", &tenant.id, &other.id, "state:read"));
|
|
1327
1334
|
}
|
|
1328
1335
|
}
|
|
@@ -17,7 +17,15 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
17
17
|
const loading = sessionRecords.loading || userRecords.loading || membershipRecords.loading || organizationRecords.loading;
|
|
18
18
|
const establish = (next: Session) => { sessionStorage.setItem(SESSION_KEY, next.id); setSessionId(next.id); };
|
|
19
19
|
const value = useMemo<AuthValue>(() => ({ loading, authenticated: Boolean(session && user && membership && organization), session, user, membership, organization,
|
|
20
|
-
signUp: async input => {
|
|
20
|
+
signUp: async input => {
|
|
21
|
+
try {
|
|
22
|
+
await db.auth.signUp({ email: input.email, password: input.password, display_name: input.name });
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if ((error as { code?: string }).code !== 'CONFLICT') throw error;
|
|
25
|
+
await db.auth.signIn({ email: input.email, password: input.password });
|
|
26
|
+
}
|
|
27
|
+
establish(await createAccount(input));
|
|
28
|
+
},
|
|
21
29
|
signIn: async (email, password) => { await db.auth.signIn({ email, password }); establish(await createSession(email)); },
|
|
22
30
|
signOut: async () => { if (session) await sessions.delete(session.id); await db.auth.signOut(); sessionStorage.removeItem(SESSION_KEY); setSessionId(null); },
|
|
23
31
|
}), [loading, session, user, membership, organization]);
|
|
@@ -3,6 +3,6 @@ import { useAuth } from '../context/AuthContext';
|
|
|
3
3
|
|
|
4
4
|
export function SignUp() {
|
|
5
5
|
const { signUp } = useAuth(); const [error, setError] = useState(''); const [busy, setBusy] = useState(false);
|
|
6
|
-
async function submit(event: FormEvent<HTMLFormElement>) { event.preventDefault(); setBusy(true); setError(''); const form = new FormData(event.currentTarget); try { await signUp({ name: String(form.get('name')), email: String(form.get('email')), password: String(form.get('password')), organization: String(form.get('organization')) }); } catch { setError('We could not create your account. Check the details and try again.'); setBusy(false); } }
|
|
6
|
+
async function submit(event: FormEvent<HTMLFormElement>) { event.preventDefault(); setBusy(true); setError(''); const form = new FormData(event.currentTarget); try { await signUp({ name: String(form.get('name')), email: String(form.get('email')), password: String(form.get('password')), organization: String(form.get('organization')) }); } catch (error) { setError(error instanceof Error ? error.message : 'We could not create your account. Check the details and try again.'); setBusy(false); } }
|
|
7
7
|
return <><span className="eyebrow">Create your workspace</span><h2>Start with durable state.</h2><p className="muted">Your actor, account, and organization are established at the FeltDB boundary.</p><form onSubmit={submit}><label>Name<input name="name" autoComplete="name" required placeholder="Ada Lovelace" /></label><label>Work email<input name="email" type="email" autoComplete="email" required placeholder="ada@example.com" /></label><label>Password<input name="password" type="password" autoComplete="new-password" minLength={8} required /></label><label>Organization<input name="organization" required placeholder="Analytical Engines" /></label>{error && <p className="error">{error}</p>}<button disabled={busy}>{busy ? 'Creating…' : 'Create account'}</button></form><p className="switch">Already have an account? <a href="?view=signin">Sign in</a></p></>;
|
|
8
8
|
}
|
package/dist/flowspec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flowspec.d.ts","sourceRoot":"","sources":["../src/flowspec.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE;AAC5E,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC7E,MAAM,WAAW,cAAc;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAAC,OAAO,EAAE,SAAS,EAAE,CAAA;CAAE;AAC3F,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE;AACjE,MAAM,WAAW,QAAS,SAAQ,SAAS;CAAG;AAC9C,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE;AACrF,MAAM,WAAW,WAAW;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE;AACpE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACzD;AAED,MAAM,WAAW,cAAc;IAAG,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AACjG,MAAM,WAAW,YAAY;IAAG,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE;AACvF,MAAM,WAAW,sBAAsB;IAAG,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,GAAG,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAEpK,eAAO,MAAM,oBAAoB,yLAA0L,CAAC;AAC5N,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ1D;AAED,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGrE,sHAAsH;AACtH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,mBAAmB,
|
|
1
|
+
{"version":3,"file":"flowspec.d.ts","sourceRoot":"","sources":["../src/flowspec.ts"],"names":[],"mappings":"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"}
|
package/dist/flowspec.js
CHANGED
|
@@ -26,7 +26,12 @@ export function flowSpecToManifest(spec, tenantId, applicationId) {
|
|
|
26
26
|
const enumValues = field.type.startsWith('enum(') && field.type.endsWith(')') ? field.type.slice(5, -1).split(',').map(value => value.trim()) : undefined;
|
|
27
27
|
return { name: field.name, type: reference ? 'reference' : enumValues ? 'enum' : field.type, required: !field.optional, ...(reference ? { reference } : {}), ...(enumValues ? { enum_values: enumValues } : {}) };
|
|
28
28
|
};
|
|
29
|
-
|
|
29
|
+
const indexFields = (expression) => {
|
|
30
|
+
const trimmed = expression.trim();
|
|
31
|
+
const match = trimmed.match(/^(?:[A-Za-z_][A-Za-z0-9_]*)?\((.*)\)$/);
|
|
32
|
+
return (match?.[1] ?? trimmed).split(',').map(value => value.trim()).filter(Boolean);
|
|
33
|
+
};
|
|
34
|
+
return { application_id: applicationId, tenant_id: tenantId, schema: 1, metadata: { name: spec.app, labels: {} }, collections: spec.collections.map(value => ({ name: value.name, fields: value.fields.map(manifestField) })), indexes: spec.collections.flatMap(collection => collection.indexes.map(index => ({ name: `${collection.name}.${index.name}`, collection: collection.name, fields: indexFields(index.expression), unique: index.kind === 'unique' }))), references: [], queries: [], actions: [], workflows: spec.workflows.map(value => ({ name: value.name, steps: value.steps.map(step => ({ name: step.name, capability: step.statements.find(statement => statement.startsWith('capability '))?.slice('capability '.length) })) })), triggers: spec.triggers.map((value, index) => ({ name: `trigger-${index + 1}`, event: value.event, workflow: spec.workflows[0]?.name || '' })), schedules: spec.schedules.map(value => ({ name: value.name, expression: value.statements[0] || '', workflow: spec.workflows[0]?.name || '' })), agents: spec.agents.map(value => ({ name: value.name, capabilities: capabilities.map(capability => capability.name).filter(name => value.statements.some(statement => statement.includes(name))) })), capabilities, modules: resolveFeltDBModules(spec.modules), connections: [], policies: spec.policies.map(value => ({ name: value.name, resource: value.name, read: policySubject(value.statements, 'read'), write: policySubject(value.statements, 'write'), capabilities: [] })), ui: { routes: [], bindings: [], forms: [], dashboards: [] }, environments: ['development', 'preview', 'staging', 'production'].map(name => ({ name, configuration: {} })), artifacts: [], deployment: { environments: ['development', 'preview', 'staging', 'production'] }, runtime: { contract: 1, minimum_engine: '0.2.0', maximum_engine_exclusive: '2.0.0' } };
|
|
30
35
|
}
|
|
31
36
|
export function manifestToFlowSpec(manifest) {
|
|
32
37
|
const fieldType = (field) => field.reference ? `ref ${field.reference}` : field.enum_values?.length ? `enum(${field.enum_values.join(',')})` : field.type;
|
package/dist/http-client.d.ts
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* For applications that only need HTTP access without the full core framework.
|
|
6
6
|
*/
|
|
7
7
|
import type { FeltDBProposalEvent, FeltDBProposalPreviewArtifact, FeltDBProposalRecord, ProposalReadiness, ProposalStatus } from './proposal.js';
|
|
8
|
+
import type { ApplicationUnderstanding } from './application-understanding.js';
|
|
9
|
+
import type { ConvergenceResult } from './convergence.js';
|
|
10
|
+
import type { ImplementationPlan, Intent, IntentEvent, IntentExecutionResult } from './intent.js';
|
|
8
11
|
import type { CanonicalQuery, QueryResult, TransactionResult } from './state-contract.js';
|
|
9
12
|
export interface ClientOptions {
|
|
10
13
|
url: string;
|
|
@@ -106,6 +109,20 @@ export declare class FeltDBClient {
|
|
|
106
109
|
readonly capabilities: {
|
|
107
110
|
run: (name: string, input: unknown) => Promise<unknown>;
|
|
108
111
|
};
|
|
112
|
+
/** Canonical intent execution and its durable semantic artifacts. */
|
|
113
|
+
readonly intents: {
|
|
114
|
+
execute: (rawRequest: string) => Promise<IntentExecutionResult>;
|
|
115
|
+
list: () => Promise<{
|
|
116
|
+
intents: Intent[];
|
|
117
|
+
}>;
|
|
118
|
+
get: (id: string) => Promise<Intent>;
|
|
119
|
+
understanding: (id: string) => Promise<ApplicationUnderstanding>;
|
|
120
|
+
plan: (id: string) => Promise<ImplementationPlan>;
|
|
121
|
+
proposal: (id: string) => Promise<FeltDBProposalRecord>;
|
|
122
|
+
history: (id: string) => Promise<{
|
|
123
|
+
events: IntentEvent[];
|
|
124
|
+
}>;
|
|
125
|
+
};
|
|
109
126
|
/** Canonical Proposal lifecycle. Repository application is intentionally absent. */
|
|
110
127
|
readonly proposals: {
|
|
111
128
|
create: (proposal: {
|
|
@@ -117,6 +134,16 @@ export declare class FeltDBClient {
|
|
|
117
134
|
metadata?: Record<string, string>;
|
|
118
135
|
parent_proposal_id?: string;
|
|
119
136
|
expires_at?: string | number;
|
|
137
|
+
contract_diff?: string[];
|
|
138
|
+
source_plan?: {
|
|
139
|
+
files: Array<{
|
|
140
|
+
path: string;
|
|
141
|
+
action: string;
|
|
142
|
+
}>;
|
|
143
|
+
};
|
|
144
|
+
understanding?: ApplicationUnderstanding;
|
|
145
|
+
evidence_hash?: string;
|
|
146
|
+
understanding_hash?: string;
|
|
120
147
|
}) => Promise<FeltDBProposalRecord>;
|
|
121
148
|
list: (options?: {
|
|
122
149
|
status?: ProposalStatus;
|
|
@@ -133,7 +160,7 @@ export declare class FeltDBClient {
|
|
|
133
160
|
history: (id: string) => Promise<{
|
|
134
161
|
events: FeltDBProposalEvent[];
|
|
135
162
|
}>;
|
|
136
|
-
status: (id: string) => Promise<ProposalReadiness>;
|
|
163
|
+
status: (id: string, currentEvidenceHash?: string) => Promise<ProposalReadiness>;
|
|
137
164
|
validate: (id: string, proposedManifest?: unknown) => Promise<FeltDBProposalRecord>;
|
|
138
165
|
createPreview: (id: string) => Promise<FeltDBProposalPreviewArtifact>;
|
|
139
166
|
preview: (previewId: string) => Promise<FeltDBProposalPreviewArtifact>;
|
|
@@ -150,6 +177,10 @@ export declare class FeltDBClient {
|
|
|
150
177
|
}>;
|
|
151
178
|
approve: (id: string, approveAuthorization?: boolean) => Promise<FeltDBProposalRecord>;
|
|
152
179
|
reject: (id: string, reason?: string) => Promise<FeltDBProposalRecord>;
|
|
180
|
+
convergence: (id: string) => Promise<{
|
|
181
|
+
convergence: ConvergenceResult[];
|
|
182
|
+
}>;
|
|
183
|
+
recordConvergence: (id: string, result: ConvergenceResult) => Promise<ConvergenceResult>;
|
|
153
184
|
};
|
|
154
185
|
}
|
|
155
186
|
export declare function createClient(options: ClientOptions): FeltDBClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/http-client.js
CHANGED
|
@@ -99,13 +99,23 @@ export class FeltDBClient {
|
|
|
99
99
|
capabilities = {
|
|
100
100
|
run: (name, input) => this.request(this.scoped(`/v1/capabilities/${encodeURIComponent(name)}/run`), { method: 'POST', body: JSON.stringify(input) }),
|
|
101
101
|
};
|
|
102
|
+
/** Canonical intent execution and its durable semantic artifacts. */
|
|
103
|
+
intents = {
|
|
104
|
+
execute: (rawRequest) => this.request('/v1/intents', { method: 'POST', body: JSON.stringify(this.scopeBody({ raw_request: rawRequest })) }),
|
|
105
|
+
list: () => this.request(this.scoped('/v1/intents')),
|
|
106
|
+
get: (id) => this.request(this.scoped(`/v1/intents/${encodeURIComponent(id)}`)),
|
|
107
|
+
understanding: (id) => this.request(this.scoped(`/v1/intents/${encodeURIComponent(id)}/understanding`)),
|
|
108
|
+
plan: (id) => this.request(this.scoped(`/v1/intents/${encodeURIComponent(id)}/plan`)),
|
|
109
|
+
proposal: (id) => this.request(this.scoped(`/v1/intents/${encodeURIComponent(id)}/proposal`)),
|
|
110
|
+
history: (id) => this.request(this.scoped(`/v1/intents/${encodeURIComponent(id)}/history`)),
|
|
111
|
+
};
|
|
102
112
|
/** Canonical Proposal lifecycle. Repository application is intentionally absent. */
|
|
103
113
|
proposals = {
|
|
104
|
-
create: (proposal) => this.request('/v1/proposals', { method: 'POST', body: JSON.stringify(this.scopeBody(proposal)) }),
|
|
114
|
+
create: (proposal) => this.request('/v1/proposals', { method: 'POST', body: JSON.stringify(this.scopeBody({ proposal_version: 1, contract_diff: [], source_plan: { files: [] }, ...proposal })) }),
|
|
105
115
|
list: (options = {}) => this.request(this.scoped('/v1/proposals', options)),
|
|
106
116
|
get: (id) => this.request(this.scoped(`/v1/proposals/${encodeURIComponent(id)}`)),
|
|
107
117
|
history: (id) => this.request(this.scoped(`/v1/proposals/${encodeURIComponent(id)}/history`)),
|
|
108
|
-
status: (id) => this.request(this.scoped(`/v1/proposals/${encodeURIComponent(id)}/status
|
|
118
|
+
status: (id, currentEvidenceHash) => this.request(this.scoped(`/v1/proposals/${encodeURIComponent(id)}/status`, { current_evidence_hash: currentEvidenceHash })),
|
|
109
119
|
validate: (id, proposedManifest) => this.request(`/v1/proposals/${encodeURIComponent(id)}/validate`, { method: 'POST', body: JSON.stringify(this.scopeBody({ proposed_manifest: proposedManifest })) }),
|
|
110
120
|
createPreview: (id) => this.request(`/v1/proposals/${encodeURIComponent(id)}/preview`, { method: 'POST', body: JSON.stringify(this.scopeBody()) }),
|
|
111
121
|
preview: (previewId) => this.request(this.scoped(`/v1/previews/${encodeURIComponent(previewId)}`)),
|
|
@@ -113,6 +123,8 @@ export class FeltDBClient {
|
|
|
113
123
|
simulatePreview: (previewId, event) => this.request(this.scoped(`/v1/previews/${encodeURIComponent(previewId)}/simulate`), { method: 'POST', body: JSON.stringify({ event }) }),
|
|
114
124
|
approve: (id, approveAuthorization = false) => this.request(`/v1/proposals/${encodeURIComponent(id)}/approve`, { method: 'POST', body: JSON.stringify(this.scopeBody({ approve_authorization: approveAuthorization })) }),
|
|
115
125
|
reject: (id, reason) => this.request(`/v1/proposals/${encodeURIComponent(id)}/reject`, { method: 'POST', body: JSON.stringify(this.scopeBody({ reason })) }),
|
|
126
|
+
convergence: (id) => this.request(this.scoped(`/v1/proposals/${encodeURIComponent(id)}/convergence`)),
|
|
127
|
+
recordConvergence: (id, result) => this.request(`/v1/proposals/${encodeURIComponent(id)}/convergence`, { method: 'POST', body: JSON.stringify(this.scopeBody(result)) }),
|
|
116
128
|
};
|
|
117
129
|
}
|
|
118
130
|
export function createClient(options) {
|