@feltdb/core 0.13.0 → 0.16.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 (300) 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 +68 -0
  5. package/dist/agent-state.d.ts.map +1 -1
  6. package/dist/agent-state.js +210 -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 +12 -4
  11. package/dist/cli/commands.js +214 -10
  12. package/dist/cli/publish-engine.js +116 -16
  13. package/dist/collection.d.ts +3 -1
  14. package/dist/collection.d.ts.map +1 -1
  15. package/dist/collection.js +33 -8
  16. package/dist/create/build-identity.json +12 -4
  17. package/dist/create/cli.js +1 -1
  18. package/dist/create/create.js +4 -6
  19. package/dist/create/managed-account.js +93 -35
  20. package/dist/create/package-versions.js +1 -1
  21. package/dist/create/server-source/Cargo.lock +8 -511
  22. package/dist/create/server-source/Cargo.toml +2 -13
  23. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
  24. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
  25. package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
  26. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
  27. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +85 -25
  28. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
  29. package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
  30. package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
  31. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
  32. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
  33. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +3 -0
  34. package/dist/create/server-source/crates/feltdb-server/src/main.rs +1134 -96
  35. package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
  36. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
  37. package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
  38. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +1 -1
  39. package/dist/db.d.ts +75 -10
  40. package/dist/db.d.ts.map +1 -1
  41. package/dist/db.js +168 -29
  42. package/dist/deployment.d.ts +19 -0
  43. package/dist/deployment.d.ts.map +1 -1
  44. package/dist/deployment.js +38 -2
  45. package/dist/embedded-query.d.ts.map +1 -1
  46. package/dist/embedded-query.js +5 -4
  47. package/dist/embedded-transaction.d.ts +8 -4
  48. package/dist/embedded-transaction.d.ts.map +1 -1
  49. package/dist/embedded-transaction.js +55 -19
  50. package/dist/error-codes.d.ts +36 -2
  51. package/dist/error-codes.d.ts.map +1 -1
  52. package/dist/error-codes.js +50 -3
  53. package/dist/feltdb.d.ts +7 -0
  54. package/dist/feltdb.d.ts.map +1 -1
  55. package/dist/file-db.d.ts +27 -0
  56. package/dist/file-db.d.ts.map +1 -1
  57. package/dist/file-db.js +145 -7
  58. package/dist/http-client.d.ts +11 -3
  59. package/dist/http-client.d.ts.map +1 -1
  60. package/dist/http-client.js +27 -14
  61. package/dist/http-db.d.ts +43 -1
  62. package/dist/http-db.d.ts.map +1 -1
  63. package/dist/http-db.js +287 -59
  64. package/dist/index.js +1 -1
  65. package/dist/local-state-lock.d.ts +34 -0
  66. package/dist/local-state-lock.d.ts.map +1 -0
  67. package/dist/local-state-lock.js +225 -0
  68. package/dist/managed-recovery.d.ts +6 -0
  69. package/dist/managed-recovery.d.ts.map +1 -1
  70. package/dist/managed-recovery.js +9 -0
  71. package/dist/reactive-graph.d.ts +0 -3
  72. package/dist/reactive-graph.d.ts.map +1 -1
  73. package/dist/reactive-graph.js +11 -1
  74. package/dist/runtime-registry.d.ts +7 -2
  75. package/dist/runtime-registry.d.ts.map +1 -1
  76. package/dist/runtime-registry.js +2 -2
  77. package/dist/studio/components/index.js +1 -1
  78. package/dist/studio/{components-BSGmHfif.js → components-CJmzntBi.js} +2 -1
  79. package/dist/studio/index.js +1 -1
  80. package/dist/studio-app/assets/{feltdb_wasm-3hDngl1h.js → feltdb_wasm-DtybUY0q.js} +1 -1
  81. package/dist/studio-app/assets/feltdb_wasm_bg-DsgIUwaB.wasm +0 -0
  82. package/dist/studio-app/assets/index-C4OffsZl.js +37 -0
  83. package/dist/studio-app/index.html +1 -1
  84. package/dist/transaction.d.ts +27 -11
  85. package/dist/transaction.d.ts.map +1 -1
  86. package/dist/transaction.js +20 -14
  87. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  88. package/dist/wasm/package.json +1 -1
  89. package/dist/workload.d.ts +86 -6
  90. package/dist/workload.d.ts.map +1 -1
  91. package/dist/workload.js +51 -3
  92. package/dist/workspace/workspace-connection.d.ts.map +1 -1
  93. package/dist/workspace/workspace-connection.js +14 -3
  94. package/package.json +1 -1
  95. package/dist/create/server-source/crates/feltdb/Cargo.lock +0 -175
  96. package/dist/create/server-source/crates/feltdb/Cargo.toml +0 -102
  97. package/dist/create/server-source/crates/feltdb/LICENSE +0 -21
  98. package/dist/create/server-source/crates/feltdb/README.md +0 -75
  99. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +0 -370
  100. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +0 -589
  101. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +0 -247
  102. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +0 -440
  103. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +0 -275
  104. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +0 -381
  105. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +0 -467
  106. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +0 -489
  107. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +0 -281
  108. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +0 -606
  109. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +0 -531
  110. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +0 -462
  111. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +0 -505
  112. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +0 -484
  113. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +0 -758
  114. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +0 -421
  115. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +0 -329
  116. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +0 -1705
  117. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +0 -286
  118. package/dist/create/server-source/crates/feltdb/src/admission.rs +0 -185
  119. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +0 -507
  120. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +0 -539
  121. package/dist/create/server-source/crates/feltdb/src/agent_state.rs +0 -320
  122. package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +0 -1545
  123. package/dist/create/server-source/crates/feltdb/src/analytics.rs +0 -521
  124. package/dist/create/server-source/crates/feltdb/src/application.rs +0 -2674
  125. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +0 -1070
  126. package/dist/create/server-source/crates/feltdb/src/authority.rs +0 -479
  127. package/dist/create/server-source/crates/feltdb/src/authority_failover.rs +0 -847
  128. package/dist/create/server-source/crates/feltdb/src/authorization.rs +0 -1030
  129. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +0 -1122
  130. package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority-client.rs +0 -32
  131. package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority.rs +0 -19
  132. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +0 -1474
  133. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +0 -8
  134. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +0 -418
  135. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +0 -482
  136. package/dist/create/server-source/crates/feltdb/src/capability.rs +0 -903
  137. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +0 -263
  138. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -77
  139. package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +0 -496
  140. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +0 -2574
  141. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +0 -212
  142. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +0 -422
  143. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +0 -445
  144. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +0 -465
  145. package/dist/create/server-source/crates/feltdb/src/convergence.rs +0 -634
  146. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +0 -427
  147. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +0 -376
  148. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +0 -365
  149. package/dist/create/server-source/crates/feltdb/src/cron.rs +0 -294
  150. package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +0 -483
  151. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +0 -477
  152. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +0 -1003
  153. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +0 -1334
  154. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +0 -368
  155. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +0 -231
  156. package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +0 -482
  157. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +0 -203
  158. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +0 -317
  159. package/dist/create/server-source/crates/feltdb/src/equality_index.rs +0 -595
  160. package/dist/create/server-source/crates/feltdb/src/execution.rs +0 -426
  161. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +0 -214
  162. package/dist/create/server-source/crates/feltdb/src/indexing.rs +0 -776
  163. package/dist/create/server-source/crates/feltdb/src/lib.rs +0 -7274
  164. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +0 -234
  165. package/dist/create/server-source/crates/feltdb/src/materialization.rs +0 -184
  166. package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -266
  167. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +0 -310
  168. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +0 -736
  169. package/dist/create/server-source/crates/feltdb/src/observability.rs +0 -379
  170. package/dist/create/server-source/crates/feltdb/src/operation.rs +0 -290
  171. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +0 -439
  172. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +0 -349
  173. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +0 -332
  174. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +0 -718
  175. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +0 -487
  176. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +0 -166
  177. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +0 -289
  178. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +0 -566
  179. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +0 -3391
  180. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +0 -203
  181. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +0 -261
  182. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +0 -502
  183. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +0 -216
  184. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +0 -303
  185. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +0 -323
  186. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +0 -531
  187. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +0 -406
  188. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +0 -436
  189. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +0 -387
  190. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +0 -378
  191. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +0 -359
  192. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +0 -372
  193. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +0 -404
  194. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +0 -376
  195. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +0 -461
  196. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +0 -2125
  197. package/dist/create/server-source/crates/feltdb/src/production_api.rs +0 -418
  198. package/dist/create/server-source/crates/feltdb/src/provenance.rs +0 -207
  199. package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +0 -126
  200. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +0 -218
  201. package/dist/create/server-source/crates/feltdb/src/read_basis.rs +0 -257
  202. package/dist/create/server-source/crates/feltdb/src/references.rs +0 -404
  203. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +0 -401
  204. package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +0 -501
  205. package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +0 -680
  206. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +0 -163
  207. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +0 -133
  208. package/dist/create/server-source/crates/feltdb/src/routing.rs +0 -409
  209. package/dist/create/server-source/crates/feltdb/src/semantic_decision.rs +0 -2029
  210. package/dist/create/server-source/crates/feltdb/src/semantic_query.rs +0 -599
  211. package/dist/create/server-source/crates/feltdb/src/sharding.rs +0 -549
  212. package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +0 -516
  213. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +0 -5894
  214. package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +0 -222
  215. package/dist/create/server-source/crates/feltdb/src/state_facade.rs +0 -320
  216. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +0 -291
  217. package/dist/create/server-source/crates/feltdb/src/state_model.rs +0 -4158
  218. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +0 -379
  219. package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +0 -673
  220. package/dist/create/server-source/crates/feltdb/src/storage.rs +0 -273
  221. package/dist/create/server-source/crates/feltdb/src/submission.rs +0 -471
  222. package/dist/create/server-source/crates/feltdb/src/sync.rs +0 -495
  223. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +0 -822
  224. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +0 -433
  225. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +0 -462
  226. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +0 -965
  227. package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +0 -1120
  228. package/dist/create/server-source/crates/feltdb/src/transactions.rs +0 -643
  229. package/dist/create/server-source/crates/feltdb/src/trigger.rs +0 -390
  230. package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +0 -749
  231. package/dist/create/server-source/crates/feltdb/src/versioned_object_substrate.rs +0 -708
  232. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +0 -1133
  233. package/dist/create/server-source/crates/feltdb/src/workflow.rs +0 -713
  234. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +0 -510
  235. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +0 -354
  236. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +0 -594
  237. package/dist/create/server-source/crates/feltdb/src/workload.rs +0 -2886
  238. package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +0 -456
  239. package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +0 -1188
  240. package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +0 -2884
  241. package/dist/create/server-source/crates/feltdb/tests/authority_process.rs +0 -297
  242. package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +0 -534
  243. package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +0 -132
  244. package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +0 -299
  245. package/dist/create/server-source/crates/feltdb/tests/common/mod.rs +0 -96
  246. package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +0 -272
  247. package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +0 -467
  248. package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +0 -309
  249. package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +0 -445
  250. package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +0 -518
  251. package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +0 -392
  252. package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +0 -850
  253. package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +0 -23340
  254. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +0 -1916
  255. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +0 -1878
  256. package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +0 -1862
  257. package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_evidence.rs +0 -123
  258. package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_substrate_completion.rs +0 -299
  259. package/dist/create/server-source/crates/feltdb/tests/local_process_ownership.rs +0 -69
  260. package/dist/create/server-source/crates/feltdb/tests/managed_incident_regression.rs +0 -191
  261. package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +0 -278
  262. package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +0 -234
  263. package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +0 -947
  264. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +0 -404
  265. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +0 -916
  266. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +0 -1045
  267. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +0 -347
  268. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +0 -361
  269. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +0 -330
  270. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +0 -93
  271. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +0 -622
  272. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +0 -517
  273. package/dist/create/server-source/crates/feltdb/tests/production_certification.rs +0 -1153
  274. package/dist/create/server-source/crates/feltdb/tests/production_contract.rs +0 -771
  275. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +0 -1383
  276. package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +0 -868
  277. package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +0 -221
  278. package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +0 -417
  279. package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +0 -338
  280. package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +0 -1039
  281. package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +0 -739
  282. package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +0 -452
  283. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +0 -81
  284. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +0 -438
  285. package/dist/create/server-source/crates/feltdb/tests/semantic_decision.rs +0 -1165
  286. package/dist/create/server-source/crates/feltdb/tests/semantic_query.rs +0 -767
  287. package/dist/create/server-source/crates/feltdb/tests/semantic_query_contract.rs +0 -363
  288. package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +0 -1799
  289. package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +0 -1316
  290. package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +0 -358
  291. package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +0 -365
  292. package/dist/create/server-source/crates/feltdb/tests/state_ref_authority.rs +0 -918
  293. package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +0 -299
  294. package/dist/create/server-source/crates/feltdb/tests/storage_independent_versioned_object_substrate.rs +0 -328
  295. package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +0 -255
  296. package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +0 -249
  297. package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +0 -994
  298. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +0 -484
  299. package/dist/studio-app/assets/feltdb_wasm_bg-CFQT4gCy.wasm +0 -0
  300. package/dist/studio-app/assets/index-Dql1hS5m.js +0 -30
