@feltdb/core 0.12.1 → 0.12.2

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 (112) hide show
  1. package/dist/build-identity.json +13 -4
  2. package/dist/cli/commands.js +88 -43
  3. package/dist/collection.d.ts +41 -4
  4. package/dist/collection.d.ts.map +1 -1
  5. package/dist/collection.js +116 -47
  6. package/dist/composition.d.ts.map +1 -1
  7. package/dist/composition.js +11 -1
  8. package/dist/create/build-identity.json +13 -4
  9. package/dist/create/cli.js +3 -3
  10. package/dist/create/create.js +17 -19
  11. package/dist/create/package-versions.js +1 -1
  12. package/dist/create/server-source/Cargo.lock +18 -3
  13. package/dist/create/server-source/Cargo.toml +4 -2
  14. package/dist/create/server-source/crates/feltdb/Cargo.toml +20 -0
  15. package/dist/create/server-source/crates/feltdb/LICENSE +21 -0
  16. package/dist/create/server-source/crates/feltdb/README.md +75 -0
  17. package/dist/create/server-source/crates/feltdb/src/agent_state.rs +320 -0
  18. package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +1545 -0
  19. package/dist/create/server-source/crates/feltdb/src/authority.rs +145 -15
  20. package/dist/create/server-source/crates/feltdb/src/lib.rs +227 -23
  21. package/dist/create/server-source/crates/feltdb/src/state_model.rs +1 -5
  22. package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +1188 -0
  23. package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +2884 -0
  24. package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +534 -0
  25. package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +23340 -0
  26. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +29 -0
  27. package/dist/create/server-source/crates/feltdb-client/LICENSE +21 -0
  28. package/dist/create/server-source/crates/feltdb-client/README.md +70 -0
  29. package/dist/create/server-source/crates/feltdb-client/src/application.rs +527 -0
  30. package/dist/create/server-source/crates/feltdb-client/src/authority.rs +679 -0
  31. package/dist/create/server-source/crates/feltdb-client/src/control.rs +292 -0
  32. package/dist/create/server-source/crates/feltdb-client/src/error.rs +227 -0
  33. package/dist/create/server-source/crates/feltdb-client/src/events.rs +146 -0
  34. package/dist/create/server-source/crates/feltdb-client/src/lib.rs +466 -0
  35. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/README.md +4 -0
  36. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/private-ca.pem +20 -0
  37. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/server-key.pem +28 -0
  38. package/dist/create/server-source/crates/feltdb-client/tests/fixtures/server.pem +20 -0
  39. package/dist/create/server-source/crates/feltdb-client/tests/private_ca.rs +95 -0
  40. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +20 -1
  41. package/dist/create/server-source/crates/feltdb-server/LICENSE +21 -0
  42. package/dist/create/server-source/crates/feltdb-server/README.md +12 -1
  43. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +6 -2
  44. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +20 -0
  45. package/dist/create/server-source/crates/feltdb-server/src/main.rs +1 -3
  46. package/dist/create/server-source/crates/feltdb-server/tests/rust_client.rs +683 -0
  47. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +3 -1
  48. package/dist/create/template/default-project/README.md +12 -7
  49. package/dist/create/template/default-project/src/pages/Dashboard.tsx +1 -1
  50. package/dist/create/template/dot-feltdb-README.md +3 -3
  51. package/dist/db.d.ts.map +1 -1
  52. package/dist/db.js +43 -17
  53. package/dist/development-runtime-bridge.d.ts.map +1 -1
  54. package/dist/development-runtime-bridge.js +22 -1
  55. package/dist/embedded-transaction.d.ts +75 -8
  56. package/dist/embedded-transaction.d.ts.map +1 -1
  57. package/dist/embedded-transaction.js +124 -18
  58. package/dist/error-codes.d.ts +2 -0
  59. package/dist/error-codes.d.ts.map +1 -1
  60. package/dist/error-codes.js +2 -0
  61. package/dist/feltdb.d.ts +1 -11
  62. package/dist/feltdb.d.ts.map +1 -1
  63. package/dist/file-db.d.ts +6 -0
  64. package/dist/file-db.d.ts.map +1 -1
  65. package/dist/file-db.js +43 -11
  66. package/dist/indexeddb-db.d.ts.map +1 -1
  67. package/dist/indexeddb-db.js +65 -41
  68. package/dist/memory-db.d.ts.map +1 -1
  69. package/dist/memory-db.js +29 -8
  70. package/dist/studio/{KeyManagementPanel-DZuSeWBK.js → KeyManagementPanel-D5FMvvU9.js} +1 -0
  71. package/dist/studio/app.d.ts.map +1 -1
  72. package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -1
  73. package/dist/studio/components/KeyManagementPanel.js +1 -1
  74. package/dist/studio/components/RouteErrorBoundary.d.ts +5 -0
  75. package/dist/studio/components/RouteErrorBoundary.d.ts.map +1 -0
  76. package/dist/studio/components/index.js +2 -2
  77. package/dist/studio/{components-Bivm2lX6.js → components-B4eKIUN5.js} +1 -1
  78. package/dist/studio/control-plane/Agents.d.ts.map +1 -1
  79. package/dist/studio/control-plane/Data.d.ts.map +1 -1
  80. package/dist/studio/control-plane/Instance.d.ts.map +1 -1
  81. package/dist/studio/control-plane/Overview.d.ts.map +1 -1
  82. package/dist/studio/control-plane/Schema.d.ts.map +1 -1
  83. package/dist/studio/control-plane/context.d.ts +4 -1
  84. package/dist/studio/control-plane/context.d.ts.map +1 -1
  85. package/dist/studio/control-plane/index.js +2 -2
  86. package/dist/studio/control-plane/primitives.d.ts +8 -0
  87. package/dist/studio/control-plane/primitives.d.ts.map +1 -1
  88. package/dist/studio/{control-plane-CLm69XwX.js → control-plane-fxMcJn74.js} +1371 -1319
  89. package/dist/studio/index.js +146 -105
  90. package/dist/studio/utils/control-plane-api.d.ts.map +1 -1
  91. package/dist/studio/utils/control-plane-api.js +4 -3
  92. package/dist/studio/utils/service-api.d.ts.map +1 -1
  93. package/dist/studio/utils/service-api.js +5 -4
  94. package/dist/studio-app/assets/{feltdb_wasm-DACcD-zs.js → feltdb_wasm-BatwwogY.js} +1 -1
  95. package/dist/studio-app/assets/feltdb_wasm_bg-BX0newOr.wasm +0 -0
  96. package/dist/studio-app/assets/index-DoVvbIay.js +30 -0
  97. package/dist/studio-app/index.html +1 -1
  98. package/dist/telemetry.d.ts +1 -0
  99. package/dist/telemetry.d.ts.map +1 -1
  100. package/dist/telemetry.js +4 -3
  101. package/dist/transaction-identity.d.ts +62 -0
  102. package/dist/transaction-identity.d.ts.map +1 -0
  103. package/dist/transaction-identity.js +138 -0
  104. package/dist/transaction.d.ts +50 -5
  105. package/dist/transaction.d.ts.map +1 -1
  106. package/dist/transaction.js +28 -0
  107. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  108. package/dist/wasm/package.json +1 -1
  109. package/package.json +1 -1
  110. package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
  111. package/dist/studio-app/assets/feltdb_wasm_bg-BejThWID.wasm +0 -0
  112. package/dist/studio-app/assets/index-CoZaxnlm.js +0 -30
