@feltdb/core 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/agent-runtime.d.ts +64 -2
  2. package/dist/agent-runtime.d.ts.map +1 -1
  3. package/dist/agent-runtime.js +121 -11
  4. package/dist/agent-state.d.ts +48 -0
  5. package/dist/agent-state.d.ts.map +1 -1
  6. package/dist/agent-state.js +174 -12
  7. package/dist/agent.d.ts +10 -1
  8. package/dist/agent.d.ts.map +1 -1
  9. package/dist/agent.js +10 -1
  10. package/dist/build-identity.json +4 -4
  11. package/dist/cli/commands.js +27 -6
  12. package/dist/collection.d.ts +3 -1
  13. package/dist/collection.d.ts.map +1 -1
  14. package/dist/collection.js +30 -8
  15. package/dist/create/build-identity.json +4 -4
  16. package/dist/create/cli.js +1 -1
  17. package/dist/create/create.js +4 -6
  18. package/dist/create/package-versions.js +1 -1
  19. package/dist/create/server-source/Cargo.lock +6 -6
  20. package/dist/create/server-source/Cargo.toml +1 -1
  21. package/dist/create/server-source/crates/feltdb/src/lib.rs +126 -35
  22. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +162 -53
  23. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +137 -1
  24. package/dist/create/server-source/crates/feltdb/src/workload.rs +1427 -91
  25. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
  26. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
  27. package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
  28. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
  29. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +85 -25
  30. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
  31. package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
  32. package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
  33. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
  34. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
  35. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +3 -0
  36. package/dist/create/server-source/crates/feltdb-server/src/main.rs +879 -84
  37. package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
  38. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
  39. package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
  40. package/dist/db.d.ts +64 -9
  41. package/dist/db.d.ts.map +1 -1
  42. package/dist/db.js +153 -27
  43. package/dist/deployment.d.ts +19 -0
  44. package/dist/deployment.d.ts.map +1 -1
  45. package/dist/deployment.js +38 -2
  46. package/dist/embedded-query.d.ts.map +1 -1
  47. package/dist/embedded-query.js +5 -4
  48. package/dist/embedded-transaction.d.ts +8 -4
  49. package/dist/embedded-transaction.d.ts.map +1 -1
  50. package/dist/embedded-transaction.js +55 -19
  51. package/dist/error-codes.d.ts +31 -2
  52. package/dist/error-codes.d.ts.map +1 -1
  53. package/dist/error-codes.js +41 -2
  54. package/dist/feltdb.d.ts +7 -0
  55. package/dist/feltdb.d.ts.map +1 -1
  56. package/dist/file-db.d.ts +27 -0
  57. package/dist/file-db.d.ts.map +1 -1
  58. package/dist/file-db.js +145 -7
  59. package/dist/http-client.d.ts +11 -3
  60. package/dist/http-client.d.ts.map +1 -1
  61. package/dist/http-client.js +27 -14
  62. package/dist/http-db.d.ts +27 -1
  63. package/dist/http-db.d.ts.map +1 -1
  64. package/dist/http-db.js +252 -54
  65. package/dist/index.js +1 -1
  66. package/dist/local-state-lock.d.ts +34 -0
  67. package/dist/local-state-lock.d.ts.map +1 -0
  68. package/dist/local-state-lock.js +225 -0
  69. package/dist/reactive-graph.d.ts +0 -3
  70. package/dist/reactive-graph.d.ts.map +1 -1
  71. package/dist/reactive-graph.js +11 -1
  72. package/dist/runtime-registry.d.ts +7 -2
  73. package/dist/runtime-registry.d.ts.map +1 -1
  74. package/dist/runtime-registry.js +2 -2
  75. package/dist/studio/components/index.js +1 -1
  76. package/dist/studio/{components-BSGmHfif.js → components-CJmzntBi.js} +2 -1
  77. package/dist/studio/index.js +1 -1
  78. package/dist/studio-app/assets/{feltdb_wasm-3hDngl1h.js → feltdb_wasm-BjM1ylL3.js} +1 -1
  79. package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
  80. package/dist/studio-app/assets/index-1wd0uKua.js +30 -0
  81. package/dist/studio-app/index.html +1 -1
  82. package/dist/transaction.d.ts +27 -11
  83. package/dist/transaction.d.ts.map +1 -1
  84. package/dist/transaction.js +20 -14
  85. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  86. package/dist/wasm/package.json +1 -1
  87. package/dist/workload.d.ts +31 -3
  88. package/dist/workload.d.ts.map +1 -1
  89. package/dist/workload.js +28 -3
  90. package/package.json +1 -1
  91. package/dist/studio-app/assets/feltdb_wasm_bg-CFQT4gCy.wasm +0 -0
  92. package/dist/studio-app/assets/index-Dql1hS5m.js +0 -30