package/dist/http-db.js CHANGED
@@ -1,6 +1,111 @@
1
1
  import { FeltDBErrorCode, FeltDBServiceError } from './error-codes.js';
2
+ import { assertBrowserSafeCredential } from './deployment.js';
2
3
  import { conditionalRefusal } from './transaction.js';
3
4
  import { BoundedBackoff, SingleFlightValue, cancellableDelay, describeFailure, } from './managed-recovery.js';
5
+ /** The origin of a URL, without any userinfo, for messages. */
6
+ function displayOrigin(url) {
7
+ try {
8
+ return new URL(url).origin;
9
+ }
10
+ catch {
11
+ return url.replace(/\/\/[^@/]*@/, '//');
12
+ }
13
+ }
14
+ const AUTHENTICATION_CODES = new Set(['AUTHENTICATION_REQUIRED', 'AUTHENTICATION_FAILED', 'UNAUTHORIZED', 'UNAUTHENTICATED']);
15
+ const LOAD_CODES = new Set(['SERVICE_OVERLOADED', 'TOO_BUSY', 'RATE_LIMITED', 'TOO_MANY_REQUESTS', 'QUERY_LIMIT_EXCEEDED']);
16
+ /**
17
+ * What to do next about a refusal the authority answered, or undefined when
18
+ * the authority's own message already says it. The code is never changed;
19
+ * this only adds the remedy a developer would otherwise have to look up.
20
+ */
21
+ function refusalRemedy(code, status, message, context) {
22
+ const application = context.applicationId ? `application "${context.applicationId}"` : 'this authority';
23
+ const environment = context.environment ?? 'production';
24
+ if (code === 'AUTHORITY_SCOPE_MISMATCH') {
25
+ return `The tenant named in createFeltDB({ authorityScope }) does not own ${application}; use the tenant the application belongs to, or omit authorityScope.`;
26
+ }
27
+ if (status === 401 || AUTHENTICATION_CODES.has(code)) {
28
+ return context.hasToken
29
+ ? `${context.origin} did not accept the credential. Check FELTDB_TOKEN: it must be an unexpired, unrevoked data key${context.applicationId ? ` issued for ${application}` : ''}. Keep it server-side only.`
30
+ : 'No credential was sent. Set FELTDB_TOKEN in the server process (never in browser code), or pass createFeltDB({ server: { token } }).';
31
+ }
32
+ if (code === 'UNKNOWN_COLLECTION') {
33
+ const collection = context.collection ?? (/^[A-Za-z_][\w.-]*$/.test(message) ? message : undefined);
34
+ return `Collection ${collection ? `"${collection}" ` : ''}is not declared in the contract promoted to environment "${environment}" for ${application}. Add it to the contract and publish and promote a new revision.`;
35
+ }
36
+ if (status === 403 || code === 'FORBIDDEN') {
37
+ // Discovery checks application:read; a canonical read or write also
38
+ // resolves the promoted revision (application:revision:read).
39
+ const scope = context.operation === 'write' ? 'the application:revision:read and state:write scopes'
40
+ : context.operation === 'discover' ? 'the application:read scope'
41
+ : context.operation === 'read' ? 'the application:revision:read and state:read scopes'
42
+ : 'the scopes this operation needs (state:read to read, state:write to write)';
43
+ return `The credential was accepted but is not authorized for ${application}${context.applicationId ? ` in environment "${environment}"` : ''}. Use a data key minted for this application with ${scope}`
44
+ + (context.operation === 'write' && context.collection
45
+ ? `; a write to a collection the promoted contract does not declare ("${context.collection}" may be one) is refused the same way.`
46
+ : '.');
47
+ }
48
+ if (status === 404 && context.applicationId) {
49
+ if (/no active contract/i.test(message)) {
50
+ return `No contract revision is promoted to environment "${environment}" for ${application}. Publish and promote one (feltdb publish --environment ${environment}), or set FELTDB_ENVIRONMENT to an environment that has one.`;
51
+ }
52
+ if (/application not found/i.test(message)) {
53
+ return `Check FELTDB_APPLICATION_ID: ${context.origin} has no ${application} visible to this credential.`;
54
+ }
55
+ if (/revision not found/i.test(message)) {
56
+ return `The revision promoted for ${application} is not readable; promote the revision again.`;
57
+ }
58
+ }
59
+ if ((code === 'VALIDATION_FAILED' || code === 'VALIDATION_ERROR') && /unknown field/i.test(message)) {
60
+ return `Declare the field on ${context.collection ? `collection "${context.collection}"` : 'the collection'} in the contract and promote it, or stop writing it.`;
61
+ }
62
+ if (code === FeltDBErrorCode.DURABILITY_FAILURE) {
63
+ return 'Whether the commit is durable is unknown: retry with the same transactionId, and never treat this as a refusal.';
64
+ }
65
+ if (status === 429 || LOAD_CODES.has(code) || (status === 503 && code === FeltDBErrorCode.SERVICE_UNAVAILABLE)) {
66
+ return context.operation === 'write'
67
+ ? 'The authority is shedding load: back off (honour Retry-After) and retry with the same transactionId.'
68
+ : 'The authority is shedding load: back off (honour Retry-After) and retry the read.';
69
+ }
70
+ return undefined;
71
+ }
72
+ /** The authority's message plus its code, status, request id and remedy. */
73
+ function refusalMessage(message, code, status, requestId, context) {
74
+ if (!context)
75
+ return message;
76
+ const remedy = refusalRemedy(code, status, message, context);
77
+ const where = [status ? `HTTP ${status}` : undefined, code, requestId ? `request ${requestId}` : undefined].filter(Boolean).join(', ');
78
+ return `${message} (${where})${remedy ? `. ${remedy}` : ''}`;
79
+ }
80
+ /**
81
+ * The typed failure for a request that ended without an answer. A read is
82
+ * `SERVICE_UNAVAILABLE`; a mutation may have reached the authority and
83
+ * committed, so it is `COMMIT_OUTCOME_UNKNOWN`, never a refusal.
84
+ */
85
+ function transportFailure(error, mutating, context) {
86
+ if (error instanceof FeltDBServiceError)
87
+ return error;
88
+ const raw = error instanceof Error ? error.message : String(error);
89
+ const cause = error?.cause;
90
+ const name = error?.name;
91
+ const timedOut = name === 'TimeoutError' || name === 'AbortError';
92
+ // Only a request that ended without an answer gets the connection advice;
93
+ // any other local error (a malformed key, say) keeps its own message.
94
+ const transport = timedOut || error instanceof TypeError || typeof cause?.code === 'string';
95
+ const detail = typeof cause?.code === 'string' ? cause.code : typeof cause?.message === 'string' ? cause.message : raw;
96
+ const message = !context || !transport ? raw
97
+ : `${timedOut ? `No answer from FeltDB at ${context.origin} within ${context.timeoutMs} ms` : `Could not reach FeltDB at ${context.origin} (${detail})`}. `
98
+ + (mutating
99
+ ? 'The write may have been applied: retry only with the same transactionId, never a new one. '
100
+ : 'Nothing was changed. ')
101
+ + `Check FELTDB_URL and the service: GET ${context.origin}/health answers while the process is up, ${context.origin}/ready only when it can serve.`;
102
+ return new FeltDBServiceError(message, mutating ? FeltDBErrorCode.COMMIT_OUTCOME_UNKNOWN : FeltDBErrorCode.SERVICE_UNAVAILABLE);
103
+ }
104
+ /** A failed `JsResult` that keeps the typed failure. */
105
+ function failed(error, mutating, context) {
106
+ const cause = transportFailure(error, mutating, context);
107
+ return { success: false, error: cause.message, cause };
108
+ }
4
109
  /**
5
110
  * A durable identity for one conditional write attempt.
6
111
  *
@@ -29,6 +134,19 @@ function managedCollectionRecord(value) {
29
134
  delete record._version;
30
135
  return record;
31
136
  }
137
+ /** The collection a canonical request body addresses, for failure messages. */
138
+ function requestCollection(body) {
139
+ if (typeof body !== 'string')
140
+ return undefined;
141
+ try {
142
+ const value = JSON.parse(body);
143
+ const collection = value.query?.collection ?? value.transaction?.operations?.[0]?.collection;
144
+ return typeof collection === 'string' ? collection : undefined;
145
+ }
146
+ catch {
147
+ return undefined;
148
+ }
149
+ }
32
150
  /** Network adapter implementing the same collection runtime contract as WASM. */