@@ -1,3 +1,3 @@
1
- <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#17211b"/><title>FeltDB Studio</title> <script type="module" crossorigin src="/assets/index-CoZaxnlm.js"></script>
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#17211b"/><title>FeltDB Studio</title> <script type="module" crossorigin src="/assets/index-DoVvbIay.js"></script>
2
2
  <link rel="stylesheet" crossorigin href="/assets/index-CiC8VY-a.css">
3
3
  </head><body><div id="root"></div></body></html>
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Privacy-preserving, anonymous telemetry for adoption analytics.
5
5
  * No source code, project names, filesystem paths, or PII collected.
6
+ * Disabled by default; opt in with FELTDB_TELEMETRY=1.
6
7
  * Fail-open: telemetry failures never affect FeltDB operation.
7
8
  */
8
9
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4CH;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,YAAY,GACZ,OAAO,GACP,OAAO,GACP,MAAM,GACN,iBAAiB,GACjB,qBAAqB,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AA8CD;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAChC,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAA8B;gBAEjC,WAAW,GAAE,MAAgB;IAczC;;OAEG;IACH,IAAI,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI;IA6BzC;;OAEG;YACW,KAAK;IAqBnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;;OAGG;YACW,UAAU;IA6BxB;;OAEG;IACH,OAAO,CAAC,KAAK;IAkBb;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAKlC;AAOD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,eAAe,CAKxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAEjE"}
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA4CH;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,YAAY,GACZ,OAAO,GACP,OAAO,GACP,MAAM,GACN,iBAAiB,GACjB,qBAAqB,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AA8CD;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAChC,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAA8B;gBAEjC,WAAW,GAAE,MAAgB;IAczC;;OAEG;IACH,IAAI,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI;IA6BzC;;OAEG;YACW,KAAK;IAqBnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;;OAGG;YACW,UAAU;IA6BxB;;OAEG;IACH,OAAO,CAAC,KAAK;IAkBb;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAKlC;AAOD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,eAAe,CAKxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAEjE"}
package/dist/telemetry.js CHANGED
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Privacy-preserving, anonymous telemetry for adoption analytics.
5
5
  * No source code, project names, filesystem paths, or PII collected.