@@ -95,6 +95,10 @@ export function recordKey(collection, id) {
95
95
  return `${collection}:${id}`;
96
96
  }
97
97
  const SEGMENT = /^[A-Za-z0-9._-]{1,128}$/;
98
+ /** The version a guard fences on, whichever spelling supplied it. */
99
+ function fencedVersion(guard) {
100
+ return guard.expectedVersion ?? guard.ifVersion;
101
+ }
98
102
  /**
99
103
  * Whether the request is well-formed, judged without any stored state.
100
104
  *
@@ -109,6 +113,11 @@ function structuralRefusal(request) {
109
113
  if (request.operations.length === 0)
110
114
  return invalid('a transaction requires at least one operation');
111
115
  const seen = new Set();
116
+ for (const guarded of [...request.operations, ...(request.preconditions ?? [])]) {
117
+ if (guarded.ifVersion !== undefined && guarded.expectedVersion !== undefined && guarded.ifVersion !== guarded.expectedVersion) {
118
+ return invalid(`${guarded.collection}:${guarded.id} supplies ifVersion ${guarded.ifVersion} and expectedVersion ${guarded.expectedVersion}; they are the same predicate`);
119
+ }
120
+ }
112
121
  for (const operation of request.operations) {
113
122
  if (!SEGMENT.test(operation.collection) || !SEGMENT.test(operation.id)) {
114
123
  return invalid(`invalid collection or id: ${operation.collection}:${operation.id}`);
@@ -195,16 +204,24 @@ export function decideTransaction(request, state, digest) {
195
204
  }
196
205
  // Preconditions first, before any operation is staged, so a failure cannot
197
206
  // leave a prefix of the transaction decided.
207
+ //
208
+ // `ifVersion` is the public spelling of `expectedVersion` and reaches this
209
+ // boundary unnormalised from callers below `db.transaction` (collections,
210
+ // agent state, composition). It is the same predicate, so it is evaluated
211
+ // here rather than counted as "constrains something" and then skipped.
198
212
  const guards = [
199
- ...(request.preconditions ?? []).map(condition => ({ ...condition })),
213
+ ...(request.preconditions ?? []).map(condition => ({
214
+ ...condition,
215
+ expectedVersion: fencedVersion(condition),
216
+ })),
200
217
  ...request.operations
201
- .filter(operation => operation.expectedVersion !== undefined
218
+ .filter(operation => fencedVersion(operation) !== undefined
202
219
  || operation.expectedEpoch !== undefined
203
220
  || operation.expectedLeaseId !== undefined)
204
221
  .map(operation => ({
205
222
  collection: operation.collection,
206
223
  id: operation.id,
207
- expectedVersion: operation.expectedVersion,
224
+ expectedVersion: fencedVersion(operation),
208
225
  expectedEpoch: operation.expectedEpoch,
209
226
  expectedLeaseId: operation.expectedLeaseId,
210
227
  })),
@@ -214,11 +231,12 @@ export function decideTransaction(request, state, digest) {
214
231
  kind: 'reject',
215
232
  reason: 'this runtime cannot evaluate transaction preconditions, so it refuses the '
216
233
  + 'transaction rather than committing it unconditionally',
234
+ code: 'CONTRACT_UNSUPPORTED',
217
235
  };
218
236
  }
219
237
  for (const guard of guards) {
220
238
  if (!SEGMENT.test(guard.collection) || !SEGMENT.test(String(guard.id))) {
221
- return { kind: 'reject', reason: `invalid collection or id: ${guard.collection}:${guard.id}` };
239
+ return { kind: 'reject', reason: `invalid collection or id: ${guard.collection}:${guard.id}`, code: 'INVALID_REQUEST' };
222
240
  }
223
241
  const constrains = guard.requireAbsent === true
224
242
  || guard.expectedVersion !== undefined
@@ -228,6 +246,7 @@ export function decideTransaction(request, state, digest) {
228
246
  return {
229
247
  kind: 'reject',
230
248
  reason: `precondition on ${guard.collection}:${guard.id} constrains nothing`,
249
+ code: 'INVALID_REQUEST',
231
250
  };
232
251
  }
233
252
  const key = recordKey(guard.collection, String(guard.id));
@@ -237,7 +256,7 @@ export function decideTransaction(request, state, digest) {
237
256
  return {
238
257
  kind: 'reject',
239
258
  reason: `PRECONDITION_FAILED:${key}:record already exists`,
240
- failure: { predicate: 'present', collection: guard.collection, key },
259
+ failure: { predicate: 'present', collection: guard.collection, id: String(guard.id), key },
241
260
  };
242
261
  }
243
262
  continue;
@@ -246,7 +265,7 @@ export function decideTransaction(request, state, digest) {
246
265
  return {
247
266
  kind: 'reject',
248
267
  reason: `PRECONDITION_FAILED:${key}:record does not exist`,
249
- failure: { predicate: 'missing', collection: guard.collection, key },
268
+ failure: { predicate: 'missing', collection: guard.collection, id: String(guard.id), key },
250
269
  };
251
270
  }
252
271
  if (guard.expectedVersion !== undefined) {
@@ -258,6 +277,7 @@ export function decideTransaction(request, state, digest) {
258
277
  failure: {
259
278
  predicate: 'version',
260
279
  collection: guard.collection,
280
+ id: String(guard.id),
261
281
  key,
262
282
  expected: guard.expectedVersion,
263
283
  actual,
@@ -275,6 +295,7 @@ export function decideTransaction(request, state, digest) {
275
295
  failure: {
276
296
  predicate: 'epoch',
277
297
  collection: guard.collection,
298
+ id: String(guard.id),
278
299
  key,
279
300
  expected: guard.expectedEpoch,
280
301
  actual,
@@ -293,6 +314,7 @@ export function decideTransaction(request, state, digest) {
293
314
  failure: {
294
315
  predicate: 'lease',
295
316
  collection: guard.collection,
317
+ id: String(guard.id),
296
318
  key,
297
319
  expected: guard.expectedLeaseId,
298
320
  actual: held ?? null,
@@ -310,18 +332,19 @@ export function decideTransaction(request, state, digest) {
310
332
  kind: 'reject',
311
333
  reason: 'this runtime cannot evaluate read-basis fences inside its commit boundary, so it refuses the '
312
334
  + 'transaction rather than committing it unfenced',
335
+ code: 'CONTRACT_UNSUPPORTED',
313
336
  };
314
337
  }
315
338
  for (const fence of fences) {
316
339
  if (typeof fence?.token !== 'string' || !fence.token.startsWith(EMBEDDED_READ_BASIS_PREFIX)) {
317
- return { kind: 'reject', reason: 'a read basis was not issued by this authority' };
340
+ return { kind: 'reject', reason: 'a read basis was not issued by this authority', code: 'INVALID_REQUEST' };
318
341
  }
319
342
  let actual;
320
343
  try {
321
344
  actual = readBasisToken(fence.reads, { read: state.read, scan: state.scan });
322
345
  }
323
346
  catch (error) {
324
- return { kind: 'reject', reason: `invalid read basis: ${error instanceof Error ? error.message : String(error)}` };
347
+ return { kind: 'reject', reason: `invalid read basis: ${error instanceof Error ? error.message : String(error)}`, code: 'INVALID_REQUEST' };
325
348
  }
326
349
  if (actual !== fence.token) {
327
350
  const first = normaliseReadSet(fence.reads);
@@ -345,6 +368,7 @@ export function decideTransaction(request, state, digest) {
345
368
  return {
346
369
  kind: 'reject',
347
370
  reason: `invalid collection or id: ${operation.collection}:${operation.id}`,
371
+ code: 'INVALID_REQUEST',
348
372
  };
349
373
  }
350
374
  const key = recordKey(operation.collection, operation.id);
@@ -352,30 +376,38 @@ export function decideTransaction(request, state, digest) {
352
376
  return {
353
377
  kind: 'reject',
354
378
  reason: `PRECONDITION_FAILED:${key}:record already exists`,
355
- failure: { predicate: 'present', collection: operation.collection, key },
379
+ failure: { predicate: 'present', collection: operation.collection, id: operation.id, key },
356
380
  };
357
381
  }
358
382
  // A requireAbsent create begins the authority-owned version lifecycle at
359
- // 1. A write fenced by expectedVersion is validated at N and written at
360
- // N + 1. Both are resolved in the same decision the runtime applies
361
- // atomically. An unconditional write remains verbatim, and a delete has no
362
- // record left to carry a version.
383
+ // 1. A write fenced by expectedVersion -- on the operation itself or by a
384
+ // transaction-level precondition on the same record -- is validated at N
385
+ // and written at N + 1. Both are resolved in the same decision the runtime
386
+ // applies atomically. An unconditional write remains verbatim, and a
387
+ // delete has no record left to carry a version.
388
+ //
389
+ // Where the fence is declared does not matter, and must not: a guard
390
+ // `preconditions: [{ A, ifVersion: N }]` beside a write of A that left the
391
+ // version alone would let a second transaction guarded on N commit after
392
+ // the first, which is the exclusive progression the guard exists to
393
+ // provide. The Rust authority applies the same rule.
363
394
  //
364
395
  // The value the caller supplied for __version is replaced rather than
365
396
  // honoured, because a caller that computes a different next version must
366
397
  // not be able to install it.
367
398
  // See docs/architecture/transaction-version-contract.md.
399
+ const sameRecord = (guard) => guard.collection === operation.collection
400
+ && String(guard.id) === operation.id;
368
401
  const guardedCreate = operation.requireAbsent === true
369
- || guards.some(guard => guard.requireAbsent === true
370
- && guard.collection === operation.collection
371
- && String(guard.id) === operation.id);
402
+ || guards.some(guard => guard.requireAbsent === true && sameRecord(guard));
403
+ const fencedAt = guards.find(guard => guard.expectedVersion !== undefined && sameRecord(guard))?.expectedVersion;
372
404
  const value = operation.value === undefined
373
405
  ? undefined
374
406
  : guardedCreate
375
407
  ? { ...operation.value, id: operation.id, __version: 1 }
376
- : operation.expectedVersion === undefined
408
+ : fencedAt === undefined
377
409
  ? { ...operation.value, id: operation.id }
378
- : { ...operation.value, id: operation.id, __version: operation.expectedVersion + 1 };
410
+ : { ...operation.value, id: operation.id, __version: fencedAt + 1 };
379
411
  mutations.push({
380
412
  key,
381
413
  collection: operation.collection,
@@ -437,7 +469,11 @@ export function embeddedDuplicate(request, plan) {
437
469
  export class EmbeddedTransactionRejected extends Error {
438
470
  feltdbCode;
439
471
  feltdbConflict;
440
- /** Set when the request itself was malformed, as opposed to refused by state. */
472
+ /**
473
+ * Set when the request itself was malformed (`INVALID_REQUEST`) or asks for
474
+ * something this runtime cannot evaluate (`CONTRACT_UNSUPPORTED`), as
475
+ * opposed to refused by state.
476
+ */
441
477
  code;
