@feltdb/core 0.12.2 → 0.15.0
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/agent-runtime.d.ts +64 -2
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +121 -11
- package/dist/agent-state.d.ts +48 -0
- package/dist/agent-state.d.ts.map +1 -1
- package/dist/agent-state.js +174 -12
- package/dist/agent.d.ts +10 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +10 -1
- package/dist/build-identity.json +4 -4
- package/dist/cli/commands.js +34 -7
- package/dist/cli/workspace-integration.js +8 -0
- package/dist/collection.d.ts +3 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +30 -8
- package/dist/create/build-identity.json +4 -4
- package/dist/create/cli.js +47 -38
- package/dist/create/create.js +21 -8
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +6 -6
- package/dist/create/server-source/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb/src/lib.rs +126 -35
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +162 -53
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +341 -2
- package/dist/create/server-source/crates/feltdb/src/workload.rs +2094 -126
- package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +18 -12
- package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +17 -5
- package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
- package/dist/create/server-source/crates/feltdb-server/src/agent_execution.rs +511 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +113 -25
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
- package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
- package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +4 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +1740 -236
- package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
- package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
- package/dist/create/setup-summary.js +40 -0
- package/dist/db.d.ts +91 -10
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +170 -31
- package/dist/deployment.d.ts +19 -0
- package/dist/deployment.d.ts.map +1 -1
- package/dist/deployment.js +38 -2
- package/dist/development-runtime-bridge.d.ts +20 -0
- package/dist/development-runtime-bridge.d.ts.map +1 -1
- package/dist/development-runtime-bridge.js +61 -12
- package/dist/embedded-query.d.ts.map +1 -1
- package/dist/embedded-query.js +5 -4
- package/dist/embedded-transaction.d.ts +8 -4
- package/dist/embedded-transaction.d.ts.map +1 -1
- package/dist/embedded-transaction.js +55 -19
- package/dist/error-codes.d.ts +31 -2
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +41 -2
- package/dist/feltdb.d.ts +7 -0
- package/dist/feltdb.d.ts.map +1 -1
- package/dist/file-db.d.ts +27 -0
- package/dist/file-db.d.ts.map +1 -1
- package/dist/file-db.js +145 -7
- package/dist/http-client.d.ts +11 -3
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +27 -14
- package/dist/http-db.d.ts +40 -1
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +285 -58
- package/dist/index.js +1 -1
- package/dist/local-state-lock.d.ts +34 -0
- package/dist/local-state-lock.d.ts.map +1 -0
- package/dist/local-state-lock.js +225 -0
- package/dist/reactive-graph.d.ts +0 -3
- package/dist/reactive-graph.d.ts.map +1 -1
- package/dist/reactive-graph.js +11 -1
- package/dist/runtime-registry.d.ts +7 -2
- package/dist/runtime-registry.d.ts.map +1 -1
- package/dist/runtime-registry.js +2 -2
- package/dist/studio/{KeyManagementPanel-D5FMvvU9.js → KeyManagementPanel-skUNnKRw.js} +36 -29
- package/dist/studio/app.d.ts +8 -1
- package/dist/studio/app.d.ts.map +1 -1
- package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -1
- package/dist/studio/components/KeyManagementPanel.js +1 -1
- package/dist/studio/components/index.js +2 -2
- package/dist/studio/{components-B4eKIUN5.js → components-CJmzntBi.js} +8 -7
- package/dist/studio/control-plane/Data.d.ts.map +1 -1
- package/dist/studio/control-plane/Instance.d.ts +4 -1
- package/dist/studio/control-plane/Instance.d.ts.map +1 -1
- package/dist/studio/control-plane/Operations.d.ts +4 -1
- package/dist/studio/control-plane/Operations.d.ts.map +1 -1
- package/dist/studio/control-plane/index.js +2 -2
- package/dist/studio/control-plane/primitives.d.ts +16 -0
- package/dist/studio/control-plane/primitives.d.ts.map +1 -1
- package/dist/studio/{control-plane-fxMcJn74.js → control-plane-CaBA7Rgv.js} +448 -424
- package/dist/studio/index.d.ts +1 -0
- package/dist/studio/index.d.ts.map +1 -1
- package/dist/studio/index.js +384 -247
- package/dist/studio/navigation.d.ts +57 -0
- package/dist/studio/navigation.d.ts.map +1 -0
- package/dist/studio/studio.css +1 -1
- package/dist/studio/utils/control-plane-api.d.ts +2 -0
- package/dist/studio/utils/control-plane-api.d.ts.map +1 -1
- package/dist/studio/utils/control-plane-api.js +5 -1
- package/dist/studio-app/assets/{feltdb_wasm-BatwwogY.js → feltdb_wasm-BjM1ylL3.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
- package/dist/studio-app/assets/index-1wd0uKua.js +30 -0
- package/dist/studio-app/assets/{index-CiC8VY-a.css → index-vi21oEQa.css} +1 -1
- package/dist/studio-app/index.html +2 -2
- package/dist/transaction.d.ts +27 -11
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +20 -14
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/wasm/package.json +1 -1
- package/dist/workload.d.ts +31 -3
- package/dist/workload.d.ts.map +1 -1
- package/dist/workload.js +28 -3
- package/dist/workspace/local-development-authority.d.ts +19 -0
- package/dist/workspace/local-development-authority.d.ts.map +1 -1
- package/dist/workspace/local-development-authority.js +335 -15
- package/package.json +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-BX0newOr.wasm +0 -0
- package/dist/studio-app/assets/index-DoVvbIay.js +0 -30
|
@@ -181,6 +181,34 @@ impl KeyStore {
|
|
|
181
181
|
})
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/// The current scopes and subject type of an active key, by id.
|
|
185
|
+
///
|
|
186
|
+
/// Work executed after its request — an autonomous run — re-reads its
|
|
187
|
+
/// principal here, so a key revoked or narrowed since the run was created
|
|
188
|
+
/// is not honoured at its old breadth. `None` when the key is unknown,
|
|
189
|
+
/// revoked, or not valid for `namespace`.
|
|
190
|
+
pub fn active_scopes(&self, key_id: &str, namespace: &str) -> Option<(Vec<String>, String)> {
|
|
191
|
+
let records = self.records.read().ok()?;
|
|
192
|
+
records
|
|
193
|
+
.iter()
|
|
194
|
+
.find(|record| {
|
|
195
|
+
record.id == key_id
|
|
196
|
+
&& !record.revoked
|
|
197
|
+
&& record
|
|
198
|
+
.namespaces
|
|
199
|
+
.iter()
|
|
200
|
+
.any(|allowed| allowed == "*" || allowed == namespace)
|
|
201
|
+
})
|
|
202
|
+
.map(|record| {
|
|
203
|
+
let kind = if record.worker_id.is_some() {
|
|
204
|
+
"worker"
|
|
205
|
+
} else {
|
|
206
|
+
"service"
|
|
207
|
+
};
|
|
208
|
+
(record.scopes.clone(), kind.to_string())
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
184
212
|
pub fn create(
|
|
185
213
|
&self,
|
|
186
214
|
name: String,
|
|
@@ -202,35 +230,13 @@ impl KeyStore {
|
|
|
202
230
|
namespaces: Vec<String>,
|
|
203
231
|
worker_id: Option<String>,
|
|
204
232
|
) -> Result<CreatedApiKey, String> {
|
|
205
|
-
let
|
|
206
|
-
.sample_iter(&Alphanumeric)
|
|
207
|
-
.take(48)
|
|
208
|
-
.map(char::from)
|
|
209
|
-
.collect();
|
|
210
|
-
let token = format!("fdb_live_{secret}");
|
|
211
|
-
// Service keys are high-entropy random secrets, not user-selected
|
|
212
|
-
// passwords. A deterministic digest keeps them out of the credential
|
|
213
|
-
// store without imposing Argon2's CPU cost on every API request.
|
|
214
|
-
let hash = hash_api_key(&token);
|
|
215
|
-
let id: String = rand::thread_rng()
|
|
216
|
-
.sample_iter(&Alphanumeric)
|
|
217
|
-
.take(12)
|
|
218
|
-
.map(char::from)
|
|
219
|
-
.collect();
|
|
233
|
+
let (record, created) = new_record(name, scopes, namespaces, worker_id);
|
|
220
234
|
self.records
|
|
221
235
|
.write()
|
|
222
236
|
.map_err(|_| "API key store lock poisoned".to_string())?
|
|
223
|
-
.push(
|
|
224
|
-
id: id.clone(),
|
|
225
|
-
name,
|
|
226
|
-
hash,
|
|
227
|
-
scopes,
|
|
228
|
-
namespaces,
|
|
229
|
-
revoked: false,
|
|
230
|
-
worker_id,
|
|
231
|
-
});
|
|
237
|
+
.push(record);
|
|
232
238
|
self.persist()?;
|
|
233
|
-
Ok(
|
|
239
|
+
Ok(created)
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
pub fn list(&self) -> Result<Vec<ApiKeySummary>, String> {
|
|
@@ -249,6 +255,46 @@ impl KeyStore {
|
|
|
249
255
|
.collect())
|
|
250
256
|
}
|
|
251
257
|
|
|
258
|
+
/// The listing entry of one key — never its secret or digest.
|
|
259
|
+
pub fn summary(&self, id: &str) -> Option<ApiKeySummary> {
|
|
260
|
+
self.list()
|
|
261
|
+
.ok()?
|
|
262
|
+
.into_iter()
|
|
263
|
+
.find(|summary| summary.id == id)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// Replace a key: issue a new secret with the same name, scopes, namespaces
|
|
267
|
+
/// and worker identity, and revoke the old key in the same store write.
|
|
268
|
+
///
|
|
269
|
+
/// The new secret is returned once and is never stored or listed. `None`
|
|
270
|
+
/// when no active key has this id.
|
|
271
|
+
pub fn rotate(&self, id: &str) -> Result<Option<CreatedApiKey>, String> {
|
|
272
|
+
let created = {
|
|
273
|
+
let mut records = self
|
|
274
|
+
.records
|
|
275
|
+
.write()
|
|
276
|
+
.map_err(|_| "API key store lock poisoned".to_string())?;
|
|
277
|
+
let Some(old) = records
|
|
278
|
+
.iter_mut()
|
|
279
|
+
.find(|record| record.id == id && !record.revoked)
|
|
280
|
+
else {
|
|
281
|
+
return Ok(None);
|
|
282
|
+
};
|
|
283
|
+
old.revoked = true;
|
|
284
|
+
let (name, scopes, namespaces, worker_id) = (
|
|
285
|
+
old.name.clone(),
|
|
286
|
+
old.scopes.clone(),
|
|
287
|
+
old.namespaces.clone(),
|
|
288
|
+
old.worker_id.clone(),
|
|
289
|
+
);
|
|
290
|
+
let (record, created) = new_record(name, scopes, namespaces, worker_id);
|
|
291
|
+
records.push(record);
|
|
292
|
+
created
|
|
293
|
+
};
|
|
294
|
+
self.persist()?;
|
|
295
|
+
Ok(Some(created))
|
|
296
|
+
}
|
|
297
|
+
|
|
252
298
|
pub fn revoke(&self, id: &str) -> Result<bool, String> {
|
|
253
299
|
let found = {
|
|
254
300
|
let mut records = self
|
|
@@ -280,6 +326,13 @@ impl KeyStore {
|
|
|
280
326
|
.map_err(|_| "API key store lock poisoned".to_string())?;
|
|
281
327
|
let bytes = serde_json::to_vec_pretty(&*records).map_err(|error| error.to_string())?;
|
|
282
328
|
fs::write(&temporary, bytes).map_err(|error| error.to_string())?;
|
|
329
|
+
// Digests, not secrets, but still credential material: owner-only.
|
|
330
|
+
#[cfg(unix)]
|
|
331
|
+
{
|
|
332
|
+
use std::os::unix::fs::PermissionsExt;
|
|
333
|
+
fs::set_permissions(&temporary, fs::Permissions::from_mode(0o600))
|
|
334
|
+
.map_err(|error| error.to_string())?;
|
|
335
|
+
}
|
|
283
336
|
fs::rename(&temporary, &self.path).map_err(|error| error.to_string())?;
|
|
284
337
|
Ok(())
|
|
285
338
|
}
|
|
@@ -289,6 +342,41 @@ impl KeyStore {
|
|
|
289
342
|
}
|
|
290
343
|
}
|
|
291
344
|
|
|
345
|
+
fn new_record(
|
|
346
|
+
name: String,
|
|
347
|
+
scopes: Vec<String>,
|
|
348
|
+
namespaces: Vec<String>,
|
|
349
|
+
worker_id: Option<String>,
|
|
350
|
+
) -> (ApiKeyRecord, CreatedApiKey) {
|
|
351
|
+
let secret: String = rand::thread_rng()
|
|
352
|
+
.sample_iter(&Alphanumeric)
|
|
353
|
+
.take(48)
|
|
354
|
+
.map(char::from)
|
|
355
|
+
.collect();
|
|
356
|
+
let token = format!("fdb_live_{secret}");
|
|
357
|
+
// Service keys are high-entropy random secrets, not user-selected
|
|
358
|
+
// passwords. A deterministic digest keeps them out of the credential
|
|
359
|
+
// store without imposing Argon2's CPU cost on every API request.
|
|
360
|
+
let hash = hash_api_key(&token);
|
|
361
|
+
let id: String = rand::thread_rng()
|
|
362
|
+
.sample_iter(&Alphanumeric)
|
|
363
|
+
.take(12)
|
|
364
|
+
.map(char::from)
|
|
365
|
+
.collect();
|
|
366
|
+
(
|
|
367
|
+
ApiKeyRecord {
|
|
368
|
+
id: id.clone(),
|
|
369
|
+
name,
|
|
370
|
+
hash,
|
|
371
|
+
scopes,
|
|
372
|
+
namespaces,
|
|
373
|
+
revoked: false,
|
|
374
|
+
worker_id,
|
|
375
|
+
},
|
|
376
|
+
CreatedApiKey { id, secret: token },
|
|
377
|
+
)
|
|
378
|
+
}
|
|
379
|
+
|
|
292
380
|
fn hash_api_key(token: &str) -> String {
|
|
293
381
|
let digest = Sha256::digest(token.as_bytes());
|
|
294
382
|
let encoded = digest
|
|
@@ -166,6 +166,10 @@ pub fn server_artifacts(data: &Path, keys: &Path, audit: &Path) -> Vec<(String,
|
|
|
166
166
|
"revoked-sessions.json".into(),
|
|
167
167
|
data.with_extension("revoked-sessions.json"),
|
|
168
168
|
),
|
|
169
|
+
(
|
|
170
|
+
"console-accounts.json".into(),
|
|
171
|
+
data.with_extension("console-accounts.json"),
|
|
172
|
+
),
|
|
169
173
|
("api-keys.json".into(), keys.to_path_buf()),
|
|
170
174
|
("audit.log".into(), audit.to_path_buf()),
|
|
171
175
|
]
|