@feltdb/core 0.12.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/agent-runtime.d.ts +64 -2
  2. package/dist/agent-runtime.d.ts.map +1 -1
  3. package/dist/agent-runtime.js +121 -11
  4. package/dist/agent-state.d.ts +48 -0
  5. package/dist/agent-state.d.ts.map +1 -1
  6. package/dist/agent-state.js +174 -12
  7. package/dist/agent.d.ts +10 -1
  8. package/dist/agent.d.ts.map +1 -1
  9. package/dist/agent.js +10 -1
  10. package/dist/build-identity.json +4 -4
  11. package/dist/cli/commands.js +34 -7
  12. package/dist/cli/workspace-integration.js +8 -0
  13. package/dist/collection.d.ts +3 -1
  14. package/dist/collection.d.ts.map +1 -1
  15. package/dist/collection.js +30 -8
  16. package/dist/create/build-identity.json +4 -4
  17. package/dist/create/cli.js +47 -38
  18. package/dist/create/create.js +21 -8
  19. package/dist/create/package-versions.js +1 -1
  20. package/dist/create/server-source/Cargo.lock +6 -6
  21. package/dist/create/server-source/Cargo.toml +1 -1
  22. package/dist/create/server-source/crates/feltdb/src/lib.rs +126 -35
  23. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +162 -53
  24. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +341 -2
  25. package/dist/create/server-source/crates/feltdb/src/workload.rs +2094 -126
  26. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +18 -12
  27. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +17 -5
  28. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
  29. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
  30. package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
  31. package/dist/create/server-source/crates/feltdb-server/src/agent_execution.rs +511 -0
  32. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
  33. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +113 -25
  34. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
  35. package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
  36. package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
  37. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
  38. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
  39. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +4 -0
  40. package/dist/create/server-source/crates/feltdb-server/src/main.rs +1740 -236
  41. package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
  42. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
  43. package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
  44. package/dist/create/setup-summary.js +40 -0
  45. package/dist/db.d.ts +91 -10
  46. package/dist/db.d.ts.map +1 -1
  47. package/dist/db.js +170 -31
  48. package/dist/deployment.d.ts +19 -0
  49. package/dist/deployment.d.ts.map +1 -1
  50. package/dist/deployment.js +38 -2
  51. package/dist/development-runtime-bridge.d.ts +20 -0
  52. package/dist/development-runtime-bridge.d.ts.map +1 -1
  53. package/dist/development-runtime-bridge.js +61 -12
  54. package/dist/embedded-query.d.ts.map +1 -1
  55. package/dist/embedded-query.js +5 -4
  56. package/dist/embedded-transaction.d.ts +8 -4
  57. package/dist/embedded-transaction.d.ts.map +1 -1
  58. package/dist/embedded-transaction.js +55 -19
  59. package/dist/error-codes.d.ts +31 -2
  60. package/dist/error-codes.d.ts.map +1 -1
  61. package/dist/error-codes.js +41 -2
  62. package/dist/feltdb.d.ts +7 -0
  63. package/dist/feltdb.d.ts.map +1 -1
  64. package/dist/file-db.d.ts +27 -0
  65. package/dist/file-db.d.ts.map +1 -1
  66. package/dist/file-db.js +145 -7
  67. package/dist/http-client.d.ts +11 -3
  68. package/dist/http-client.d.ts.map +1 -1
  69. package/dist/http-client.js +27 -14
  70. package/dist/http-db.d.ts +40 -1
  71. package/dist/http-db.d.ts.map +1 -1
  72. package/dist/http-db.js +285 -58
  73. package/dist/index.js +1 -1
  74. package/dist/local-state-lock.d.ts +34 -0
  75. package/dist/local-state-lock.d.ts.map +1 -0
  76. package/dist/local-state-lock.js +225 -0
  77. package/dist/reactive-graph.d.ts +0 -3
  78. package/dist/reactive-graph.d.ts.map +1 -1
  79. package/dist/reactive-graph.js +11 -1
  80. package/dist/runtime-registry.d.ts +7 -2
  81. package/dist/runtime-registry.d.ts.map +1 -1
  82. package/dist/runtime-registry.js +2 -2
  83. package/dist/studio/{KeyManagementPanel-D5FMvvU9.js → KeyManagementPanel-skUNnKRw.js} +36 -29
  84. package/dist/studio/app.d.ts +8 -1
  85. package/dist/studio/app.d.ts.map +1 -1
  86. package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -1
  87. package/dist/studio/components/KeyManagementPanel.js +1 -1
  88. package/dist/studio/components/index.js +2 -2
  89. package/dist/studio/{components-B4eKIUN5.js → components-CJmzntBi.js} +8 -7
  90. package/dist/studio/control-plane/Data.d.ts.map +1 -1
  91. package/dist/studio/control-plane/Instance.d.ts +4 -1
  92. package/dist/studio/control-plane/Instance.d.ts.map +1 -1
  93. package/dist/studio/control-plane/Operations.d.ts +4 -1
  94. package/dist/studio/control-plane/Operations.d.ts.map +1 -1
  95. package/dist/studio/control-plane/index.js +2 -2
  96. package/dist/studio/control-plane/primitives.d.ts +16 -0
  97. package/dist/studio/control-plane/primitives.d.ts.map +1 -1
  98. package/dist/studio/{control-plane-fxMcJn74.js → control-plane-CaBA7Rgv.js} +448 -424
  99. package/dist/studio/index.d.ts +1 -0
  100. package/dist/studio/index.d.ts.map +1 -1
  101. package/dist/studio/index.js +384 -247
  102. package/dist/studio/navigation.d.ts +57 -0
  103. package/dist/studio/navigation.d.ts.map +1 -0
  104. package/dist/studio/studio.css +1 -1
  105. package/dist/studio/utils/control-plane-api.d.ts +2 -0
  106. package/dist/studio/utils/control-plane-api.d.ts.map +1 -1
  107. package/dist/studio/utils/control-plane-api.js +5 -1
  108. package/dist/studio-app/assets/{feltdb_wasm-BatwwogY.js → feltdb_wasm-BjM1ylL3.js} +1 -1
  109. package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
  110. package/dist/studio-app/assets/index-1wd0uKua.js +30 -0
  111. package/dist/studio-app/assets/{index-CiC8VY-a.css → index-vi21oEQa.css} +1 -1
  112. package/dist/studio-app/index.html +2 -2
  113. package/dist/transaction.d.ts +27 -11
  114. package/dist/transaction.d.ts.map +1 -1
  115. package/dist/transaction.js +20 -14
  116. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  117. package/dist/wasm/package.json +1 -1
  118. package/dist/workload.d.ts +31 -3
  119. package/dist/workload.d.ts.map +1 -1
  120. package/dist/workload.js +28 -3
  121. package/dist/workspace/local-development-authority.d.ts +19 -0
  122. package/dist/workspace/local-development-authority.d.ts.map +1 -1
  123. package/dist/workspace/local-development-authority.js +335 -15
  124. package/package.json +1 -1
  125. package/dist/studio-app/assets/feltdb_wasm_bg-BX0newOr.wasm +0 -0
  126. package/dist/studio-app/assets/index-DoVvbIay.js +0 -30
