@feltdb/core 0.12.1 → 0.13.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 (139) hide show
  1. package/dist/build-identity.json +13 -4
  2. package/dist/cli/commands.js +96 -45
  3. package/dist/cli/workspace-integration.js +8 -0
  4. package/dist/collection.d.ts +41 -4
  5. package/dist/collection.d.ts.map +1 -1
  6. package/dist/collection.js +116 -47
  7. package/dist/composition.d.ts.map +1 -1
  8. package/dist/composition.js +11 -1
  9. package/dist/create/build-identity.json +13 -4
  10. package/dist/create/cli.js +49 -40
  11. package/dist/create/create.js +32 -19
  12. package/dist/create/package-versions.js +1 -1
  13. package/dist/create/server-source/Cargo.lock +18 -3
  14. package/dist/create/server-source/Cargo.toml +4 -2
  15. package/dist/create/server-source/crates/feltdb/Cargo.toml +20 -0
  16. package/dist/create/server-source/crates/feltdb/LICENSE +21 -0
  17. package/dist/create/server-source/crates/feltdb/README.md +75 -0
  18. package/dist/create/server-source/crates/feltdb/src/agent_state.rs +320 -0
  19. package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +1545 -0
  20. package/dist/create/server-source/crates/feltdb/src/authority.rs +145 -15
  21. package/dist/create/server-source/crates/feltdb/src/lib.rs +227 -23
  22. package/dist/create/server-source/crates/feltdb/src/state_model.rs +1 -5
  23. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +204 -1
  24. package/dist/create/server-source/crates/feltdb/src/workload.rs +685 -53
  25. package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +1188 -0
  26. package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +2884 -0
  27. package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +534 -0
  28. package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +23340 -0
  29. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +18 -12
  30. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +17 -5
  31. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +29 -0
  32. package/dist/create/server-source/crates/feltdb-client/LICENSE +21 -0
  33. package/dist/create/server-source/crates/feltdb-client/README.md +70 -0
  34. package/dist/create/server-source/crates/feltdb-client/src/application.rs +527 -0
  35. package/dist/create/server-source/crates/feltdb-client/src/authority.rs +679 -0
  36. package/dist/create/server-source/crates/feltdb-client/src/control.rs +292 -0
  37. package/dist/create/server-source/crates/feltdb-client/src/error.rs +227 -0
  38. package/dist/create/server-source/crates/feltdb-client/src/events.rs +146 -0
  39. package/dist/create/server-source/crates/feltdb-client/src/lib.rs +466 -0
  40. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/README.md +4 -0
  41. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/private-ca.pem +20 -0
  42. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/server-key.pem +28 -0
  43. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/server.pem +20 -0
  44. package/dist/create/server-source/crates/feltdb-client/tests/private_ca.rs +95 -0
  45. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +20 -1
  46. package/dist/create/server-source/crates/feltdb-server/LICENSE +21 -0
  47. package/dist/create/server-source/crates/feltdb-server/README.md +12 -1
  48. package/dist/create/server-source/crates/feltdb-server/src/agent_execution.rs +511 -0
  49. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +28 -0
  50. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +6 -2
  51. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +21 -0
  52. package/dist/create/server-source/crates/feltdb-server/src/main.rs +845 -138
  53. package/dist/create/server-source/crates/feltdb-server/tests/rust_client.rs +683 -0
  54. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +3 -1
  55. package/dist/create/setup-summary.js +40 -0
  56. package/dist/create/template/default-project/README.md +12 -7
  57. package/dist/create/template/default-project/src/pages/Dashboard.tsx +1 -1
  58. package/dist/create/template/dot-feltdb-README.md +3 -3
  59. package/dist/db.d.ts +27 -1
  60. package/dist/db.d.ts.map +1 -1
  61. package/dist/db.js +60 -21
  62. package/dist/development-runtime-bridge.d.ts +20 -0
  63. package/dist/development-runtime-bridge.d.ts.map +1 -1
  64. package/dist/development-runtime-bridge.js +74 -4
  65. package/dist/embedded-transaction.d.ts +75 -8
  66. package/dist/embedded-transaction.d.ts.map +1 -1
  67. package/dist/embedded-transaction.js +124 -18
  68. package/dist/error-codes.d.ts +2 -0
  69. package/dist/error-codes.d.ts.map +1 -1
  70. package/dist/error-codes.js +2 -0
  71. package/dist/feltdb.d.ts +1 -11
  72. package/dist/feltdb.d.ts.map +1 -1
  73. package/dist/file-db.d.ts +6 -0
  74. package/dist/file-db.d.ts.map +1 -1
  75. package/dist/file-db.js +43 -11
  76. package/dist/http-db.d.ts +13 -0
  77. package/dist/http-db.d.ts.map +1 -1
  78. package/dist/http-db.js +33 -4
  79. package/dist/indexeddb-db.d.ts.map +1 -1
  80. package/dist/indexeddb-db.js +65 -41
  81. package/dist/memory-db.d.ts.map +1 -1
  82. package/dist/memory-db.js +29 -8
  83. package/dist/studio/{KeyManagementPanel-DZuSeWBK.js → KeyManagementPanel-skUNnKRw.js} +36 -28
  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/RouteErrorBoundary.d.ts +5 -0
  89. package/dist/studio/components/RouteErrorBoundary.d.ts.map +1 -0
  90. package/dist/studio/components/index.js +2 -2
  91. package/dist/studio/{components-Bivm2lX6.js → components-BSGmHfif.js} +6 -6
  92. package/dist/studio/control-plane/Agents.d.ts.map +1 -1
  93. package/dist/studio/control-plane/Data.d.ts.map +1 -1
  94. package/dist/studio/control-plane/Instance.d.ts +4 -1
  95. package/dist/studio/control-plane/Instance.d.ts.map +1 -1
  96. package/dist/studio/control-plane/Operations.d.ts +4 -1
  97. package/dist/studio/control-plane/Operations.d.ts.map +1 -1
  98. package/dist/studio/control-plane/Overview.d.ts.map +1 -1
  99. package/dist/studio/control-plane/Schema.d.ts.map +1 -1
  100. package/dist/studio/control-plane/context.d.ts +4 -1
  101. package/dist/studio/control-plane/context.d.ts.map +1 -1
  102. package/dist/studio/control-plane/index.js +2 -2
  103. package/dist/studio/control-plane/primitives.d.ts +24 -0
  104. package/dist/studio/control-plane/primitives.d.ts.map +1 -1
  105. package/dist/studio/{control-plane-CLm69XwX.js → control-plane-CaBA7Rgv.js} +1374 -1298
  106. package/dist/studio/index.d.ts +1 -0
  107. package/dist/studio/index.d.ts.map +1 -1
  108. package/dist/studio/index.js +415 -237
  109. package/dist/studio/navigation.d.ts +57 -0
  110. package/dist/studio/navigation.d.ts.map +1 -0
  111. package/dist/studio/studio.css +1 -1
  112. package/dist/studio/utils/control-plane-api.d.ts +2 -0
  113. package/dist/studio/utils/control-plane-api.d.ts.map +1 -1
  114. package/dist/studio/utils/control-plane-api.js +9 -4
  115. package/dist/studio/utils/service-api.d.ts.map +1 -1
  116. package/dist/studio/utils/service-api.js +5 -4
  117. package/dist/studio-app/assets/{feltdb_wasm-DACcD-zs.js → feltdb_wasm-3hDngl1h.js} +1 -1
  118. package/dist/studio-app/assets/feltdb_wasm_bg-CFQT4gCy.wasm +0 -0
  119. package/dist/studio-app/assets/index-Dql1hS5m.js +30 -0
  120. package/dist/studio-app/assets/{index-CiC8VY-a.css → index-vi21oEQa.css} +1 -1
  121. package/dist/studio-app/index.html +2 -2
  122. package/dist/telemetry.d.ts +1 -0
  123. package/dist/telemetry.d.ts.map +1 -1
  124. package/dist/telemetry.js +4 -3
  125. package/dist/transaction-identity.d.ts +62 -0
  126. package/dist/transaction-identity.d.ts.map +1 -0
  127. package/dist/transaction-identity.js +138 -0
  128. package/dist/transaction.d.ts +50 -5
  129. package/dist/transaction.d.ts.map +1 -1
  130. package/dist/transaction.js +28 -0
  131. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  132. package/dist/wasm/package.json +1 -1
  133. package/dist/workspace/local-development-authority.d.ts +19 -0
  134. package/dist/workspace/local-development-authority.d.ts.map +1 -1
  135. package/dist/workspace/local-development-authority.js +335 -15
  136. package/package.json +1 -1
  137. package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
  138. package/dist/studio-app/assets/feltdb_wasm_bg-BejThWID.wasm +0 -0
  139. package/dist/studio-app/assets/index-CoZaxnlm.js +0 -30