6
+ * Disabled by default; opt in with FELTDB_TELEMETRY=1.
6
7
  * Fail-open: telemetry failures never affect FeltDB operation.
7
8
  */
8
9
  const isBrowserRuntime = () => typeof window !== 'undefined' && typeof window.document !== 'undefined';
@@ -99,9 +100,9 @@ export class TelemetryClient {
99
100
  constructor(coreVersion = '0.5.7') {
100
101
  this.coreVersion = coreVersion;
101
102
  this.identity = new InstallationIdentity();
102
- // Check if telemetry is disabled
103
- this.enabled = environmentValue('FELTDB_TELEMETRY') !== '0' &&
104
- environmentValue('FELTDB_TELEMETRY') !== 'false';
103
+ // Telemetry is off by default; opt in with FELTDB_TELEMETRY=1 or true
104
+ const optIn = environmentValue('FELTDB_TELEMETRY')?.toLowerCase();
105
+ this.enabled = optIn === '1' || optIn === 'true';
105
106
  // Detect browser environment
106
107
  if (isBrowserRuntime()) {
107
108
  this.runtime = 'browser';
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Transaction identity: what a transaction ID is bound to.
3
+ *
4
+ * A transaction ID names one logical transaction *and* its contents. The
5
+ * embedded runtimes record the ID together with a digest of the request, so a
6
+ * retry can be told apart from a different request that happens to reuse the
7
+ * ID. The design and its compatibility analysis are in
8
+ * `adrs/transaction-identity-and-payload-binding.md`.
9
+ *
10
+ * Everything here is synchronous and dependency-free (SHA-256 is the portable
11
+ * implementation in `stable-hash.ts`), because the digest must
12
+ * be computed before a runtime opens its commit boundary (an IndexedDB
13
+ * transaction cannot be held open across an `await`) and must behave the same
14
+ * in Node and in a browser served from an insecure origin, where
15
+ * `crypto.subtle` is unavailable.
16
+ */
17
+ import type { AtomicTransactionRequest } from './transaction.js';
18
+ /** The construction version this build writes. */
19
+ export declare const TRANSACTION_DIGEST_VERSION = "txd1";
20
+ /** A request that cannot be given an identity because it is not valid. */
21
+ export declare class InvalidTransactionPayload extends Error {
22
+ constructor(message: string);
23
+ }
24
+ /**
25
+ * Serialize `value` as RFC 8785 canonical JSON.
26
+ *
27
+ * Object members are sorted by UTF-16 code unit, numbers use the ECMAScript
28
+ * shortest form (`-0` is `0`), strings use the standard escapes, and there is
29
+ * no insignificant whitespace. Members whose value is `undefined` are omitted,
30
+ * exactly as `JSON.stringify` and a caller who left them out would produce.
31
+ * Array order is preserved.
32
+ *
33
+ * Anything that is not a JSON value is refused rather than coerced: `NaN`,
34
+ * `Infinity`, `undefined` in an array, `BigInt`, symbols, functions, cycles,
35
+ * and non-plain objects such as `Date` or `Map`.
36
+ */
37
+ export declare function canonicalJsonStrict(value: unknown, where?: string): string;
38
+ /**
39
+ * The semantic request: what the runtime acts on, and nothing else.
40
+ *
41
+ * The transaction ID is the key the digest is stored under, so it is not part
42
+ * of it. Operations, preconditions and fences are ordered arrays; reordering
43
+ * them is a different request.
44
+ */
45
+ export declare function semanticRequest(request: AtomicTransactionRequest): Record<string, unknown>;
46
+ /**
47
+ * `txd1:sha256:<hex>` over the canonical form of the semantic request.
48
+ *
49
+ * @throws InvalidTransactionPayload when the request holds a non-JSON value
50
+ */
51
+ export declare function transactionDigest(request: AtomicTransactionRequest): string;
52
+ /** What a stored digest says about a retry's digest. */
53
+ export type DigestComparison = 'match' | 'mismatch' | 'unverifiable';
54
+ /**
55
+ * Compare a recorded digest with a retry's.
56
+ *
57
+ * A digest of a version this build cannot compute, or one that is not a
58
+ * well-formed digest at all, cannot be judged either way, so it is neither a
59
+ * match nor a mismatch: the caller must fail closed.
60
+ */
61
+ export declare function compareDigests(stored: unknown, computed: string): DigestComparison;
62
+ //# sourceMappingURL=transaction-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-identity.d.ts","sourceRoot":"","sources":["../src/transaction-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAGjE,kDAAkD;AAClD,eAAO,MAAM,0BAA0B,SAAS,CAAC;AAKjD,0EAA0E;AAC1E,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,OAAO,EAAE,MAAM;CAI5B;AAaD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAU,GAAG,MAAM,CAE3E;AA+DD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM1F;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAG3E;AAED,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,cAAc,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAKlF"}
@@ -0,0 +1,138 @@
1
+ import { sha256Hex } from './stable-hash.js';
2
+ /** The construction version this build writes. */
3
+ export const TRANSACTION_DIGEST_VERSION = 'txd1';
4
+ /** `txd1:sha256:<64 lowercase hex>` -- the prefix names the whole construction. */
5
+ const DIGEST_FORM = /^(txd\d+):sha256:[0-9a-f]{64}$/;
6
+ /** A request that cannot be given an identity because it is not valid. */
7
+ export class InvalidTransactionPayload extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = 'InvalidTransactionPayload';
11
+ }
12
+ }
13
+ /* ---------------------------------------------------------------------------
14
+ * Canonical JSON (RFC 8785)
15
+ * ------------------------------------------------------------------------ */
16
+ const LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
17
+ function canonicalString(text, where) {
18
+ if (LONE_SURROGATE.test(text))
19
+ throw new InvalidTransactionPayload(`${where} contains a lone surrogate, which has no UTF-8 form`);
20
+ return JSON.stringify(text);
21
+ }
22
+ /**
23
+ * Serialize `value` as RFC 8785 canonical JSON.
24
+ *
25
+ * Object members are sorted by UTF-16 code unit, numbers use the ECMAScript
26
+ * shortest form (`-0` is `0`), strings use the standard escapes, and there is
27
+ * no insignificant whitespace. Members whose value is `undefined` are omitted,
28
+ * exactly as `JSON.stringify` and a caller who left them out would produce.
29
+ * Array order is preserved.
30
+ *
31
+ * Anything that is not a JSON value is refused rather than coerced: `NaN`,
32
+ * `Infinity`, `undefined` in an array, `BigInt`, symbols, functions, cycles,
33
+ * and non-plain objects such as `Date` or `Map`.
34
+ */
35
+ export function canonicalJsonStrict(value, where = 'value') {
36
+ return write(value, where, new Set());
37
+ }
38
+ function write(value, where, active) {
39
+ if (value === null)
40
+ return 'null';
41
+ switch (typeof value) {
42
+ case 'boolean': return value ? 'true' : 'false';
43
+ case 'string': return canonicalString(value, where);
44
+ case 'number':
45
+ if (!Number.isFinite(value))
46
+ throw new InvalidTransactionPayload(`${where} is ${value}, which is not a JSON number`);
47
+ return String(value);
48
+ case 'object': break;
49
+ default:
50
+ throw new InvalidTransactionPayload(`${where} is a ${typeof value}, which is not a JSON value`);
51
+ }
52
+ const object = value;
53
+ if (active.has(object))
54
+ throw new InvalidTransactionPayload(`${where} is part of a cycle`);
55
+ active.add(object);
56
+ try {
57
+ if (Array.isArray(object)) {
58
+ const parts = [];
59
+ for (let index = 0; index < object.length; index += 1) {
60
+ if (!(index in object) || object[index] === undefined) {
61
+ throw new InvalidTransactionPayload(`${where}[${index}] is ${index in object ? 'undefined' : 'a hole'}; arrays hold JSON values only`);
62
+ }
63
+ parts.push(write(object[index], `${where}[${index}]`, active));
64
+ }
65
+ return `[${parts.join(',')}]`;
66
+ }
67
+ const prototype = Object.getPrototypeOf(object);
68
+ if (prototype !== Object.prototype && prototype !== null) {
69
+ throw new InvalidTransactionPayload(`${where} is a ${prototype?.constructor?.name ?? 'non-plain object'}; only plain objects are JSON values`);
70
+ }
71
+ const record = object;
72
+ const members = Object.keys(record).filter(key => record[key] !== undefined).sort();
73
+ return `{${members.map(key => `${canonicalString(key, `${where} key`)}:${write(record[key], `${where}.${key}`, active)}`).join(',')}}`;
74
+ }
75
+ finally {
76
+ active.delete(object);
77
+ }
78
+ }
79
+ /* ---------------------------------------------------------------------------
80
+ * The txd1 digest
81
+ * ------------------------------------------------------------------------ */
82
+ function pick(source, fields, where) {
83
+ const record = source;
84
+ const picked = {};
85
+ for (const field of fields)
86
+ if (record[field] !== undefined)
87
+ picked[field] = record[field];
88
+ // `ifVersion` and `expectedVersion` are one predicate (see
89
+ // `normalisePrecondition`); the digest knows only the wire spelling.
90
+ if (picked.ifVersion !== undefined) {
91
+ if (picked.expectedVersion !== undefined && picked.expectedVersion !== picked.ifVersion) {
92
+ throw new InvalidTransactionPayload(`${where} supplies ifVersion ${String(picked.ifVersion)} and expectedVersion ${String(picked.expectedVersion)}; they are the same predicate`);
93
+ }
94
+ picked.expectedVersion = picked.ifVersion;
95
+ delete picked.ifVersion;
96
+ }
97
+ return picked;
98
+ }
99
+ const OPERATION_FIELDS = ['collection', 'id', 'value', 'requireAbsent', 'ifVersion', 'expectedVersion', 'expectedEpoch', 'expectedLeaseId'];
100
+ const PRECONDITION_FIELDS = ['collection', 'id', 'requireAbsent', 'ifVersion', 'expectedVersion', 'expectedEpoch', 'expectedLeaseId'];
101
+ /**
102
+ * The semantic request: what the runtime acts on, and nothing else.
103
+ *
104
+ * The transaction ID is the key the digest is stored under, so it is not part
105
+ * of it. Operations, preconditions and fences are ordered arrays; reordering
106
+ * them is a different request.
107
+ */
108
+ export function semanticRequest(request) {
109
+ return {
110
+ operations: request.operations.map((operation, index) => pick(operation, OPERATION_FIELDS, `operations[${index}]`)),
111
+ preconditions: (request.preconditions ?? []).map((condition, index) => pick(condition, PRECONDITION_FIELDS, `preconditions[${index}]`)),
112
+ fences: (request.fences ?? []).map(fence => ({ token: fence.token, reads: fence.reads })),
113
+ };
114
+ }
115
+ /**
116
+ * `txd1:sha256:<hex>` over the canonical form of the semantic request.
117
+ *
118
+ * @throws InvalidTransactionPayload when the request holds a non-JSON value
119
+ */
120
+ export function transactionDigest(request) {
121
+ const canonical = canonicalJsonStrict(semanticRequest(request), 'transaction');
122
+ return `${TRANSACTION_DIGEST_VERSION}:sha256:${sha256Hex(canonical)}`;
123
+ }
124
+ /**
125
+ * Compare a recorded digest with a retry's.
126
+ *
127
+ * A digest of a version this build cannot compute, or one that is not a
128
+ * well-formed digest at all, cannot be judged either way, so it is neither a
129
+ * match nor a mismatch: the caller must fail closed.
130
+ */
131
+ export function compareDigests(stored, computed) {
132
+ if (typeof stored !== 'string')
133
+ return 'unverifiable';
134
+ const form = DIGEST_FORM.exec(stored);
135
+ if (!form || form[1] !== TRANSACTION_DIGEST_VERSION)
136
+ return 'unverifiable';
137
+ return stored === computed ? 'match' : 'mismatch';
138
+ }
@@ -166,14 +166,37 @@ export interface AtomicTransactionResult {
166
166
  transactionId: string;
167
167
  /** True when this id was already committed; nothing was applied again. */
168
168
  duplicate: boolean;
169
+ /**
170
+ * How a duplicate was recognized (present only when `duplicate` is true on an
171
+ * embedded runtime):
172
+ * - `verified`: the id and the digest of this request both match what was
173
+ * committed, so this request *is* the original one;
174
+ * - `legacy-unverified`: the id was committed by a build that did not record
175
+ * a digest, so only the id could be checked. Treat the outcome as
176
+ * uncertain if the request might differ from the original.
177
+ */
178
+ binding?: 'verified' | 'legacy-unverified';
179
+ /**
180
+ * Whether the fields below describe the original commit. `unavailable` means
181
+ * the durable record no longer holds the original positions (an id committed
182
+ * by a build that did not record them, since folded into a snapshot); they
183
+ * are then absent rather than guessed. Absent on a first commit, where they
184
+ * are always known.
185
+ */
186
+ outcome?: 'original' | 'unavailable';
169
187
  operations: number;
170
- stateBefore: number;
171
- stateAfter: number;
188
+ /**
189
+ * Position of the *original* commit: the store's sequence before and after
190
+ * it, not the store's current sequence. Absent when `outcome` is
191
+ * `unavailable`.
192
+ */
193
+ stateBefore?: number;
194
+ stateAfter?: number;
172
195
  /** Authority revision before and after this atomic commit. */
173
- baseRevision: number;
174
- commitRevision: number;
196
+ baseRevision?: number;
197
+ commitRevision?: number;
175
198
  /** Stable revision and operation identities; never aliases of transactionId. */
176
- revisionId: string;
199
+ revisionId?: string;
177
200
  operationIds: string[];
178
201
  }
179
202
  /** Staging surface for one collection inside a transaction. */
@@ -234,6 +257,28 @@ export declare class AtomicTransactionError extends Error {
234
257
  readonly status?: number;
235
258
  constructor(message: string, transactionId: string, code?: string, status?: number, cause?: unknown);
236
259
  }
260
+ /**
261
+ * The transaction id was already committed with a different payload.
262
+ *
263
+ * Nothing was applied and the recorded transaction is unchanged. Retrying with
264
+ * the same id cannot succeed: choose a new id for a new transaction, or resend
265
+ * the original payload to confirm the original.
266
+ */
267
+ export declare class TransactionIdConflictError extends AtomicTransactionError {
268
+ readonly code: "IDEMPOTENCY_CONFLICT";
269
+ constructor(transactionId: string, message?: string);
270
+ }
271
+ /**
272
+ * The transaction id exists, but its recorded identity cannot be checked by
273
+ * this build (a digest of a newer construction, or a malformed one).
274
+ *
275
+ * Not a conflict and not a duplicate: neither can be established. Nothing was
276
+ * applied. Do not assume either outcome.
277
+ */
278
+ export declare class TransactionIdUnverifiableError extends AtomicTransactionError {
279
+ readonly code: "IDEMPOTENCY_UNVERIFIABLE";
280
+ constructor(transactionId: string, message?: string);
281
+ }
237
282
  /** Which predicate failed, and what the authority actually holds. */
238
283
  export interface ConditionalConflictDetail {
239
284
  predicate: 'version' | 'epoch' | 'lease' | 'present' | 'missing' | 'fence';
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"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"}
@@ -79,6 +79,34 @@ export class AtomicTransactionError extends Error {
79
79
  this.status = status;
80
80
  }
81
81
  }