@@ -42,25 +42,76 @@ function safeBridgeUrl(value) {
42
42
  }
43
43
  }
44
44
  let warnedMismatch = false;
45
+ function loopbackOrigin(value) {
46
+ if (!value)
47
+ return undefined;
48
+ try {
49
+ const url = new URL(value);
50
+ const host = ['localhost', '127.0.0.1', '::1', '[::1]'].includes(url.hostname) ? 'loopback' : url.hostname;
51
+ return `${url.protocol}//${host}:${url.port || (url.protocol === 'https:' ? '443' : '80')}`;
52
+ }
53
+ catch {
54
+ return undefined;
55
+ }
56
+ }
57
+ /** The authority a client is connected to, compared as an endpoint: `localhost` and `127.0.0.1` are one host. */
58
+ export function sameAuthority(left, right) {
59
+ const a = loopbackOrigin(left);
60
+ return a !== undefined && a === loopbackOrigin(right);
61
+ }
62
+ /**
63
+ * Whether a database belongs to a development session: the same namespace, and
64
+ * either the same embedded runtime or a remote connection to the session's own
65
+ * authority. A browser application of a Node.js-authority project is the
66
+ * second case — it runs in the browser but its state is the session's.
67
+ */
68
+ export function developmentConnectionMatches(session, connection) {
69
+ if (session.namespace !== connection.namespace)
70
+ return false;
71
+ if (connection.runtime === 'remote') {
72
+ if (connection.authorityUrl)
73
+ return sameAuthority(connection.authorityUrl, session.authorityUrl);
74
+ return ['managed', 'self-hosted', 'remote'].includes(session.runtime);
75
+ }
76
+ return session.runtime === connection.runtime;
77
+ }
45
78
  /**
46
79
  * A development session was supplied but belongs to a different database than
47
80
  * the one being opened. Studio would show this app as "Not connected" with no
48
- * cause, so say what differs once instead of skipping registration silently.
81
+ * cause, so say what differs, and what to change, once instead of skipping
82
+ * registration silently.
49
83
  */