package/dist/http-db.js CHANGED
@@ -56,6 +56,9 @@ export class HttpJsDb {
56
56
  nextRetryAt;
57
57
  streamFailures = 0;
58
58
  authorityFailures = 0;
59
+ /** One entry per subscription, so the same callback subscribed twice is two subscriptions. */
60
+ changeListeners = new Set();
61
+ changeStream;
59
62
  constructor(options) {
60
63
  this.url = options.url.replace(/\/$/, '');
61
64
  this.token = options.token || '';
@@ -749,14 +752,40 @@ export class HttpJsDb {
749
752
  * a timer that wakes up after the caller has unsubscribed and opens a new
750
753
  * connection to an authority nobody is listening to.
751
754
  */
755
+ /**
756
+ * One event stream per client, shared by every subscriber.
757
+ *
758
+ * A browser holds at most six HTTP/1.1 connections to one host, and an event
759
+ * stream holds its connection for as long as it is open. A stream per live
760
+ * collection therefore lets an application with six live collections occupy
761
+ * every connection to its authority, after which each other request — the
762
+ * next write included — waits forever. Subscribers are fanned out here
763
+ * instead, and the stream closes with the last of them.
764
+ */
752
765
  subscribe_changes(callback) {
753
- const controller = new AbortController();
754
- this.connectionState = 'connecting';
755
- void this.consumeEvents(controller, callback);
766
+ const subscription = { callback };
767
+ this.changeListeners.add(subscription);
768
+ if (!this.changeStream) {
769
+ const controller = new AbortController();
770
+ this.changeStream = controller;
771
+ this.connectionState = 'connecting';
772
+ void this.consumeEvents(controller, collection => {
773
+ for (const listener of [...this.changeListeners]) {
774
+ // One subscriber's failure is its own; the others still hear the change.
775
+ try {
776
+ listener.callback(collection);
777
+ }
778
+ catch { /* reported by the subscriber */ }
779
+ }
780
+ });
781
+ }
756
782
  return () => {
783
+ if (!this.changeListeners.delete(subscription) || this.changeListeners.size > 0 || !this.changeStream)
784
+ return;
757
785
  // `abort()` reaches both: the in-flight fetch through its signal, and
758
786
  // the pending backoff through the listener `cancellableDelay` installs.
759
- controller.abort();
787
+ this.changeStream.abort();
788
+ this.changeStream = undefined;
760
789
  this.connectionState = 'closed';
761
790
  this.nextRetryAt = undefined;
762
791
  };
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb-db.d.ts","sourceRoot":"","sources":["../src/indexeddb-db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"indexeddb-db.d.ts","sourceRoot":"","sources":["../src/indexeddb-db.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { FreshnessContractViolation } from './freshness.js';
2
- import { normaliseReadSet } from './transaction.js';
3
- import { decideTransaction, readBasisToken, embeddedResult, EmbeddedTransactionRejected, } from './embedded-transaction.js';
2
+ import { TransactionIdConflictError, TransactionIdUnverifiableError, normaliseReadSet } from './transaction.js';
3
+ import { decideTransaction, prepareTransaction, readBasisToken, refusalError, embeddedDuplicate, embeddedResult, } from './embedded-transaction.js';
4
4
  import { EmbeddedQueryEngine } from './embedded-query.js';
5
5
  /** Durable browser runtime. Every mutation resolves only after its IndexedDB transaction commits. */
6
6
  export class IndexedDbJsDb {
@@ -102,27 +102,18 @@ export class IndexedDbJsDb {
102
102
  */
103
103
  async commit_transaction(request) {
104
104
  const db = await this.database;
105
- const before = this.sequence;
106
- // A transaction with no operations, or with no identity, would open an
107
- // IndexedDB transaction that reads nothing and therefore never reaches a
108
- // decision. Those two are settled first, before a transaction is opened.
109
- //
110
- // Nothing else is pre-decided here. Every other question this runtime has
111
- // to answer -- does the record exist, what version does it hold -- is a
112
- // question about stored state, and answering it outside the IndexedDB
113
- // transaction would put another writer between the check and the write.
114
- if (!request.transactionId?.trim() || request.operations.length === 0) {
115
- const structural = decideTransaction(request, { exists: () => false, hasApplied: () => false });
116
- if (structural.kind === 'reject')
117
- throw new EmbeddedTransactionRejected(structural.reason, structural.failure);
118
- }
119
- // Applied transaction ids live in their own store so identity survives a
120
- // page reload the same way records do.
121
- const alreadyApplied = await this.request('transactions', store => store.get(request.transactionId));
122
- if (alreadyApplied !== undefined) {
123
- return embeddedResult(request, true, before, this.sequence);
124
- }
125
- const plan = await new Promise((resolve, reject) => {
105
+ // Validity and identity need no stored state, so they are settled here,
106
+ // before the IndexedDB transaction is opened: that transaction cannot be
107
+ // held open across other asynchronous work, and a malformed request must
108
+ // never reach (or be answered by) the stored identity.
109
+ const digest = prepareTransaction(request);
110
+ // Everything else is a question about stored state -- is this id already
111
+ // committed, and with which digest; does the record exist, what version
112
+ // does it hold -- and is answered inside the one read-write transaction
113
+ // that also writes. IndexedDB does not start a read-write transaction
114
+ // while another with an overlapping scope is active, across tabs and
115
+ // connections, so two attempts at one id cannot both see it as new.
116
+ const outcome = await new Promise((resolve, reject) => {
126
117
  let transaction;
127
118
  try {
128
119
  transaction = db.transaction(['rows', 'changes', 'transactions'], 'readwrite', { durability: 'strict' });
@@ -155,27 +146,32 @@ export class IndexedDbJsDb {
155
146
  // same transaction.
156
147
  const ranges = [...new Set(fences.flatMap(fence => (fence.reads.predicates ?? []).map(predicate => predicate.collection)))];
157
148
  const scanned = new Map();
158
- let pending = touched.length + ranges.length;
149
+ // The identity lookup is one of the reads, issued first.
150
+ let pending = touched.length + ranges.length + 1;
151
+ let prior;
159
152
  let decided = null;
160
153
  const finish = () => {
161
154
  const plan = decideTransaction(request, {
162
155
  exists: key => records.get(key) !== undefined,
163
156
  read: key => records.get(key),
164
157
  scan: collections => new Map(collections.map(collection => [collection, scanned.get(collection) ?? []])),
165
- hasApplied: () => false,
166
- });
167
- decided = plan;
158
+ applied: () => prior,
159
+ }, digest);
160
+ decided = { plan };
168
161
  if (plan.kind !== 'apply') {
169
162
  transaction.abort();
170
163
  return;
171
164
  }
172
165
  const timestamp = Date.now();
166
+ let outstanding = plan.mutations.length;
167
+ let first;
168
+ let last = 0;
173
169
  for (const mutation of plan.mutations) {
174
170
  if (mutation.value === undefined)
175
171
  rows.delete(mutation.key);
176
172
  else
177
173
  rows.put(mutation.value, mutation.key);
178
- changes.add({
174
+ const added = changes.add({
179
175
  collection: mutation.collection,
180
176
  key: mutation.key,
181
177
  type: mutation.value === undefined ? 'delete' : 'put',
@@ -184,16 +180,41 @@ export class IndexedDbJsDb {
184
180
  origin: this.origin,
185
181
  id: `${this.origin}:${timestamp}:${Math.random().toString(36).slice(2)}`,
186
182
  });
183
+ added.onsuccess = () => {
184
+ const position = Number(added.result);
185
+ first = first === undefined ? position : Math.min(first, position);
186
+ last = Math.max(last, position);
187
+ outstanding -= 1;
188
+ // The identity is written in this same transaction, once the
189
+ // commit's durable position -- the change log's own sequence, the
190
+ // same for every connection -- is known.
191
+ if (outstanding === 0) {
192
+ const before = (first ?? 1) - 1;
193
+ decided = { plan, before, after: last };
194
+ transactions.put({ transactionId: request.transactionId, committedAt: timestamp, digest, before, after: last }, request.transactionId);
195
+ }
196
+ };
187
197
  }
188
- transactions.put({ transactionId: request.transactionId, committedAt: timestamp }, request.transactionId);
189
198
  };
199
+ const settle = () => { pending -= 1; if (pending === 0)
200
+ finish(); };
201
+ const identity = transactions.get(request.transactionId);
202
+ identity.onsuccess = () => {
203
+ const stored = identity.result;
204
+ // An entry with no digest was written before digests existed.
205
+ prior = stored === undefined ? undefined : {
206
+ ...(stored.digest === undefined ? {} : { digest: stored.digest }),
207
+ before: stored.before,
208
+ after: stored.after,
209
+ };
210
+ settle();
211
+ };
212
+ identity.onerror = () => reject(identity.error ?? new Error('IndexedDB read failed'));
190
213
  for (const collection of ranges) {
191
214
  const lookup = rows.getAll(IDBKeyRange.bound(`${collection}:`, `${collection}:\uffff`));
192
215
  lookup.onsuccess = () => {
193
216
  scanned.set(collection, lookup.result);
194
- pending -= 1;
195
- if (pending === 0)
196
- finish();
217
+ settle();
197
218
  };
198
219
  lookup.onerror = () => reject(lookup.error ?? new Error('IndexedDB read failed'));
199
220
  }
@@ -201,33 +222,36 @@ export class IndexedDbJsDb {
201
222
  const lookup = rows.get(key);
202
223
  lookup.onsuccess = () => {
203
224
  records.set(key, lookup.result);
204
- pending -= 1;
205
- if (pending === 0)
206
- finish();
225
+ settle();
207
226
  };
208
227
  lookup.onerror = () => reject(lookup.error ?? new Error('IndexedDB read failed'));
209
228
  }
210
- transaction.oncomplete = () => resolve(decided ?? { kind: 'reject', reason: 'transaction did not decide' });
229
+ transaction.oncomplete = () => resolve(decided ?? { plan: { kind: 'reject', reason: 'transaction did not decide' } });
211
230
  transaction.onabort = () => {
212
- if (decided && decided.kind !== 'apply')
231
+ if (decided && decided.plan.kind !== 'apply')
213
232
  resolve(decided);
214
233
  else
215
234
  reject(transaction.error ?? new Error('IndexedDB transaction aborted'));
216
235
  };
217
236
  transaction.onerror = () => {
218
- if (decided && decided.kind !== 'apply')
237
+ if (decided && decided.plan.kind !== 'apply')
219
238
  return;
220
239
  reject(transaction.error ?? new Error('IndexedDB transaction failed'));
221
240
  };
222
241
  });
242
+ const { plan } = outcome;
223
243
  if (plan.kind === 'duplicate')
224
- return embeddedResult(request, true, before, this.sequence);
244
+ return embeddedDuplicate(request, plan);
245
+ if (plan.kind === 'conflict')
246
+ throw new TransactionIdConflictError(request.transactionId);
247
+ if (plan.kind === 'unverifiable')
248
+ throw new TransactionIdUnverifiableError(request.transactionId);
225
249
  if (plan.kind === 'reject')
226
- throw new EmbeddedTransactionRejected(plan.reason, plan.failure);
250
+ throw refusalError(plan);
227
251
  this.sequence += plan.mutations.length;
228
252
  for (const mutation of plan.mutations)
229
253
  this.announceLocalChange(mutation.collection, this.sequence);
230
- return embeddedResult(request, false, before, this.sequence);
254
+ return embeddedResult(request, false, outcome.before ?? 0, outcome.after ?? 0);
231
255
  }
232
256
  /** Capture a read basis inside one readonly IndexedDB transaction. */
233
257
  async read_basis(reads) {
@@ -1 +1 @@
1
- {"version":3,"file":"memory-db.d.ts","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-db.d.ts","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"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"}
package/dist/memory-db.js CHANGED
@@ -1,8 +1,16 @@
1
1
  import { FreshnessContractViolation } from './freshness.js';
2
- import { normaliseReadSet } from './transaction.js';
3
- import { decideTransaction, readBasisToken, scanRows, embeddedResult, EmbeddedTransactionRejected, } from './embedded-transaction.js';
2
+ import { TransactionIdConflictError, TransactionIdUnverifiableError, normaliseReadSet } from './transaction.js';
3
+ import { decideTransaction, prepareTransaction, readBasisToken, refusalError, scanRows, embeddedDuplicate, embeddedResult, } from './embedded-transaction.js';
4
4
  import { EmbeddedQueryEngine } from './embedded-query.js';
5
5
  const namespaces = new Map();
6
+ /**
7
+ * Committed transaction identities, per namespace.
8
+ *
9
+ * The rows of a namespace are shared by every handle opened on it, so the
10
+ * identities of the transactions that wrote them must be shared too: otherwise
11
+ * two handles would each apply the same transaction id once.
12
+ */
13
+ const appliedTransactions = new Map();
6
14
  const revisions = new Map();
7
15
  function namespaceRevision(namespace) {
8
16
  let revision = revisions.get(namespace);
@@ -20,7 +28,7 @@ export class MemoryJsDb {
20
28
  origin;
21
29
  revisionState;
22
30
  peers = new Set();
23
- applied = new Set();
31
+ applied;
24
32
  queryEngine;
25
33
  indexedRevision;
26
34
  constructor(namespace) {
@@ -30,6 +38,12 @@ export class MemoryJsDb {
30
38
  namespaces.set(namespace, rows);
31
39
  }
32
40
  this.rows = rows;
41
+ let applied = appliedTransactions.get(namespace);
42
+ if (!applied) {
43
+ applied = new Map();
44
+ appliedTransactions.set(namespace, applied);
45
+ }
46
+ this.applied = applied;
33
47
  this.revisionState = namespaceRevision(namespace);
34
48
  this.origin = `memory:${namespace}`;
35
49
  this.queryEngine = new EmbeddedQueryEngine(() => this.rows.entries());
@@ -66,16 +80,21 @@ export class MemoryJsDb {
66
80
  }
67
81
  async commit_transaction(request) {
68
82
  const before = this.sequence;
83
+ const digest = prepareTransaction(request);
69
84
  const plan = decideTransaction(request, {
70
85
  exists: key => this.rows.has(key),
71
- hasApplied: transactionId => this.applied.has(transactionId),
86
+ applied: transactionId => this.applied.get(transactionId),
72
87
  read: key => this.rows.get(key),
73
88
  scan: collections => scanRows(this.rows, collections),
74
- });
89
+ }, digest);
75
90
  if (plan.kind === 'duplicate')
76
- return embeddedResult(request, true, before, this.sequence);
91
+ return embeddedDuplicate(request, plan);
92
+ if (plan.kind === 'conflict')
93
+ throw new TransactionIdConflictError(request.transactionId);
94
+ if (plan.kind === 'unverifiable')
95
+ throw new TransactionIdUnverifiableError(request.transactionId);
77
96
  if (plan.kind === 'reject')
78
- throw new EmbeddedTransactionRejected(plan.reason, plan.failure);
97
+ throw refusalError(plan);
79
98
  for (const mutation of plan.mutations) {
80
99
  if (mutation.value === undefined) {
81
100
  this.rows.delete(mutation.key);
@@ -86,7 +105,7 @@ export class MemoryJsDb {
86
105
  this.event(mutation.collection, mutation.key, 'put', mutation.value);
87
106
  }
88
107
  }
89
- this.applied.add(request.transactionId);
108
+ this.applied.set(request.transactionId, { digest, before, after: this.sequence });
90
109
  return embeddedResult(request, false, before, this.sequence);
91
110
  }
92
111
  insert(key, value) {
@@ -112,6 +131,8 @@ export class MemoryJsDb {
112
131
  : { success: true, data: JSON.stringify(value) };
113
132
  }
114
133
  delete(key) {
134
+ if (!this.rows.has(key))
135
+ return { success: false, error: `Record ${key} not found` };
115
136
  this.rows.delete(key);
116
137
  this.event(key.split(':')[0], key, 'delete');
117
138
  return { success: true, data: key };
@@ -29,11 +29,11 @@ var a = {
29
29
  revokeBtn: "_revokeBtn_1cbba_250",
30
30
  info: "_info_1cbba_265"
31
31
  }, o = ({ apiUrl: o, token: s, namespace: c = "app-store-sherpa", onConfigure: l }) => {
32
- let [u, d] = t([]), [f, p] = t(!0), [m, h] = t(null), [g, _] = t(!1), [v, y] = t(null), [b, x] = t(""), [S, C] = t([
32
+ let [u, d] = t([]), [f, p] = t(!0), [m, h] = t(null), [g, _] = t(!1), [v, y] = t(null), [b, x] = t(""), [S, C] = t(!1), [w, T] = t([
33
33
  "state:read",
34
34
  "state:write",
35
35
  "events:read"
36
- ]), w = [
36
+ ]), E = [
37
37
  "state:read",
38
38
  "state:write",
39
39
  "events:read",
@@ -41,7 +41,7 @@ var a = {
41
41
  "backup:restore",
42
42
  "admin:logs",
43
43
  "admin:restart"
44
- ], T = [
44
+ ], D = [
45
45
  "state:read",
46
46
  "state:write",
47
47
  "events:read",
@@ -51,9 +51,9 @@ var a = {
51
51
  "admin:restart"
52
52
  ];
53
53
  e(() => {
54
- E();
54
+ O();
55
55
  }, [o, s]);
56
- let E = async () => {
56
+ let O = async () => {
57
57
  try {
58
58
  if (p(!0), h(null), !o) {
59
59
  h("A server or managed API URL is not configured."), p(!1);
@@ -65,7 +65,11 @@ var a = {
65
65
  });
66
66
  if (e.status === 401) throw Error("Unauthorized: Invalid or expired API token");
67
67
  if (e.status === 403) throw Error("Forbidden: Your account does not have permission to manage API keys");
68
- if (!e.ok) throw Error(`Failed to fetch keys: ${e.status} ${e.statusText}`);
68
+ if (e.status === 404) {
69
+ C(!0), d([]);
70
+ return;
71
+ }
72
+ if (C(!1), !e.ok) throw Error(`Failed to fetch keys: ${e.status} ${e.statusText}`);
69
73
  let t = await e.json();
70
74
  d(t.tokens || []);
71
75
  } catch (e) {
@@ -74,7 +78,7 @@ var a = {
74
78
  } finally {
75
79
  p(!1);
76
80
  }
77
- }, D = async (e) => {
81
+ }, k = async (e) => {
78
82
  e.preventDefault();
79
83
  try {
80
84
  let e = await fetch(`${o}/api/keys`, {
@@ -86,7 +90,7 @@ var a = {
86
90
  body: JSON.stringify({
87
91
  id: b || `key-${Date.now()}`,
88
92
  namespace: c,
89
- scopes: S.length > 0 ? S : T
93
+ scopes: w.length > 0 ? w : D
90
94
  }),
91
95
  signal: AbortSignal.timeout(1e4)
92
96
  });
@@ -94,12 +98,12 @@ var a = {
94
98
  if (e.status === 409) throw Error("A key with this name already exists");
95
99
  if (!e.ok) throw Error(`Failed to create key: ${e.status} ${e.statusText}`);
96
100
  let t = await e.json();
97
- j(t.secret), x(""), C(T), _(!1), await E();
101
+ N(t.secret), x(""), T(D), _(!1), await O();
98
102
  } catch (e) {
99
103
  let t = e instanceof TypeError ? "Connection error: Unable to reach the API server" : e instanceof Error ? e.message : "Failed to create key";
100
104
  h(t), console.error("Error creating API key:", e);
101
105
  }
102
- }, O = async (e) => {
106
+ }, A = async (e) => {
103
107
  if (confirm(`Revoke key "${e}"? This cannot be undone.`)) try {
104
108
  let t = await fetch(`${o}/api/keys/${e}`, {
105
109
  method: "DELETE",
@@ -109,28 +113,32 @@ var a = {
109
113
  if (t.status === 404) throw Error("Key not found");
110
114
  if (t.status === 401) throw Error("Unauthorized: Invalid or expired API token");
111
115
  if (!t.ok) throw Error(`Failed to revoke key: ${t.status} ${t.statusText}`);
112
- await E();
116
+ await O();
113
117
  } catch (e) {
114
118
  let t = e instanceof TypeError ? "Connection error: Unable to reach the API server" : e instanceof Error ? e.message : "Failed to revoke key";
115
119
  h(t), console.error("Error revoking API key:", e);
116
120
  }
117
- }, k = (e, t) => {
121
+ }, j = (e, t) => {
118
122
  navigator.clipboard.writeText(e), y(t), setTimeout(() => y(null), 2e3);
119
- }, [A, j] = t(null);
123
+ }, [M, N] = t(null);
120
124
  return f ? /* @__PURE__ */ r("div", {
121
125
  className: a.panel,
122
126
  children: "Loading keys..."
123
127
  }) : /* @__PURE__ */ i("div", {
124
128
  className: a.panel,
125
129
  children: [
126
- /* @__PURE__ */ i("div", {
130
+ /* @__PURE__ */ r("div", {
127
131
  className: a.header,
128
- children: [/* @__PURE__ */ r("h2", { children: "API Key Management" }), /* @__PURE__ */ r("button", {
132
+ children: !S && o && /* @__PURE__ */ r("button", {
129
133
  className: a.createButton,
130
134
  onClick: () => _(!g),
131
- disabled: !o,
132
135
  children: g ? "✕ Cancel" : "+ New Key"
133
- })]
136
+ })
137
+ }),
138
+ S && /* @__PURE__ */ i("div", {
139
+ className: a.info,
140
+ "data-availability": "unsupported",
141
+ children: [/* @__PURE__ */ r("strong", { children: "This instance does not issue API keys." }), /* @__PURE__ */ r("p", { children: "The local development authority is unauthenticated and loopback-only, so there are no keys to create or list. A self-hosted or managed FeltDB server issues them." })]
134
142
  }),
135
143
  m && /* @__PURE__ */ i("div", {
136
144
  className: a.error,
@@ -154,7 +162,7 @@ var a = {
154
162
  ]
155
163
  }),
156
164
  /* @__PURE__ */ r("button", {
157
- onClick: () => E(),
165
+ onClick: () => O(),
158
166
  style: {
159
167
  marginTop: "8px",
160
168
  padding: "4px 12px",
@@ -177,19 +185,19 @@ var a = {
177
185
  children: "Open connection settings"
178
186
  })]
179
187
  }),
180
- A && /* @__PURE__ */ i("div", {
188
+ M && /* @__PURE__ */ i("div", {
181
189
  className: a.info,
182
190
  children: [
183
191
  /* @__PURE__ */ r("strong", { children: "New secret — copy it now; it will not be shown again." }),
184
- /* @__PURE__ */ r("code", { children: A }),
192
+ /* @__PURE__ */ r("code", { children: M }),
185
193
  /* @__PURE__ */ r("button", {
186
- onClick: () => k(A, "created"),
194
+ onClick: () => j(M, "created"),
187
195
  children: v === "created" ? "✓ Copied" : "Copy secret"
188
196
  })
189
197
  ]
190
198
  }),
191
- g && /* @__PURE__ */ i("form", {
192
- onSubmit: D,
199
+ g && !S && /* @__PURE__ */ i("form", {
200
+ onSubmit: k,
193
201
  className: a.createForm,
194
202
  children: [
195
203
  /* @__PURE__ */ i("div", {
@@ -205,13 +213,13 @@ var a = {
205
213
  className: a.formGroup,
206
214
  children: [/* @__PURE__ */ r("label", { children: "Scopes" }), /* @__PURE__ */ r("div", {
207
215
  className: a.scopeList,
208
- children: w.map((e) => /* @__PURE__ */ i("label", {
216
+ children: E.map((e) => /* @__PURE__ */ i("label", {
209
217
  className: a.scopeCheckbox,
210
218
  children: [/* @__PURE__ */ r("input", {
211
219
  type: "checkbox",
212
- checked: S.includes(e),
220
+ checked: w.includes(e),
213
221
  onChange: (t) => {
214
- t.target.checked ? C([...S, e]) : C(S.filter((t) => t !== e));
222
+ t.target.checked ? T([...w, e]) : T(w.filter((t) => t !== e));
215
223
  }
216
224
  }), e]
217
225
  }, e))
@@ -224,7 +232,7 @@ var a = {
224
232
  })
225
233
  ]
226
234
  }),
227
- u.length === 0 ? /* @__PURE__ */ r("div", {
235
+ S ? null : u.length === 0 ? /* @__PURE__ */ r("div", {
228
236
  className: a.empty,
229
237
  children: "No API keys configured. Create one to get started."
230
238
  }) : /* @__PURE__ */ r("div", {
@@ -259,7 +267,7 @@ var a = {
259
267
  className: a.keyActions,
260
268
  children: /* @__PURE__ */ r("button", {
261
269
  className: a.revokeBtn,
262
- onClick: () => O(e.id),
270
+ onClick: () => A(e.id),
263
271
  disabled: e.revoked,
264
272
  children: "Revoke"
265
273
  })
@@ -20,6 +20,13 @@ export interface ApplicationConnectionNoticeProps {
20
20
  registration?: {
21
21
  namespace?: string;
22
22
  };
23
+ /**
24
+ * Whether Studio could ask the development session at all. `unreachable`
25
+ * means the session did not answer, which says nothing about the
26
+ * application; without a registration it otherwise reads as waiting.
27
+ */
28
+ session?: 'reachable' | 'unreachable';
29
+ applicationUrl?: string;
23
30
  }
24
31
  export type StudioConnectionResolution = {
25
32
  source: 'explicit-authority' | 'configured-authority';
@@ -38,7 +45,7 @@ export declare function resolveStudioConnection(input: {
38
45
  }): StudioConnectionResolution;
39
46
  /** A registration proves the application is connected; it does not identify
40
47
  * the JavaScript environment in which the application itself executes. */
41
- export declare function ApplicationConnectionNotice({ registration }: ApplicationConnectionNoticeProps): React.JSX.Element;
48
+ export declare function ApplicationConnectionNotice({ registration, session, applicationUrl }: ApplicationConnectionNoticeProps): React.JSX.Element;
42
49
  export declare function StudioApp({ db, remoteUrl, token, namespace, deploymentRuntime, applicationUrl, applicationId, environment, developmentSession, managedPublish, sourceSync, onConnect }: StudioAppProps): React.JSX.Element;
43
50
  export default StudioApp;
44
51
  //# sourceMappingURL=app.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAQ3D,OAA4B,EAAE,KAAK,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AACzG,OAAO,EAAa,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAqBjF,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAI/E,OAAO,mCAAmC,CAAC;AAC3C,OAAO,yBAAyB,CAAC;AACjC,OAAO,WAAW,CAAC;AACnB,OAAO,mCAAmC,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,cAAc,CAAC,EAAE,2BAA2B,CAAC;IAC7C,UAAU,CAAC,EAAE,uBAAuB,CAAC;IACrC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClD;AAED,MAAM,WAAW,gCAAgC;IAC/C,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,EAAE,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,EAAE,CAAA;CAAE,CAAC;AAE5C,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,0BAA0B,CAU7B;AAED;0EAC0E;AAC1E,wBAAgB,2BAA2B,CAAC,EAAE,YAAY,EAAE,EAAE,gCAAgC,qBAM7F;AAiBD,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,SAAc,EAAE,KAAU,EAAE,SAAqB,EAAE,iBAA6B,EAAE,cAAmB,EAAE,aAAkB,EAAE,WAA0B,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,cAAc,qBA8HjQ;AA+DD,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAU3D,OAA4B,EAAE,KAAK,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AACzG,OAAO,EAAa,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAsBjF,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAI/E,OAAO,mCAAmC,CAAC;AAC3C,OAAO,yBAAyB,CAAC;AACjC,OAAO,WAAW,CAAC;AACnB,OAAO,mCAAmC,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,cAAc,CAAC,EAAE,2BAA2B,CAAC;IAC7C,UAAU,CAAC,EAAE,uBAAuB,CAAC;IACrC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClD;AAED,MAAM,WAAW,gCAAgC;IAC/C,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,EAAE,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,EAAE,CAAA;CAAE,CAAC;AAE5C,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,0BAA0B,CAU7B;AAED;0EAC0E;AAC1E,wBAAgB,2BAA2B,CAAC,EAAE,YAAY,EAAE,OAAqB,EAAE,cAAc,EAAE,EAAE,gCAAgC,qBAsBpI;AAGD,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,SAAc,EAAE,KAAU,EAAE,SAAqB,EAAE,iBAA6B,EAAE,cAAmB,EAAE,aAAkB,EAAE,WAA0B,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,cAAc,qBAqIjQ;AAiED,eAAe,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"KeyManagementPanel.d.ts","sourceRoot":"","sources":["../../src/components/KeyManagementPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAWnD,UAAU,uBAAuB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA+ThE,CAAC"}
1
+ {"version":3,"file":"KeyManagementPanel.d.ts","sourceRoot":"","sources":["../../src/components/KeyManagementPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAWnD,UAAU,uBAAuB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAgVhE,CAAC"}
@@ -1,2 +1,2 @@
1
- import { t as e } from "../KeyManagementPanel-DZuSeWBK.js";
1
+ import { t as e } from "../KeyManagementPanel-skUNnKRw.js";
2
2
  export { e as KeyManagementPanel };
@@ -0,0 +1,5 @@
1
+ import { default as React } from 'react';
2
+ export declare function RouteErrorBoundary({ children }: {
3
+ children: React.ReactNode;
4
+ }): React.JSX.Element;
5
+ //# sourceMappingURL=RouteErrorBoundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteErrorBoundary.d.ts","sourceRoot":"","sources":["../../src/components/RouteErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AA+B1B,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAG7E"}
@@ -1,4 +1,4 @@
1
- import { _ as e, a as t, b as n, c as r, d as i, f as a, g as o, h as s, i as c, l, m as u, n as d, o as f, p, r as m, s as h, t as g, u as _, v, y } from "../components-Bivm2lX6.js";
2
- import { t as b } from "../KeyManagementPanel-DZuSeWBK.js";
1
+ import { _ as e, a as t, b as n, c as r, d as i, f as a, g as o, h as s, i as c, l, m as u, n as d, o as f, p, r as m, s as h, t as g, u as _, v, y } from "../components-BSGmHfif.js";
2
+ import { t as b } from "../KeyManagementPanel-skUNnKRw.js";
3
3
  import { ManagedInstancePanel as x } from "./ManagedInstancePanel.js";
4
4
  export { v as AgentExplorer, s as ApplicationDesigner, u as AskFeltDB, l as CapabilityExplorer, m as ConflictExplorer, _ as ContractInspector, n as ExecutionViewer, o as GlobalSearch, g as HealthCenter, b as KeyManagementPanel, x as ManagedInstancePanel, a as ModuleExplorer, t as OperationsExplorer, r as OverviewDashboard, c as PeerMap, p as ProposalBrowser, d as ProvenanceViewer, f as ReferenceExplorer, e as SettingsPanel, h as StateExplorer, y as WorkflowVisualizer, i as dataCollectionLocation };