442
478
  constructor(reason, failure, code) {
443
479
  super(reason);
@@ -53,13 +53,42 @@ export declare enum FeltDBErrorCode {
53
53
  SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
54
54
  AUTHORITY_SCOPE_REQUIRED = "AUTHORITY_SCOPE_REQUIRED",
55
55
  AUTHORITY_SCOPE_INVALID = "AUTHORITY_SCOPE_INVALID",
56
- AUTHORITY_SCOPE_MISMATCH = "AUTHORITY_SCOPE_MISMATCH"
56
+ AUTHORITY_SCOPE_MISMATCH = "AUTHORITY_SCOPE_MISMATCH",
57
+ /** A local state directory is open exclusively by another live process. */
58
+ STATE_LOCKED = "STATE_LOCKED",
59
+ /** Stored content no longer hashes to its address. The bytes were not returned. */
60
+ CONTENT_INTEGRITY_FAILURE = "CONTENT_INTEGRITY_FAILURE"
57
61
  }
58
62
  export declare class FeltDBServiceError extends Error {
59
63
  readonly code: FeltDBErrorCode | string;
60
64
  readonly requestId?: string | undefined;
61
65
  readonly status?: number | undefined;
62
- constructor(message: string, code: FeltDBErrorCode | string, requestId?: string | undefined, status?: number | undefined);
66
+ /** The authority's structured error body, when it answered with one. */
67
+ readonly body?: Record<string, unknown>;
68
+ constructor(message: string, code: FeltDBErrorCode | string, requestId?: string | undefined, status?: number | undefined, body?: Record<string, unknown>);
69
+ /** The body's structured `details`, when it carried any (e.g. a reused idempotency key's reason). */
70
+ get details(): Record<string, unknown> | undefined;
71
+ }
72
+ /**
73
+ * The local file runtime's state directory is held exclusively by another
74
+ * process. Nothing was opened, read, or modified.
75
+ *
76
+ * `owner` is what the lock file records about its holder. Close the other
77
+ * process, or, if it is gone and its lock could not be judged stale (another
78
+ * host, an unreadable lock), remove `lockPath` by hand.
79
+ */
80
+ export declare class LocalStateLockedError extends FeltDBServiceError {
81
+ readonly lockPath: string;
82
+ readonly owner: {
83
+ pid?: number;
84
+ host?: string;
85
+ acquiredAt?: string;
86
+ };
87
+ constructor(lockPath: string, owner: {
88
+ pid?: number;
89
+ host?: string;
90
+ acquiredAt?: string;
91
+ }, detail?: string);
63
92
  }
64
93
  /**
65
94
  * Error response structure that all FeltDB APIs must return
@@ -1 +1 @@
1
- {"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;GAEG;AACH,oBAAY,eAAe;IACzB,eAAe,oBAAoB;IACnC,YAAY,iBAAiB;IAC7B,gBAAgB,qBAAqB;IACrC,eAAe,oBAAoB;IACnC,cAAc,mBAAmB;IACjC,sBAAsB,2BAA2B;IACjD,kBAAkB,uBAAuB;IACzC,gBAAgB,qBAAqB;IACrC,oBAAoB,yBAAyB;IAC7C,6BAA6B;IAC7B,EAAE,OAAO;IAET,wEAAwE;IACxE,QAAQ,aAAa;IAErB,2DAA2D;IAC3D,mBAAmB,wBAAwB;IAE3C,gEAAgE;IAChE,QAAQ,aAAa;IAErB,6DAA6D;IAC7D,cAAc,mBAAmB;IACjC,uBAAuB,4BAA4B;IACnD,qBAAqB,0BAA0B;IAC/C,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,gBAAgB,qBAAqB;IACrC,oBAAoB,yBAAyB;IAC7C,gFAAgF;IAChF,wBAAwB,6BAA6B;IACrD;sEACkE;IAClE,sBAAsB,2BAA2B;IACjD,aAAa,kBAAkB;IAC/B,oBAAoB,yBAAyB;IAC7C,kBAAkB,uBAAuB;IACzC,eAAe,oBAAoB;IACnC,oBAAoB,yBAAyB;IAC7C,gBAAgB,qBAAqB;IACrC,mBAAmB,wBAAwB;IAC3C,wBAAwB,6BAA6B;IACrD,uBAAuB,4BAA4B;IACnD,wBAAwB,6BAA6B;CACtD;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAGzC,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;gBAHxB,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,eAAe,GAAG,MAAM,EAC9B,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,MAAM,CAAC,EAAE,MAAM,YAAA;CAE3B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC;IAE/B,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IAEnB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IAEpB,gEAAgE;IAChE,aAAa,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;CAC1F;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,OAAO,CAGxE;AAED,MAAM,MAAM,yBAAyB,GACjC,WAAW,GACX,eAAe,GACf,yBAAyB,GACzB,4BAA4B,CAAC;AAEjC,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,yBAAyB,CAevF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,qBAAqB,GAAG,gBAAgB,GAAG,YAAY,CAQxH"}
1
+ {"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"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"}
@@ -55,17 +55,53 @@ export var FeltDBErrorCode;
55
55
  FeltDBErrorCode["AUTHORITY_SCOPE_REQUIRED"] = "AUTHORITY_SCOPE_REQUIRED";
56
56
  FeltDBErrorCode["AUTHORITY_SCOPE_INVALID"] = "AUTHORITY_SCOPE_INVALID";
57
57
  FeltDBErrorCode["AUTHORITY_SCOPE_MISMATCH"] = "AUTHORITY_SCOPE_MISMATCH";
58
+ /** A local state directory is open exclusively by another live process. */
59
+ FeltDBErrorCode["STATE_LOCKED"] = "STATE_LOCKED";
60
+ /** Stored content no longer hashes to its address. The bytes were not returned. */
61
+ FeltDBErrorCode["CONTENT_INTEGRITY_FAILURE"] = "CONTENT_INTEGRITY_FAILURE";
58
62
  })(FeltDBErrorCode || (FeltDBErrorCode = {}));