50
84
  function warnSessionMismatch(session, input) {
51
85
  if (warnedMismatch)
52
86
  return;
53
87
  warnedMismatch = true;
54
- const differences = [
55
- session.namespace !== input.namespace ? `namespace "${input.namespace}" (session expects "${session.namespace}")` : '',
56
- session.runtime !== input.runtime ? `runtime "${input.runtime}" (session expects "${session.runtime}")` : '',
57
- ].filter(Boolean).join(' and ');
58
- console.warn(`[feltdb] This database opened with ${differences}, so it is not registered with the running \`feltdb dev\` session and Studio will report the application as not connected. `
59
- + 'Pass the session namespace to createFeltDB({ namespace }).');
88
+ const differences = [];
89
+ const advice = [];
90
+ if (session.namespace !== input.namespace) {
91
+ differences.push(`namespace "${input.namespace}" (session expects "${session.namespace}")`);
92
+ advice.push('pass the session namespace to createFeltDB({ namespace })');
93
+ }
94
+ if (input.runtime === 'remote' && input.authorityUrl && !sameAuthority(input.authorityUrl, session.authorityUrl)) {
95
+ differences.push(`authority ${input.authorityUrl} (session authority is ${session.authorityUrl})`);
96
+ advice.push('connect to the session authority (VITE_FELTDB_AUTHORITY_URL) or start `feltdb dev` against this authority');
97
+ }
98
+ else if (session.namespace === input.namespace) {
99
+ differences.push(`runtime "${input.runtime}" (session expects "${session.runtime}")`);
100
+ advice.push(session.runtime === 'browser'
101
+ ? 'open the database in the browser runtime'
102
+ : `connect to the session authority with createFeltDB({ namespace, server: { url: ${JSON.stringify(session.authorityUrl)} } })`);
103
+ }
104
+ console.warn(`[feltdb] This database opened with ${differences.join(' and ')}, so it is not registered with the running \`feltdb dev\` session and Studio will report the application as not connected. `
105
+ + `To connect it, ${advice.join(' and ')}.`);
60
106
  }
61
107
  /** Internal, optional registration hook called by Core runtime construction. */
