@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.
Files changed (126) hide show
  1. package/dist/agent-runtime.d.ts +64 -2
  2. package/dist/agent-runtime.d.ts.map +1 -1
  3. package/dist/agent-runtime.js +121 -11
  4. package/dist/agent-state.d.ts +48 -0
  5. package/dist/agent-state.d.ts.map +1 -1
  6. package/dist/agent-state.js +174 -12
  7. package/dist/agent.d.ts +10 -1
  8. package/dist/agent.d.ts.map +1 -1
  9. package/dist/agent.js +10 -1
  10. package/dist/build-identity.json +4 -4
  11. package/dist/cli/commands.js +34 -7
  12. package/dist/cli/workspace-integration.js +8 -0
  13. package/dist/collection.d.ts +3 -1
  14. package/dist/collection.d.ts.map +1 -1
  15. package/dist/collection.js +30 -8
  16. package/dist/create/build-identity.json +4 -4
  17. package/dist/create/cli.js +47 -38
  18. package/dist/create/create.js +21 -8
  19. package/dist/create/package-versions.js +1 -1
  20. package/dist/create/server-source/Cargo.lock +6 -6
  21. package/dist/create/server-source/Cargo.toml +1 -1
  22. package/dist/create/server-source/crates/feltdb/src/lib.rs +126 -35
  23. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +162 -53
  24. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +341 -2
  25. package/dist/create/server-source/crates/feltdb/src/workload.rs +2094 -126
  26. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +18 -12
  27. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +17 -5
  28. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
  29. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
  30. package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
  31. package/dist/create/server-source/crates/feltdb-server/src/agent_execution.rs +511 -0
  32. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
  33. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +113 -25
  34. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
  35. package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
  36. package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
  37. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
  38. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
  39. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +4 -0
  40. package/dist/create/server-source/crates/feltdb-server/src/main.rs +1740 -236
  41. package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
  42. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
  43. package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
  44. package/dist/create/setup-summary.js +40 -0
  45. package/dist/db.d.ts +91 -10
  46. package/dist/db.d.ts.map +1 -1
  47. package/dist/db.js +170 -31
  48. package/dist/deployment.d.ts +19 -0
  49. package/dist/deployment.d.ts.map +1 -1
  50. package/dist/deployment.js +38 -2
  51. package/dist/development-runtime-bridge.d.ts +20 -0
  52. package/dist/development-runtime-bridge.d.ts.map +1 -1
  53. package/dist/development-runtime-bridge.js +61 -12
  54. package/dist/embedded-query.d.ts.map +1 -1
  55. package/dist/embedded-query.js +5 -4
  56. package/dist/embedded-transaction.d.ts +8 -4
  57. package/dist/embedded-transaction.d.ts.map +1 -1
  58. package/dist/embedded-transaction.js +55 -19
  59. package/dist/error-codes.d.ts +31 -2
  60. package/dist/error-codes.d.ts.map +1 -1
  61. package/dist/error-codes.js +41 -2
  62. package/dist/feltdb.d.ts +7 -0
  63. package/dist/feltdb.d.ts.map +1 -1
  64. package/dist/file-db.d.ts +27 -0
  65. package/dist/file-db.d.ts.map +1 -1
  66. package/dist/file-db.js +145 -7
  67. package/dist/http-client.d.ts +11 -3
  68. package/dist/http-client.d.ts.map +1 -1
  69. package/dist/http-client.js +27 -14
  70. package/dist/http-db.d.ts +40 -1
  71. package/dist/http-db.d.ts.map +1 -1
  72. package/dist/http-db.js +285 -58
  73. package/dist/index.js +1 -1
  74. package/dist/local-state-lock.d.ts +34 -0
  75. package/dist/local-state-lock.d.ts.map +1 -0
  76. package/dist/local-state-lock.js +225 -0
  77. package/dist/reactive-graph.d.ts +0 -3
  78. package/dist/reactive-graph.d.ts.map +1 -1
  79. package/dist/reactive-graph.js +11 -1
  80. package/dist/runtime-registry.d.ts +7 -2
  81. package/dist/runtime-registry.d.ts.map +1 -1
  82. package/dist/runtime-registry.js +2 -2
  83. package/dist/studio/{KeyManagementPanel-D5FMvvU9.js → KeyManagementPanel-skUNnKRw.js} +36 -29
  84. package/dist/studio/app.d.ts +8 -1
  85. package/dist/studio/app.d.ts.map +1 -1
  86. package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -1
  87. package/dist/studio/components/KeyManagementPanel.js +1 -1
  88. package/dist/studio/components/index.js +2 -2
  89. package/dist/studio/{components-B4eKIUN5.js → components-CJmzntBi.js} +8 -7
  90. package/dist/studio/control-plane/Data.d.ts.map +1 -1
  91. package/dist/studio/control-plane/Instance.d.ts +4 -1
  92. package/dist/studio/control-plane/Instance.d.ts.map +1 -1
  93. package/dist/studio/control-plane/Operations.d.ts +4 -1
  94. package/dist/studio/control-plane/Operations.d.ts.map +1 -1
  95. package/dist/studio/control-plane/index.js +2 -2
  96. package/dist/studio/control-plane/primitives.d.ts +16 -0
  97. package/dist/studio/control-plane/primitives.d.ts.map +1 -1
  98. package/dist/studio/{control-plane-fxMcJn74.js → control-plane-CaBA7Rgv.js} +448 -424
  99. package/dist/studio/index.d.ts +1 -0
  100. package/dist/studio/index.d.ts.map +1 -1
  101. package/dist/studio/index.js +384 -247
  102. package/dist/studio/navigation.d.ts +57 -0
  103. package/dist/studio/navigation.d.ts.map +1 -0
  104. package/dist/studio/studio.css +1 -1
  105. package/dist/studio/utils/control-plane-api.d.ts +2 -0
  106. package/dist/studio/utils/control-plane-api.d.ts.map +1 -1
  107. package/dist/studio/utils/control-plane-api.js +5 -1
  108. package/dist/studio-app/assets/{feltdb_wasm-BatwwogY.js → feltdb_wasm-BjM1ylL3.js} +1 -1
  109. package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
  110. package/dist/studio-app/assets/index-1wd0uKua.js +30 -0
  111. package/dist/studio-app/assets/{index-CiC8VY-a.css → index-vi21oEQa.css} +1 -1
  112. package/dist/studio-app/index.html +2 -2
  113. package/dist/transaction.d.ts +27 -11
  114. package/dist/transaction.d.ts.map +1 -1
  115. package/dist/transaction.js +20 -14
  116. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  117. package/dist/wasm/package.json +1 -1
  118. package/dist/workload.d.ts +31 -3
  119. package/dist/workload.d.ts.map +1 -1
  120. package/dist/workload.js +28 -3
  121. package/dist/workspace/local-development-authority.d.ts +19 -0
  122. package/dist/workspace/local-development-authority.d.ts.map +1 -1
  123. package/dist/workspace/local-development-authority.js +335 -15
  124. package/package.json +1 -1
  125. package/dist/studio-app/assets/feltdb_wasm_bg-BX0newOr.wasm +0 -0
  126. 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 secret: String = rand::thread_rng()
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(ApiKeyRecord {
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(CreatedApiKey { id, secret: token })
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
  ]