59
63
  export class FeltDBServiceError extends Error {
60
64
  code;
61
65
  requestId;
62
66
  status;
63
- constructor(message, code, requestId, status) {
67
+ /** The authority's structured error body, when it answered with one. */
68
+ body;
69
+ constructor(message, code, requestId, status, body) {
64
70
  super(message);
65
71
  this.code = code;
66
72
  this.requestId = requestId;
67
73
  this.status = status;
68
74
  this.name = 'FeltDBServiceError';
75
+ if (body !== undefined)
76
+ this.body = body;
77
+ }
78
+ /** The body's structured `details`, when it carried any (e.g. a reused idempotency key's reason). */
79
+ get details() {
80
+ const details = this.body?.details;
81
+ return details && typeof details === 'object' && !Array.isArray(details) ? details : undefined;
82
+ }
83
+ }
84
+ /**
85
+ * The local file runtime's state directory is held exclusively by another
86
+ * process. Nothing was opened, read, or modified.
87
+ *
88
+ * `owner` is what the lock file records about its holder. Close the other
89
+ * process, or, if it is gone and its lock could not be judged stale (another
90
+ * host, an unreadable lock), remove `lockPath` by hand.
91
+ */
92
+ export class LocalStateLockedError extends FeltDBServiceError {
93
+ lockPath;
94
+ owner;
95
+ constructor(lockPath, owner, detail) {
96
+ super(`STATE_LOCKED: ${lockPath.replace(/[\\/][^\\/]+$/, '')} is open exclusively by `
97
+ + `${owner.pid === undefined ? 'another process' : `process ${owner.pid}`}`
98
+ + `${owner.host ? ` on ${owner.host}` : ''}${owner.acquiredAt ? ` since ${owner.acquiredAt}` : ''}. `
99
+ + (detail ? `${detail} ` : '')
100
+ + 'Close that process first, or open with createFeltDB({ path, access: \'shared\' }) if several '
101
+ + 'processes are meant to share this state.', FeltDBErrorCode.STATE_LOCKED);
102
+ this.lockPath = lockPath;
103
+ this.owner = owner;
104
+ this.name = 'LocalStateLockedError';
69
105
  }
70
106
  }
71
107
  /**
@@ -81,7 +117,10 @@ export function classifyError(code) {
81
117
  return 'retryable';
82
118
  if (code === FeltDBErrorCode.CONFLICT || code === FeltDBErrorCode.VERSION_CONFLICT
83
119
  || code === FeltDBErrorCode.IDEMPOTENCY_CONFLICT
84
- || code === FeltDBErrorCode.COMMIT_OUTCOME_UNKNOWN)
120
+ || code === FeltDBErrorCode.COMMIT_OUTCOME_UNKNOWN
121
+ // A commit the authority could not make durable has an unknown outcome:
122
+ // reconcile by retrying with the same transaction id, never by assuming.
123
+ || code === FeltDBErrorCode.DURABILITY_FAILURE)
85
124
  return 'requires_reconciliation';
86
125
  if (code === FeltDBErrorCode.PRECONDITION_FAILED
87
126
  || code === FeltDBErrorCode.VALIDATION_ERROR
package/dist/feltdb.d.ts CHANGED
@@ -67,6 +67,13 @@ export interface JsDb {
67
67
  delete?(key: string): any | Promise<any>;
68
68
  /** Subscribe to runtime-originated changes, including remote mutations. */
69
69
  subscribe_changes?(callback: (collection: string) => void, collection?: string): () => void;
70
+ /** Content-addressed immutable bytes (server and local file runtimes). */
71
+ storeContent?(content: Uint8Array): Promise<{
72
+ hash: string;
73
+ bytes: number;
74
+ ref: string;
75
+ }>;
76
+ acquireContent?(hash: string): Promise<Uint8Array | null>;
70
77
  close?(): void | Promise<void>;
71
78
  /**
72
79
  * Get capability records
@@ -1 +1 @@
1
- {"version":3,"file":"feltdb.d.ts","sourceRoot":"","sources":["../src/feltdb.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feltdb.d.ts","sourceRoot":"","sources":["../src/feltdb.ts"],"names":[],"mappings":"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"}
package/dist/file-db.d.ts CHANGED
@@ -57,6 +57,15 @@ export interface FileJsDbOptions {
57
57
  };
58
58
  /** Collect persistence timings. Also enabled by `FELTDB_PERSISTENCE_PROFILE=1`. */
59
59
  profile?: boolean;
60
+ /**
61
+ * `shared` (the default for a directly constructed `FileJsDb`): any number
62
+ * of processes may open the directory; each commit is serialized by
63
+ * `state.lock`. `exclusive` (the default of `createFeltDB({ path })`): this
64
+ * process takes `owner.lock` at open and another process opening the same
65
+ * directory exclusively *or shared* is refused with `LocalStateLockedError`
66
+ * until `close()` or process exit. Handles in one process share the lock.
67
+ */
68
+ access?: 'shared' | 'exclusive';
60
69
  }