33
151
  export class HttpJsDb {
34
152
  collection_queries_via_authority = true;
@@ -60,6 +178,8 @@ export class HttpJsDb {
60
178
  changeListeners = new Set();
61
179
  changeStream;
62
180
  constructor(options) {
181
+ if (!options.allowServiceKeyInBrowser)
182
+ assertBrowserSafeCredential(options.token, typeof window !== 'undefined' && typeof document !== 'undefined', 'the HTTP runtime token');
63
183
  this.url = options.url.replace(/\/$/, '');
64
184
  this.token = options.token || '';
65
185
  this.applicationId = options.applicationId;
@@ -127,6 +247,14 @@ export class HttpJsDb {
127
247
  ...(json ? { 'Content-Type': 'application/json' } : {}),
128
248
  };
129
249
  }
250
+ /** Where this client's requests go, for actionable failure messages. */
251
+ context(operation, collection) {
252
+ return {
253
+ origin: displayOrigin(this.url), timeoutMs: this.requestTimeoutMs, hasToken: !!this.token,
254
+ ...(this.applicationId ? { applicationId: this.applicationId, environment: this.environment } : {}),
255
+ ...(operation ? { operation } : {}), ...(collection ? { collection } : {}),
256
+ };
257
+ }
130
258
  updateToken(token) {
131
259
  this.token = token;
132
260
  // Credentials changed, so a permanent authorization failure may no longer
@@ -202,11 +330,33 @@ export class HttpJsDb {
202
330
  revisionState() {
203
331
  return this.revisionCache.state;
204
332
  }
205
- async canonical(path, payload) {
333
+ /**
334
+ * A canonical *read* (`/query`, `/transactions/read-basis`). It is a POST
335
+ * only because its request has a body; an interrupted read changed nothing,
336
+ * so it is `SERVICE_UNAVAILABLE`, never `COMMIT_OUTCOME_UNKNOWN`.
337
+ */
338
+ /**
339
+ * Run a request under the discovered revision. The authority answers only the revision
340
+ * active in this environment; after a promotion it refuses the old one with
341
+ * `REVISION_NOT_ACTIVE` and applies nothing. That refusal reaches the caller unchanged
342
+ * (the request is not resent under a different contract), and the revision is forgotten,
343
+ * so the next request runs under the one now active.
344
+ */
345
+ async withRevision(request) {
206
346
  const revisionId = await this.revisionId();
207
- return this.application_request(path, { method: 'POST', body: JSON.stringify({
347
+ try {
348
+ return await request(revisionId);
349
+ }
350
+ catch (error) {
351
+ if (error?.code === FeltDBErrorCode.REVISION_NOT_ACTIVE)
352
+ this.revisionCache.forget(revisionId);
353
+ throw error;
354
+ }
355
+ }
356
+ async canonical(path, payload) {
357
+ return this.withRevision(revisionId => this.application_request(path, { method: 'POST', body: JSON.stringify({
208
358
  application_id: this.applicationId, revision_id: revisionId, environment: this.environment, ...payload,
209
- }) });
359
+ }) }, { read: true }));
210
360
  }
211
361
  transactionDocument(revisionId, operations, transactionId = crypto.randomUUID(), preconditions = [], fences = []) {
212
362
  const tenantId = this.authorityScope?.kind === 'tenant' ? this.authorityScope.tenantId : '';
@@ -215,8 +365,7 @@ export class HttpJsDb {
215
365
  ...(fences.length ? { fences } : {}) };
216
366
  }
217
367
  async canonicalTransaction(operations, transactionId, preconditions = [], fences = []) {
218
- const revisionId = await this.revisionId();
219
- return this.application_request('/transactions', { method: 'POST', body: JSON.stringify({ application_id: this.applicationId, revision_id: revisionId, environment: this.environment, transaction: this.transactionDocument(revisionId, operations, transactionId, preconditions, fences) }) });
368
+ return this.withRevision(revisionId => this.application_request('/transactions', { method: 'POST', body: JSON.stringify({ application_id: this.applicationId, revision_id: revisionId, environment: this.environment, transaction: this.transactionDocument(revisionId, operations, transactionId, preconditions, fences) }) }));
220
369
  }
221
370
  async get(key) {
222
371
  try {
@@ -229,6 +378,7 @@ export class HttpJsDb {
229
378
  }
230
379
  const response = await fetch(`${this.url}/collections/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {
231
380
  headers: this.headers(),
381
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
232
382
  });
233
383
  if (response.status === 404)
234
384
  return { success: true };
@@ -238,7 +388,7 @@ export class HttpJsDb {
238
388
  return { success: true, data: JSON.stringify(record.value) };
239
389
  }
240
390
  catch (error) {
241
- return { success: false, error: String(error) };
391
+ return failed(error, false, this.context('read'));
242
392
  }
243
393
  }
244
394
  async query(collection) {
@@ -257,6 +407,7 @@ export class HttpJsDb {
257
407
  }
258
408
  const response = await fetch(`${this.url}/collections/${encodeURIComponent(collection)}`, {
259
409
  headers: this.headers(),
410
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
260
411
  });
261
412
  if (!response.ok)
262
413
  return this.failure(response);
@@ -264,7 +415,7 @@ export class HttpJsDb {
264
415
  return { success: true, data: JSON.stringify(records.map(record => record.value)) };
265
416
  }
266
417
  catch (error) {
267
- return { success: false, error: String(error) };
418
+ return failed(error, false, this.context('read'));
268
419
  }
269
420
  }
270
421
  async authority_query(query) {
@@ -289,17 +440,21 @@ export class HttpJsDb {
289
440
  } });
290
441
  return { records: result.records.map(managedCollectionRecord), nextCursor: result.next_cursor, exhausted: !result.next_cursor, plan: result.plan };
291
442
  }
292
- const response = await fetch(`${this.url}/query`, {
293
- method: 'POST', headers: this.headers(true), body: JSON.stringify(query),
294
- });
295
- const body = await response.json();
296
- if (!response.ok) {
297
- const error = new Error(body.message || body.error || `authority query failed with HTTP ${response.status}`);
298
- error.code = body.code;
299
- error.status = response.status;
300
- throw error;
443
+ let response;
444
+ try {
445
+ response = await fetch(`${this.url}/query`, {
446
+ method: 'POST', headers: this.headers(true), body: JSON.stringify(query),
447
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
448
+ });
301
449
  }
302
- return body;
450
+ catch (error) {
451
+ // A bounded query is a read: an interruption is SERVICE_UNAVAILABLE.
452
+ this.recordFailure(error);
453
+ throw transportFailure(error, false, this.context('read', query.collection));
454
+ }
455
+ if (!response.ok)
456
+ throw await this.refusal(response);
457
+ return await response.json();
303
458
  }
304
459
  async insert(key, value) {
305
460
  try {
@@ -313,13 +468,14 @@ export class HttpJsDb {
313
468
  method: 'POST',
314
469
  headers: this.headers(true),
315
470
  body: JSON.stringify({ ...record, id }),
471
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
316
472
  });
317
473
  if (!response.ok)
318
474
  return this.failure(response);
319
475
  return { success: true, data: key };
320
476
  }
321
477
  catch (error) {
322
- return { success: false, error: String(error) };
478
+ return failed(error, true, this.context('write'));
323
479
  }
324
480
  }
325
481
  async update(key, value) {
@@ -333,13 +489,14 @@ export class HttpJsDb {
333
489
  method: 'PATCH',
334
490
  headers: this.headers(true),
335
491
  body: value,
492
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
336
493
  });
337
494
  if (!response.ok)
338
495
  return this.failure(response);
339
496
  return { success: true, data: key };
340
497
  }
341
498
  catch (error) {
342
- return { success: false, error: String(error) };
499
+ return failed(error, true, this.context('write'));
343
500
  }
344
501
  }
345
502
  /**
@@ -351,7 +508,10 @@ export class HttpJsDb {
351
508
  async commit_transaction(request) {
352
509
  if (this.applicationId) {
353
510
  const operations = request.operations.map(operation => ({
354
- kind: operation.value === undefined ? 'delete' : operation.requireAbsent ? 'insert' : 'update',
511
+ // A write without `requireAbsent` creates an absent record and replaces an
512
+ // existing one, as on every other runtime (`put`). `update` would merge into an
513
+ // existing record and refuse an absent one.
514
+ kind: operation.value === undefined ? 'delete' : operation.requireAbsent ? 'insert' : 'put',
355
515
  collection: operation.collection,
356
516
  id: operation.id,
357
517
  value: operation.value && typeof operation.value === 'object' && !Array.isArray(operation.value)
@@ -395,7 +555,7 @@ export class HttpJsDb {
395
555
  }
396
556
  catch (error) {
397
557
  this.recordFailure(error);
398
- throw new FeltDBServiceError(error instanceof Error ? error.message : String(error), FeltDBErrorCode.COMMIT_OUTCOME_UNKNOWN);
558
+ throw transportFailure(error, true, this.context('write', request.operations[0]?.collection));
399
559
  }
400
560
  if (!response.ok) {
401
561
  // The authority answers a refused transaction with a structured
@@ -407,12 +567,13 @@ export class HttpJsDb {
407
567
  body = await response.json();
408
568
  }
409
569
  catch { /* not JSON */ }
410
- const error = new Error(body.error || `transaction failed with HTTP ${response.status}`);
411
- error.status = response.status;
412
- if (body.code)
413
- error.feltdbCode = body.code;
570
+ const code = body.code
571
+ ?? (response.status >= 500 ? FeltDBErrorCode.SERVICE_UNAVAILABLE : FeltDBErrorCode.INVALID_REQUEST);
572
+ const error = new FeltDBServiceError(refusalMessage((code === body.error ? body.message : body.error) || body.message || `transaction failed with HTTP ${response.status}`, code, response.status, body.request_id, this.context('write', request.operations[0]?.collection)), code, body.request_id, response.status);
573
+ error.feltdbCode = code;
414
574
  if (body.failure)
415
575
  error.feltdbConflict = body.failure;
576
+ this.recordFailure(error);
416
577
  throw error;
417
578
  }
418
579
  const body = await response.json();
@@ -566,17 +727,28 @@ export class HttpJsDb {
566
727
  try {
567
728
  const [collection, id] = this.splitKey(params.key);
568
729
  const parsed = JSON.parse(params.value);
569
- const response = await fetch(`${this.url}/collections/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/cas`, {
570
- method: 'POST',
571
- headers: this.headers(true),
572
- body: JSON.stringify({
573
- expectedVersion: params.expectedVersion,
574
- expectedEpoch: params.expectedEpoch,
575
- expectedLeaseId: params.expectedLeaseId,
576
- rejectIfDiverged: params.rejectIfDiverged,
577
- value: parsed,
578
- }),
579
- });
730
+ let response;
731
+ try {
732
+ response = await fetch(`${this.url}/collections/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/cas`, {
733
+ method: 'POST',
734
+ headers: this.headers(true),
735
+ body: JSON.stringify({
736
+ expectedVersion: params.expectedVersion,
737
+ expectedEpoch: params.expectedEpoch,
738
+ expectedLeaseId: params.expectedLeaseId,
739
+ rejectIfDiverged: params.rejectIfDiverged,
740
+ value: parsed,
741
+ }),
742
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
743
+ });
744
+ }
745
+ catch (error) {
746
+ // The request may have reached the authority and committed. A CAS
747
+ // carries no identity to retry by, so the caller reconciles by
748
+ // re-reading: a retried CAS is refused by the version it advanced.
749
+ this.recordFailure(error);
750
+ throw new FeltDBServiceError(error instanceof Error ? error.message : String(error), FeltDBErrorCode.COMMIT_OUTCOME_UNKNOWN);
751
+ }
580
752
  // Handle conflict response (structured error)
581
753
  if (response.status === 409) {
582
754
  const body = await response.json();
@@ -590,10 +762,14 @@ export class HttpJsDb {
590
762
  };
591
763
  }
592
764
  }
593
- // Other errors
765
+ // Other errors, typed by the authority's code.
594
766
  if (!response.ok) {
595
- const failure = await this.failure(response);
596
- throw new Error(failure.error || 'HTTP CAS failed');
767
+ let body = {};
768
+ try {
769
+ body = await response.json();
770
+ }
771
+ catch { /* not JSON */ }
772
+ throw new FeltDBServiceError(body.message || body.error || `HTTP CAS failed with ${response.status}`, body.code || (response.status >= 500 ? FeltDBErrorCode.SERVICE_UNAVAILABLE : FeltDBErrorCode.INVALID_REQUEST), body.request_id, response.status);
597
773
  }
598
774
  // Success response
599
775
  const result = await response.json();
@@ -613,11 +789,12 @@ export class HttpJsDb {
613
789
  const response = await fetch(`${this.url}/collections/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {
614
790
  method: 'DELETE',
615
791
  headers: this.headers(),
792
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
616
793
  });
617
794
  return response.ok ? { success: true, data: key } : this.failure(response);
618
795
  }
619
796
  catch (error) {
620
- return { success: false, error: String(error) };
797
+ return failed(error, true, this.context('write'));
621
798
  }
622
799
  }
623
800
  /** Acquire a reference through the server's causal peer fabric. */
@@ -626,7 +803,7 @@ export class HttpJsDb {
626
803
  if (response.status === 404)
627
804
  return null;
628
805
  if (!response.ok)
629
- throw new Error((await this.failure(response)).error);
806
+ throw await this.refusal(response);
630
807
  return (await response.json()).value;
631
808
  }
632
809
  /** Execute the built-in state-derived search capability remotely. */
@@ -635,19 +812,19 @@ export class HttpJsDb {
635
812
  method: 'POST', headers: this.headers(true), body: JSON.stringify({ query, limit }),
636
813
  });
637
814
  if (!response.ok)
638
- throw new Error((await this.failure(response)).error);
815
+ throw await this.refusal(response);
639
816
  return (await response.json()).map(record => record.value);
640
817
  }
641
818
  async provenance(collection, id) {
642
819
  const response = await fetch(`${this.url}/provenance/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, { headers: this.headers() });
643
820
  if (!response.ok)
644
- throw new Error((await this.failure(response)).error);
821
+ throw await this.refusal(response);
645
822
  return (await response.json()).value;
646
823
  }
647
824
  async storeContent(content) {
648
825
  const response = await fetch(`${this.url}/content`, { method: 'PUT', headers: this.headers(), body: content });
649
826
  if (!response.ok)
650
- throw new Error((await this.failure(response)).error);
827
+ throw await this.refusal(response);
651
828
  return response.json();
652
829
  }
653
830
  async acquireContent(hash) {
@@ -655,7 +832,7 @@ export class HttpJsDb {
655
832
  if (response.status === 404)
656
833
  return null;
657
834
  if (!response.ok)
658
- throw new Error((await this.failure(response)).error);
835
+ throw await this.refusal(response);
659
836
  return new Uint8Array(await response.arrayBuffer());
660
837
  }
661
838
  async command(path, body) {
@@ -663,19 +840,28 @@ export class HttpJsDb {
663
840
  method: 'POST', headers: this.headers(true), body: JSON.stringify(body),
664
841
  });
665
842
  if (!response.ok)
666
- throw new Error((await this.failure(response)).error);
843
+ throw await this.refusal(response);
667
844
  return response.status === 204 ? undefined : response.json();
668
845
  }
669
- async application_request(path, init = {}) {
846
+ /**
847
+ * One request to the canonical application service. A request without a
848
+ * body-carrying method is a read; a POST is treated as a mutation unless the
849
+ * caller declares it a read (`{ read: true }`), because only a mutation can
850
+ * leave an uncertain commit behind.
851
+ */
852
+ async application_request(path, init = {}, options = {}) {
670
853
  const separator = path.includes('?') ? '&' : '?';
671
- const context = this.applicationId
854
+ const query = this.applicationId
672
855
  ? `${separator}application_id=${encodeURIComponent(this.applicationId)}&environment=${encodeURIComponent(this.environment)}`
673
856
  : '';
674
857
  if (this.availabilityState === 'degraded')
675
858
  this.availabilityState = 'recovering';
859
+ const mutating = !options.read && !['GET', 'HEAD', 'OPTIONS'].includes((init.method ?? 'GET').toUpperCase());
860
+ // Built only on failure: parsing the request body is not free.
861
+ const context = () => this.context(path.startsWith('/application') ? 'discover' : mutating ? 'write' : 'read', requestCollection(init.body));
676
862
  let response;
677
863
  try {
678
- response = await fetch(`${this.url}/v1${path}${context}`, {
864
+ response = await fetch(`${this.url}/v1${path}${query}`, {
679
865
  ...init,
680
866
  signal: init.signal ?? AbortSignal.timeout(this.requestTimeoutMs),
681
867
  headers: { ...this.headers(init.body !== undefined), ...(init.headers || {}) },
@@ -683,10 +869,17 @@ export class HttpJsDb {
683
869
  }
684
870
  catch (error) {
685
871
  this.recordFailure(error);
686
- const mutating = !['GET', 'HEAD', 'OPTIONS'].includes((init.method ?? 'GET').toUpperCase());
687
- throw new FeltDBServiceError(error instanceof Error ? error.message : String(error), mutating ? FeltDBErrorCode.COMMIT_OUTCOME_UNKNOWN : FeltDBErrorCode.SERVICE_UNAVAILABLE);
872
+ throw transportFailure(error, mutating, context());
873
+ }
874
+ let text;
875
+ try {
876
+ text = await response.text();
877
+ }
878
+ catch (error) {
879
+ // The answer started and was cut off: for a mutation, still unknown.
880
+ this.recordFailure(error);
881
+ throw transportFailure(error, mutating, context());
688
882
  }
689
- const text = await response.text();
690
883
  let body;
691
884
  try {
692
885
  body = text ? JSON.parse(text) : undefined;
@@ -695,7 +888,8 @@ export class HttpJsDb {
695
888
  body = { message: text };
696
889
  }
697
890
  if (!response.ok) {
698
- const error = new FeltDBServiceError(body?.message || body?.error || `FeltDB service request failed: HTTP ${response.status}`, body?.code || body?.error || 'REQUEST_FAILED', body?.request_id, response.status);
891
+ const code = body?.code || body?.error || 'REQUEST_FAILED';
892
+ const error = new FeltDBServiceError(refusalMessage(body?.message || body?.error || `FeltDB service request failed: HTTP ${response.status}`, code, response.status, body?.request_id, context()), code, body?.request_id, response.status, body && typeof body === 'object' && !Array.isArray(body) ? body : undefined);
699
893
  // The same structured refusal the direct route carries, so a lost race
700
894
  // is typed the same way on every route.
701
895
  if (body?.failure)
@@ -706,6 +900,17 @@ export class HttpJsDb {
706
900
  this.recordSuccess();
707
901
  return body;
708
902
  }
903
+ /**
904
+ * A `fetch` bound to this authority: the configured origin and the current credentials and scope headers, read per request so a refreshed
905
+ * token is honoured. `db.workloads` is built on it; a path is resolved against the origin.
906
+ */
907
+ authority_transport() {
908
+ const fetcher = ((input, init = {}) => fetch(input, {
909
+ ...init,
910
+ headers: { ...this.headers(), ...(init.headers || {}) },
911
+ }));
912
+ return { baseUrl: this.url, fetcher };
913
+ }
709
914
  /** Canonical HTTP adapter used by the typed public substrate contract. */
710
915
  async public_request(path, init = {}) {
711
916
  let response;
@@ -733,7 +938,7 @@ export class HttpJsDb {
733
938
  const error = new FeltDBServiceError(body?.message || body?.error || `FeltDB request failed: HTTP ${response.status}`, body?.code || (response.status === 401 ? FeltDBErrorCode.UNAUTHORIZED
734
939
  : response.status === 403 ? FeltDBErrorCode.FORBIDDEN
735
940
  : response.status === 404 ? FeltDBErrorCode.NOT_FOUND
736
- : 'INVALID_REQUEST'), body?.request_id, response.status);
941
+ : 'INVALID_REQUEST'), body?.request_id, response.status, body && typeof body === 'object' && !Array.isArray(body) ? body : undefined);
737
942
  this.recordFailure(error);
738
943
  throw error;
739
944
  }
@@ -877,15 +1082,38 @@ export class HttpJsDb {
877
1082
  this.connectionState = 'closed';
878
1083
  this.nextRetryAt = undefined;
879
1084
  }
1085
+ /** A refused response as a failed `JsResult` carrying the typed refusal. */
880
1086
  async failure(response) {
881
- let detail = `HTTP ${response.status}`;
1087
+ const cause = await this.refusal(response);
1088
+ return { success: false, error: cause.message, cause };
1089
+ }
1090
+ /**
1091
+ * The authority's refusal, typed: its stable `code` (or one derived from the
1092
+ * status when the body carries none), status, request id and body.
1093
+ */
1094
+ async refusal(response) {
1095
+ let body;
882
1096
  try {
883
- const body = await response.json();
884
- if (body.error)
885
- detail = body.error;
1097
+ const parsed = await response.json();
1098
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
1099
+ body = parsed;
886
1100
  }
887
1101
  catch { /* response was not JSON */ }
888
- return { success: false, error: detail };
1102
+ const text = (name) => (typeof body?.[name] === 'string' ? body[name] : undefined);
1103
+ // An `error` field is a code only when it is spelled like one; older
1104
+ // answers put prose there.
1105
+ const errorField = text('error');
1106
+ const errorCode = errorField && /^[A-Z][A-Z0-9_]+$/.test(errorField) ? errorField : undefined;
1107
+ const code = text('code') ?? errorCode ?? (response.status === 401 ? FeltDBErrorCode.AUTHENTICATION_REQUIRED
1108
+ : response.status === 403 ? FeltDBErrorCode.FORBIDDEN
1109
+ : response.status === 404 ? FeltDBErrorCode.NOT_FOUND
1110
+ : response.status === 409 ? FeltDBErrorCode.CONFLICT
1111
+ : response.status >= 500 ? FeltDBErrorCode.SERVICE_UNAVAILABLE
1112
+ : FeltDBErrorCode.INVALID_REQUEST);
1113
+ const message = refusalMessage(text('message') ?? (errorField !== code ? errorField : undefined) ?? `HTTP ${response.status}`, code, response.status, text('request_id'), this.context());
1114
+ const error = new FeltDBServiceError(message, code, text('request_id'), response.status, body);
1115
+ this.recordFailure(error);
1116
+ return error;
889
1117
  }
890
1118
  get_capability_records(capability) { return this.query(capability); }
891
1119
  execute_op() { return { success: false, error: 'Raw operation execution is internal to the server fabric' }; }
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { registerDeploymentConfigLoader } from './deployment.js';
15
15
  import { FileJsDb } from './file-db.js';
16
16
  import * as nodeFs from 'fs';
17
17
  import * as nodePath from 'path';
18
- registerRuntime('file', path => new FileJsDb(path));
18
+ registerRuntime('file', (path, options) => new FileJsDb(path, options?.access ? { access: options.access } : {}));
19
19
  registerDeploymentConfigLoader(() => {
20
20
  const configPath = nodePath.join(process.cwd(), 'feltdb.config.json');
21
21
  if (!nodeFs.existsSync(configPath))
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Exclusive ownership of a local state directory.
3
+ *
4
+ * The local file runtime is safe for several processes at the level of a
5
+ * single commit (each mutation takes `state.lock`). An application usually
6
+ * wants more: that no *other* process opens its state at all, because two
7
+ * application processes over one directory each believe they are the only
8
+ * writer of their caches, schedules, and in-process subscriptions.
9
+ *
10
+ * `acquire` creates `owner.lock` in the directory with `O_EXCL` and records
11
+ * the holder (`pid`, `host`, a random token). A second process finds it and is
12
+ * refused with `LocalStateLockedError`. Handles in the same process share the
13
+ * lock and the last `release` removes it; process exit removes it too.
14
+ *
15
+ * A lock whose holder is gone is recoverable: when the recorded host is this
16
+ * host and `process.kill(pid, 0)` reports no such process, the lock is taken
17
+ * over. The takeover renames the old lock aside and checks it is the one that
18
+ * was judged stale before deleting it, so two processes recovering the same
19
+ * stale lock cannot both win. A lock recorded by another host, or one that
20
+ * cannot be read, is never judged stale (it is refused, and the error names
21
+ * the file to remove by hand). A lock records its directory's real path, so a
22
+ * lock copied with the directory (a backup, an upgrade's verification copy)
23
+ * does not hold the copy.
24
+ *
25
+ * This is not authority state: it holds no data, and removing it never
26
+ * changes what the store contains.
27
+ */
28
+ export declare const LOCAL_STATE_LOCK_FILE = "owner.lock";
29
+ /**
30
+ * Take exclusive ownership of `directory` for this process.
31
+ * Throws `LocalStateLockedError` when another live process holds it.
32
+ */
33
+ export declare function acquireLocalStateLock(directory: string): () => void;
34
+ //# sourceMappingURL=local-state-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-state-lock.d.ts","sourceRoot":"","sources":["../src/local-state-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAOH,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAiHlD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,IAAI,CAoDnE"}