62
108
  export function attachDevelopmentRuntimeBridge(input) {
63
109
  const runtimeInstanceId = randomId();
110
+ const connection = {
111
+ namespace: input.namespace,
112
+ runtime: input.runtime,
113
+ ...(input.authorityUrl ? { authorityUrl: input.authorityUrl } : {}),
114
+ };
64
115
  let activeSession;
65
116
  let heartbeat;
66
117
  let flushTimer;
@@ -74,19 +125,17 @@ export function attachDevelopmentRuntimeBridge(input) {
74
125
  || 'application';
75
126
  const register = async (candidate) => {
76
127
  const session = candidate || configuredSession || processSession();
77
- const compatibleRuntime = session?.runtime === input.runtime
78
- || (input.runtime === 'remote' && ['managed', 'self-hosted', 'remote'].includes(session?.runtime || ''));
79
128
  if (!session)
80
129
  return;
81
- if (session.namespace !== input.namespace || !compatibleRuntime) {
82
- warnSessionMismatch(session, input);
130
+ if (!developmentConnectionMatches(session, connection)) {
131
+ warnSessionMismatch(session, connection);
83
132
  return;
84
133
  }
85
134
  const bridgeUrl = safeBridgeUrl(session.bridgeUrl);
86
135
  if (!bridgeUrl)
87
136
  return;
88
137
  activeSession = { ...session, bridgeUrl };
89
- const registration = { ...activeSession, runtimeInstanceId, applicationId };
138
+ const registration = { ...activeSession, runtimeInstanceId, applicationId, connection };
90
139
  try {
91
140
  const response = await fetch(`${bridgeUrl}/api/v1/development/runtime/register`, {
92
141
  method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(registration),
@@ -1 +1 @@
1
- {"version":3,"file":"embedded-query.d.ts","sourceRoot":"","sources":["../src/embedded-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAG9E,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAInC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,aAAa,GAAG,cAAc,GAAG,WAAW,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAgDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CASrH;AAkCD,kFAAkF;AAClF,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,OAAO,CAAmC;gBAErB,OAAO,EAAE,MAAM,QAAQ,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAIvE,OAAO,IAAI,IAAI;IAMf,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI;IAgCpD,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,IAAI;IAqBZ,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,wBAAwB;IAK/D,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,qBAAqB,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG;QAAE,KAAK,EAAE,kBAAkB,CAAA;KAAE;IAyErG,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,QAAQ;CAkBjB"}
1
+ {"version":3,"file":"embedded-query.d.ts","sourceRoot":"","sources":["../src/embedded-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAI9E,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAInC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,aAAa,GAAG,cAAc,GAAG,WAAW,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAgDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CASrH;AAkCD,kFAAkF;AAClF,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,OAAO,CAAmC;gBAErB,OAAO,EAAE,MAAM,QAAQ,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAIvE,OAAO,IAAI,IAAI;IAMf,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI;IAgCpD,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,IAAI;IAqBZ,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,wBAAwB;IAK/D,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,qBAAqB,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG;QAAE,KAAK,EAAE,kBAAkB,CAAA;KAAE;IAyErG,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,QAAQ;CAkBjB"}
@@ -1,3 +1,4 @@
1
+ import { FeltDBErrorCode, FeltDBServiceError } from './error-codes.js';
1
2
  const now = () => typeof performance !== 'undefined' ? performance.now() : Date.now();
2
3
  function compareValue(left, right) {
3
4
  if (left === right)
@@ -78,7 +79,7 @@ function decode(cursor, expectedBinding) {
78
79
  return value;
79
80
  }
80
81
  catch {
81
- throw new Error('INVALID_CURSOR: cursor is malformed or does not match this query');
82
+ throw new FeltDBServiceError('INVALID_CURSOR: cursor is malformed or does not match this query', FeltDBErrorCode.INVALID_CURSOR);
82
83
  }
83
84
  }
84
85
  /** Small deterministic planner/executor owned by an embedded storage boundary. */
@@ -331,7 +332,7 @@ export class EmbeddedQueryEngine {
331
332
  }
332
333
  validate(query) {
333
334
  if (!query.collection?.trim() || !Number.isInteger(query.limit) || query.limit < 1 || query.limit > 1_000)
334
- throw new Error('INVALID_QUERY: collection and a limit between 1 and 1000 are required');
335
+ throw new FeltDBServiceError('INVALID_QUERY: collection and a limit between 1 and 1000 are required', 'INVALID_QUERY');
335
336
  for (const condition of query.where ?? []) {
336
337
  // Every key beside `field` must be exactly one known operator. A stray
337
338
  // key — a `semantic` clause misplaced into a condition, or anything
@@ -340,13 +341,13 @@ export class EmbeddedQueryEngine {
340
341
  const keys = Object.keys(condition).filter(key => key !== 'field');
341
342
  const operators = keys.filter(operator => ['eq', 'neq', 'lt', 'lte', 'gt', 'gte'].includes(operator));
342
343
  if (!condition.field || operators.length !== 1 || keys.length !== 1)
343
- throw new Error('INVALID_QUERY: each condition requires a field and exactly one operator');
344
+ throw new FeltDBServiceError('INVALID_QUERY: each condition requires a field and exactly one operator', 'INVALID_QUERY');
344
345
  }
345
346
  if (query.semantic !== undefined) {
346
347
  // Semantic composition runs where the Rust decision primitive runs. This
347
348
  // embedded engine has no runtime binding, so it refuses the clause
348
349
  // rather than answering the deterministic query in its place.
349
- throw new Error('SEMANTIC_UNSUPPORTED: this runtime has no semantic runtime binding; semantic query composition is available through the managed authority');
350
+ throw new FeltDBServiceError('SEMANTIC_UNSUPPORTED: this runtime has no semantic runtime binding; semantic query composition is available through the managed authority', 'SEMANTIC_UNSUPPORTED');
350
351
  }
351
352
  }
352
353
  }
@@ -126,7 +126,7 @@ export type EmbeddedPlan =
126
126
  kind: 'reject';
127
127
  reason: string;
128
128
  failure?: ConditionalConflictDetail;
129
- code?: 'INVALID_REQUEST';
129
+ code?: 'INVALID_REQUEST' | 'CONTRACT_UNSUPPORTED';
130
130
  } | {
131
131
  kind: 'apply';
132
132
  mutations: EmbeddedMutation[];
@@ -184,8 +184,12 @@ export declare function embeddedDuplicate(request: AtomicTransactionRequest, pla
184
184
  export declare class EmbeddedTransactionRejected extends Error {
185
185
  readonly feltdbCode?: 'PRECONDITION_FAILED';
186
186
  readonly feltdbConflict?: ConditionalConflictDetail;
187
- /** Set when the request itself was malformed, as opposed to refused by state. */
188
- readonly code?: 'INVALID_REQUEST';
189
- constructor(reason: string, failure?: ConditionalConflictDetail, code?: 'INVALID_REQUEST');
187
+ /**
188
+ * Set when the request itself was malformed (`INVALID_REQUEST`) or asks for
189
+ * something this runtime cannot evaluate (`CONTRACT_UNSUPPORTED`), as
190
+ * opposed to refused by state.
191
+ */
192
+ readonly code?: 'INVALID_REQUEST' | 'CONTRACT_UNSUPPORTED';
193
+ constructor(reason: string, failure?: ConditionalConflictDetail, code?: 'INVALID_REQUEST' | 'CONTRACT_UNSUPPORTED');
190
194
  }
191
195
  //# sourceMappingURL=embedded-transaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"embedded-transaction.d.ts","sourceRoot":"","sources":["../src/embedded-transaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"embedded-transaction.d.ts","sourceRoot":"","sources":["../src/embedded-transaction.ts"],"names":[],"mappings":"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"}
@@ -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