61
70
  export interface PersistenceStatus {
62
71
  format: 'none' | 'legacy-snapshot' | 'snapshot+journal';
@@ -91,7 +100,16 @@ export declare class FileJsDb implements JsDb {
91
100
  private readonly profiler;
92
101
  private readonly compaction;
93
102
  private compactionScheduled;
103
+ private releaseOwnerLock;
104
+ /** How this handle opened its directory. */
105
+ readonly access: 'shared' | 'exclusive';
94
106
  constructor(path: string, options?: FileJsDbOptions);
107
+ /**
108
+ * A shared open still respects an exclusive owner in another process: a
109
+ * process that asked for exclusive access must not find a second writer.
110
+ * Probing takes no lock of its own.
111
+ */
112
+ private assertNotHeldExclusively;
95
113
  private journalPath;
96
114
  private snapshotKey;
97
115
  private parseSnapshot;
@@ -283,6 +301,15 @@ export declare class FileJsDb implements JsDb {
283
301
  conflictCode?: string;
284
302
  item?: any;
285
303
  }>;
304
+ private contentDirectory;
305
+ private static sha256;
306
+ storeContent(content: Uint8Array): Promise<{
307
+ hash: string;
308
+ bytes: number;
309
+ ref: string;
310
+ }>;
311
+ acquireContent(hash: string): Promise<Uint8Array | null>;
312
+ private fsyncDirectory;
286
313
  close(): void;
287
314
  }
288
315
  //# sourceMappingURL=file-db.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-db.d.ts","sourceRoot":"","sources":["../src/file-db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-db.d.ts","sourceRoot":"","sources":["../src/file-db.ts"],"names":[],"mappings":"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"}
package/dist/file-db.js CHANGED
@@ -2,9 +2,11 @@ import { validateOperationAdmissionInput, operationsConflict, generateOperationI
2
2
  import { FeltDBErrorCode, FeltDBServiceError } from './error-codes.js';
3
3
  import * as nodeFs from 'fs';
4
4
  import * as nodePath from 'path';
5
+ import { createHash as nodeCreateHash } from 'crypto';
5
6
  import { TransactionIdConflictError, TransactionIdUnverifiableError, normaliseReadSet } from './transaction.js';
6
7
  import { decideTransaction, readBasisToken, scanRows, embeddedDuplicate, embeddedResult, prepareTransaction, refusalError, } from './embedded-transaction.js';
7
8
  import { EmbeddedQueryEngine } from './embedded-query.js';
9
+ import { LOCAL_STATE_LOCK_FILE, acquireLocalStateLock } from './local-state-lock.js';
8
10
  import { encodeRecord, scanJournal, JournalCorruptionError, PersistenceProfiler, } from './file-journal.js';
9
11
  export { JournalCorruptionError } from './file-journal.js';
10
12
  /** The newest local file snapshot format this build reads and writes. */
@@ -71,6 +73,9 @@ export class FileJsDb {
71
73
  profiler;
72
74
  compaction;
73
75
  compactionScheduled = false;
76
+ releaseOwnerLock = null;
77
+ /** How this handle opened its directory. */
78
+ access;
74
79
  constructor(path, options = {}) {
75
80
  const nodePath = getPathSync();
76
81
  const nodeFs = getFsSync();
@@ -96,13 +101,43 @@ export class FileJsDb {
96
101
  }
97
102
  // Generate stable instance ID based on path
98
103
  this.origin = `file:${this.dataPath}`;
99
- // Clean up any stale locks from previous crashes on startup
100
- this.cleanupStaleLock();
101
- // Load or initialize state
102
- this.state = this.initializeState();
103
- this.loadDurableState();
104
- this.queryEngine = new EmbeddedQueryEngine(() => Object.entries(this.state.rows));
105
- this.indexedSequence = this.state.sequence;
104
+ this.access = options.access ?? 'shared';
105
+ if (this.access !== 'shared' && this.access !== 'exclusive') {
106
+ throw new Error(`access must be 'shared' or 'exclusive', not ${String(options.access)}`);
107
+ }
108
+ if (this.access === 'exclusive') {
109
+ this.releaseOwnerLock = acquireLocalStateLock(this.dataPath);
110
+ }
111
+ else {
112
+ this.assertNotHeldExclusively(nodePath.join(this.dataPath, LOCAL_STATE_LOCK_FILE));
113
+ }
114
+ try {
115
+ // Clean up any stale locks from previous crashes on startup
116
+ this.cleanupStaleLock();
117
+ // Load or initialize state
118
+ this.state = this.initializeState();
119
+ this.loadDurableState();
120
+ this.queryEngine = new EmbeddedQueryEngine(() => Object.entries(this.state.rows));
121
+ this.indexedSequence = this.state.sequence;
122
+ }
123
+ catch (error) {
124
+ this.releaseOwnerLock?.();
125
+ this.releaseOwnerLock = null;
126
+ throw error;
127
+ }
128
+ }
129
+ /**
130
+ * A shared open still respects an exclusive owner in another process: a
131
+ * process that asked for exclusive access must not find a second writer.
132
+ * Probing takes no lock of its own.
133
+ */
134
+ assertNotHeldExclusively(lockPath) {
135
+ const nodeFs = getFsSync();
136
+ if (!nodeFs.existsSync(lockPath))
137
+ return;
138
+ // acquire-then-release judges liveness and recovers a stale lock exactly
139
+ // as an exclusive open would; it refuses when a live process holds it.
140
+ acquireLocalStateLock(this.dataPath)();
106
141
  }
107
142
  /* ------------------------------------------------------------------------
108
143
  * Durable layout
@@ -1442,8 +1477,111 @@ export class FileJsDb {
1442
1477
  console.log(`[CAS-${casId}] lock released, EXIT`);
1443
1478
  }
1444
1479
  }
1480
+ /* ------------------------------------------------------------------------
1481
+ * Content store
1482
+ *
1483
+ * Immutable bytes addressed by SHA-256, under `<state dir>/content/<hash>`:
1484
+ * the same contract as the server's `PUT /content` / `GET /content/{hash}`.
1485
+ * A blob is written to a temporary file, fsynced, renamed into place, and
1486
+ * the directory fsynced, so it is durable before `storeContent` returns and
1487
+ * never visible half-written. Every read is re-hashed; bytes that no longer
1488
+ * match their address are refused, never returned. Content is not indexed
1489
+ * state and is never deleted by FeltDB.
1490
+ * ---------------------------------------------------------------------- */
1491
+ contentDirectory() {
1492
+ return getPathSync().join(this.dataPath, 'content');
1493
+ }
1494
+ static sha256(bytes) {
1495
+ return nodeCreateHash('sha256').update(bytes).digest('hex');
1496
+ }
1497
+ async storeContent(content) {
1498
+ if (!(content instanceof Uint8Array)) {
1499
+ throw new FeltDBServiceError('INVALID_REQUEST: content must be a Uint8Array', FeltDBErrorCode.INVALID_REQUEST);
1500
+ }
1501
+ if (content.byteLength === 0) {
1502
+ throw new FeltDBServiceError('INVALID_REQUEST: content body must not be empty', FeltDBErrorCode.INVALID_REQUEST);
1503
+ }
1504
+ const nodeFs = getFsSync();
1505
+ const nodePath = getPathSync();
1506
+ const bytes = Buffer.from(content.buffer, content.byteOffset, content.byteLength);
1507
+ const hash = FileJsDb.sha256(bytes);
1508
+ const directory = this.contentDirectory();
1509
+ const target = nodePath.join(directory, hash);
1510
+ if (!nodeFs.existsSync(directory)) {
1511
+ nodeFs.mkdirSync(directory, { recursive: true });
1512
+ this.fsyncDirectory(this.dataPath);
1513
+ }
1514
+ try {
1515
+ const existing = nodeFs.readFileSync(target);
1516
+ if (FileJsDb.sha256(existing) === hash)
1517
+ return { hash, bytes: bytes.length, ref: `sha256:${hash}` };
1518
+ // A damaged copy is replaced by the verified bytes now in hand.
1519
+ }
1520
+ catch (error) {
1521
+ if (!isMissing(error))
1522
+ throw error;
1523
+ }
1524
+ const temporary = nodePath.join(directory, `.${hash}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`);
1525
+ const fd = nodeFs.openSync(temporary, 'wx', 0o600);
1526
+ try {
1527
+ writeFully(fd, bytes, 0);
1528
+ nodeFs.fsyncSync(fd);
1529
+ }
1530
+ finally {
1531
+ nodeFs.closeSync(fd);
1532
+ }
1533
+ try {
1534
+ nodeFs.renameSync(temporary, target);
1535
+ }
1536
+ catch (error) {
1537
+ try {
1538
+ nodeFs.unlinkSync(temporary);
1539
+ }
1540
+ catch { /* best effort */ }
1541
+ throw error;
1542
+ }
1543
+ this.fsyncDirectory(directory);
1544
+ return { hash, bytes: bytes.length, ref: `sha256:${hash}` };
1545
+ }
1546
+ async acquireContent(hash) {
1547
+ // The bare lowercase hex digest, exactly as the server's GET /content/{hash} takes it.
1548
+ const address = hash;
1549
+ if (typeof address !== 'string' || !/^[0-9a-f]{64}$/.test(address)) {
1550
+ throw new FeltDBServiceError('INVALID_REQUEST: invalid sha256 content hash', FeltDBErrorCode.INVALID_REQUEST);
1551
+ }
1552
+ let bytes;
1553
+ try {
1554
+ bytes = getFsSync().readFileSync(getPathSync().join(this.contentDirectory(), address));
1555
+ }
1556
+ catch (error) {
1557
+ if (isMissing(error))
1558
+ return null;
1559
+ throw error;
1560
+ }
1561
+ if (FileJsDb.sha256(bytes) !== address) {
1562
+ throw new FeltDBServiceError(`CONTENT_INTEGRITY_FAILURE: stored content ${address} failed verification; it was not returned`, FeltDBErrorCode.CONTENT_INTEGRITY_FAILURE);
1563
+ }
1564
+ return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
1565
+ }
1566
+ fsyncDirectory(directory) {
1567
+ const nodeFs = getFsSync();
1568
+ let fd;
1569
+ try {
1570
+ fd = nodeFs.openSync(directory, 'r');
1571
+ nodeFs.fsyncSync(fd);
1572
+ }
1573
+ catch {
1574
+ // Some platforms cannot fsync a directory; the rename is still atomic.
1575
+ }
1576
+ finally {
1577
+ if (fd !== undefined)
1578
+ nodeFs.closeSync(fd);
1579
+ }
1580
+ }
1445
1581
  close() {
1446
1582
  // Mutations are durable before they return. Closing a stale handle must
1447
1583
  // never rewrite authority state produced by another process.
1584
+ this.releaseOwnerLock?.();
1585
+ this.releaseOwnerLock = null;
1448
1586
  }
1449
1587
  }