82
+ /**
83
+ * The transaction id was already committed with a different payload.
84
+ *
85
+ * Nothing was applied and the recorded transaction is unchanged. Retrying with
86
+ * the same id cannot succeed: choose a new id for a new transaction, or resend
87
+ * the original payload to confirm the original.
88
+ */
89
+ export class TransactionIdConflictError extends AtomicTransactionError {
90
+ code = 'IDEMPOTENCY_CONFLICT';
91
+ constructor(transactionId, message) {
92
+ super(message ?? `Transaction ${transactionId} was already committed with a different payload`, transactionId);
93
+ this.name = 'TransactionIdConflictError';
94
+ }
95
+ }
96
+ /**
97
+ * The transaction id exists, but its recorded identity cannot be checked by
98
+ * this build (a digest of a newer construction, or a malformed one).
99
+ *
100
+ * Not a conflict and not a duplicate: neither can be established. Nothing was
101
+ * applied. Do not assume either outcome.
102
+ */
103
+ export class TransactionIdUnverifiableError extends AtomicTransactionError {
104
+ code = 'IDEMPOTENCY_UNVERIFIABLE';
105
+ constructor(transactionId, message) {
106
+ super(message ?? `Transaction ${transactionId} exists, but its recorded identity cannot be verified by this build`, transactionId);
107
+ this.name = 'TransactionIdUnverifiableError';
108
+ }
109
+ }
82
110
  /**
83
111
  * A transaction was refused because a precondition did not hold.
84
112
  *
Binary file
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "feltdb-wasm",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "files": [
6
6
  "feltdb_wasm_bg.wasm",
7
7
  "feltdb_wasm.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feltdb/core",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "description": "FeltDB Core - Application-facing database with Browser, Local, and Server runtimes. Durable state, reactive APIs.",
5
5
  "license": "MIT",
6
6
  "type": "module",