@feltdb/core 0.5.0 → 0.5.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 (52) hide show
  1. package/README.md +24 -14
  2. package/dist/cell.d.ts +233 -0
  3. package/dist/cell.d.ts.map +1 -0
  4. package/dist/cell.js +1078 -0
  5. package/dist/cli/index.js +1 -1
  6. package/dist/collection.d.ts +48 -1
  7. package/dist/collection.d.ts.map +1 -1
  8. package/dist/collection.js +95 -10
  9. package/dist/create/package-versions.js +1 -1
  10. package/dist/create/server-source/crates/feltdb/src/application.rs +183 -8
  11. package/dist/create/server-source/crates/feltdb/src/lib.rs +173 -0
  12. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +231 -0
  13. package/dist/create/server-source/crates/feltdb-server/src/main.rs +314 -46
  14. package/dist/create/server-source/crates/feltdb-server/src/request_telemetry.rs +1 -1
  15. package/dist/create/server-source/crates/feltdb-server/tests/revision_recovery_integration_test.rs +219 -0
  16. package/dist/db.d.ts +16 -0
  17. package/dist/db.d.ts.map +1 -1
  18. package/dist/db.js +21 -0
  19. package/dist/feltdb.d.ts +7 -1
  20. package/dist/feltdb.d.ts.map +1 -1
  21. package/dist/file-db.d.ts +5 -0
  22. package/dist/file-db.d.ts.map +1 -1
  23. package/dist/file-db.js +72 -9
  24. package/dist/http-db.d.ts +13 -0
  25. package/dist/http-db.d.ts.map +1 -1
  26. package/dist/http-db.js +41 -0
  27. package/dist/http-server.d.ts +42 -0
  28. package/dist/http-server.d.ts.map +1 -0
  29. package/dist/http-server.js +182 -0
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -0
  33. package/dist/indexeddb-conformance.spec.d.ts +21 -0
  34. package/dist/indexeddb-conformance.spec.d.ts.map +1 -0
  35. package/dist/indexeddb-conformance.spec.js +103 -0
  36. package/dist/indexeddb-db.d.ts +8 -0
  37. package/dist/indexeddb-db.d.ts.map +1 -1
  38. package/dist/indexeddb-db.js +69 -0
  39. package/dist/memory-db.d.ts +14 -0
  40. package/dist/memory-db.d.ts.map +1 -1
  41. package/dist/memory-db.js +42 -0
  42. package/dist/state-contract.d.ts +1 -1
  43. package/dist/state-contract.d.ts.map +1 -1
  44. package/dist/state-contract.js +1 -1
  45. package/dist/studio-app/assets/{feltdb_wasm-CBGD0zRu.js → feltdb_wasm-h9mxesnH.js} +1 -1
  46. package/dist/studio-app/assets/feltdb_wasm_bg-B8U4A1n1.wasm +0 -0
  47. package/dist/studio-app/assets/index-BMaQv3zF.js +28 -0
  48. package/dist/studio-app/index.html +1 -1
  49. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  50. package/package.json +1 -1
  51. package/dist/studio-app/assets/feltdb_wasm_bg-C6ATF9mJ.wasm +0 -0
  52. package/dist/studio-app/assets/index-3cvTQ0Mv.js +0 -28
@@ -0,0 +1,182 @@
1
+ /**
2
+ * FeltDB HTTP Server
3
+ *
4
+ * Provides HTTP endpoints for FeltDB collection operations including atomic CAS.
5
+ * Can be used as middleware in Express, Hono, or any HTTP framework.
6
+ *
7
+ * Endpoints:
8
+ * - GET /collections/{collection}/{id} - Get a record
9
+ * - POST /collections/{collection} - Insert a record
10
+ * - PATCH /collections/{collection}/{id} - Update a record
11
+ * - POST /collections/{collection}/{id}/cas - Compare-and-set atomic update
12
+ * - DELETE /collections/{collection}/{id} - Delete a record
13
+ *
14
+ * The CAS endpoint preserves atomic semantics across the HTTP boundary by:
15
+ * 1. Receiving expectedVersion and value from client
16
+ * 2. Delegating to Collection.updateIfVersion() inside transaction boundary
17
+ * 3. Returning structured conflict response on version mismatch
18
+ * 4. Ensuring exactly one concurrent writer succeeds on same version
19
+ */
20
+ /**
21
+ * HTTP Server Request Handler
22
+ *
23
+ * This is a framework-agnostic handler that can be adapted to Express, Hono, etc.
24
+ * Returns {status, headers, body} that can be sent to the client.
25
+ */
26
+ export async function handleHttpRequest(options, request) {
27
+ const { db } = options;
28
+ const { method, path, headers, body } = request;
29
+ // Parse path: /collections/{collection}/{id}[/cas]
30
+ const match = path.match(/^\/collections\/([^/]+)(?:\/([^/]+))?(?:\/(.+))?$/);
31
+ if (!match) {
32
+ return errorResponse(404, 'Not Found', 'Invalid path');
33
+ }
34
+ const collection = decodeURIComponent(match[1]);
35
+ const id = match[2] ? decodeURIComponent(match[2]) : undefined;
36
+ const operation = match[3] || undefined;
37
+ // GET /collections/{collection}/{id}
38
+ if (method === 'GET' && id) {
39
+ return handleGet(db, collection, id);
40
+ }
41
+ // POST /collections/{collection}
42
+ if (method === 'POST' && !id && !operation) {
43
+ return handleInsert(db, collection, body);
44
+ }
45
+ // PATCH /collections/{collection}/{id}
46
+ if (method === 'PATCH' && id && !operation) {
47
+ return handleUpdate(db, collection, id, body);
48
+ }
49
+ // POST /collections/{collection}/{id}/cas - Atomic compare-and-set
50
+ if (method === 'POST' && id && operation === 'cas') {
51
+ return handleCas(db, collection, id, body);
52
+ }
53
+ // DELETE /collections/{collection}/{id}
54
+ if (method === 'DELETE' && id && !operation) {
55
+ return handleDelete(db, collection, id);
56
+ }
57
+ return errorResponse(404, 'Not Found', `No handler for ${method} ${path}`);
58
+ }
59
+ async function handleGet(db, collection, id) {
60
+ try {
61
+ const coll = db.collection(collection);
62
+ const item = await coll.get(id);
63
+ if (!item) {
64
+ return errorResponse(404, 'Not Found', `Record ${collection}:${id} not found`);
65
+ }
66
+ return successResponse(200, { value: item });
67
+ }
68
+ catch (error) {
69
+ return errorResponse(500, 'Internal Server Error', String(error));
70
+ }
71
+ }
72
+ async function handleInsert(db, collection, body) {
73
+ try {
74
+ if (!body) {
75
+ return errorResponse(400, 'Bad Request', 'Request body required');
76
+ }
77
+ const value = JSON.parse(body);
78
+ const id = String(value.id ?? '');
79
+ if (!id) {
80
+ return errorResponse(400, 'Bad Request', 'Record must have an id');
81
+ }
82
+ const coll = db.collection(collection);
83
+ await coll.insert(value, id);
84
+ return successResponse(201, { id, value });
85
+ }
86
+ catch (error) {
87
+ return errorResponse(400, 'Bad Request', String(error));
88
+ }
89
+ }
90
+ async function handleUpdate(db, collection, id, body) {
91
+ try {
92
+ if (!body) {
93
+ return errorResponse(400, 'Bad Request', 'Request body required');
94
+ }
95
+ const updates = JSON.parse(body);
96
+ const coll = db.collection(collection);
97
+ await coll.update(id, updates);
98
+ const item = await coll.get(id);
99
+ return successResponse(200, { value: item });
100
+ }
101
+ catch (error) {
102
+ return errorResponse(400, 'Bad Request', String(error));
103
+ }
104
+ }
105
+ /**
106
+ * Handle atomic Compare-And-Set (CAS) operation via HTTP
107
+ *
108
+ * This endpoint receives expectedVersion and value from the client,
109
+ * delegates to Collection.updateIfVersion() which performs the atomic
110
+ * version check inside the backend transaction boundary, and returns
111
+ * a structured conflict response if the version doesn't match.
112
+ *
113
+ * Path: POST /collections/{collection}/{id}/cas
114
+ * Body: { expectedVersion: number, value: object }
115
+ * Response 200: { updated: true, currentVersion: number, item: object }
116
+ * Response 409: { code: "VERSION_CONFLICT", currentVersion: number }
117
+ */
118
+ async function handleCas(db, collection, id, body) {
119
+ try {
120
+ if (!body) {
121
+ return errorResponse(400, 'Bad Request', 'Request body required');
122
+ }
123
+ const request = JSON.parse(body);
124
+ if (request.expectedVersion === undefined) {
125
+ return errorResponse(400, 'Bad Request', 'expectedVersion is required');
126
+ }
127
+ if (!request.value) {
128
+ return errorResponse(400, 'Bad Request', 'value is required');
129
+ }
130
+ const coll = db.collection(collection);
131
+ const result = await coll.updateIfVersion(id, request.expectedVersion, request.value);
132
+ if (result.updated) {
133
+ // Success: return the updated item with new version
134
+ return successResponse(200, {
135
+ updated: true,
136
+ currentVersion: result.item?.__version,
137
+ item: result.item,
138
+ });
139
+ }
140
+ else {
141
+ // Conflict: return structured error response with actual version
142
+ return errorResponse(409, 'VERSION_CONFLICT', `Version mismatch for ${collection}:${id}`, {
143
+ code: 'VERSION_CONFLICT',
144
+ currentVersion: result.currentVersion,
145
+ });
146
+ }
147
+ }
148
+ catch (error) {
149
+ if (String(error).includes('not found')) {
150
+ return errorResponse(404, 'Not Found', `Record ${collection}:${id} not found`);
151
+ }
152
+ return errorResponse(400, 'Bad Request', String(error));
153
+ }
154
+ }
155
+ async function handleDelete(db, collection, id) {
156
+ try {
157
+ const coll = db.collection(collection);
158
+ await coll.delete(id);
159
+ return successResponse(204, {});
160
+ }
161
+ catch (error) {
162
+ return errorResponse(400, 'Bad Request', String(error));
163
+ }
164
+ }
165
+ function successResponse(status, data) {
166
+ return {
167
+ status,
168
+ headers: { 'Content-Type': 'application/json' },
169
+ body: JSON.stringify(data),
170
+ };
171
+ }
172
+ function errorResponse(status, code, message, extra) {
173
+ return {
174
+ status,
175
+ headers: { 'Content-Type': 'application/json' },
176
+ body: JSON.stringify({
177
+ code,
178
+ message,
179
+ ...extra,
180
+ }),
181
+ };
182
+ }
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
  export * from './db.js';
9
9
  export * from './collection.js';
10
+ export * from './cell.js';
10
11
  export * from './reactive-graph.js';
11
12
  export * from './index-types.js';
12
13
  export * from './index-backend.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,KAAK,OAAO,EACZ,KAAK,SAAS,IAAI,iBAAiB,EACnC,KAAK,QAAQ,IAAI,gBAAgB,GAClC,MAAM,eAAe,CAAC;AAEvB;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AAEnC;;GAEG;AACH,YAAY,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,KAAK,OAAO,EACZ,KAAK,SAAS,IAAI,iBAAiB,EACnC,KAAK,QAAQ,IAAI,gBAAgB,GAClC,MAAM,eAAe,CAAC;AAEvB;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AAEnC;;GAEG;AACH,YAAY,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
  export * from './db.js';
9
9
  export * from './collection.js';
10
+ export * from './cell.js';
10
11
  export * from './reactive-graph.js';
11
12
  export * from './index-types.js';
12
13
  export * from './index-backend.js';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * IndexedDB CAS Conformance Tests - Chromium/Playwright
3
+ *
4
+ * Note: IndexedDB conformance testing requires a browser environment with
5
+ * ES modules support. For now, this file documents the test structure.
6
+ *
7
+ * To run these tests:
8
+ * 1. Create a simple HTML page that imports the compiled FeltDB modules
9
+ * 2. Run `npx playwright test` in this directory
10
+ * 3. Tests will run in Chromium and verify IndexedDB CAS semantics
11
+ *
12
+ * Validation points:
13
+ * - Concurrent transaction isolation
14
+ * - Version persistence across reopen
15
+ * - Stale writer conflict detection
16
+ * - Version increment atomicity
17
+ * - Failed CAS leaves state unchanged
18
+ * - __version cannot be supplied by caller
19
+ */
20
+ export declare const playwrightTestStructure = "\nRequired test coverage (Playwright + Chromium):\n\nTest 1: Single process CAS increments version\n \u2713 Insert record (version = 1)\n \u2713 CAS update (expectedVersion: 1)\n \u2713 Result: updated=true, currentVersion=2\n \u2713 Verify persisted: version=2\n\nTest 2: Version conflict on mismatch\n \u2713 Insert record (version = 1)\n \u2713 CAS with wrong expectedVersion (999)\n \u2713 Result: updated=false, currentVersion=1\n \u2713 Verify no mutation: version=1, data unchanged\n\nTest 3: Two concurrent writers (Promise.all)\n \u2713 Insert record (version = 1)\n \u2713 Race 2 CAS requests on same version\n \u2713 Result: 1 success, 1 conflict\n \u2713 Verify final version = 2, not 3\n\nTest 4: Three concurrent writers\n \u2713 Insert record (version = 1)\n \u2713 Race 3 CAS requests on same version\n \u2713 Result: 1 success, 2 conflicts\n \u2713 Verify final version = 2\n\nTest 5: 50 concurrent races\n \u2713 For each i in 0..49:\n - Insert record\n - Race 2 writers on version 1\n - Verify: 1 success, 1 conflict\n\nTest 6: 100 sequential updates\n \u2713 Insert counter (version = 1)\n \u2713 For each i in 0..99:\n - CAS with expectedVersion = i+1\n - Verify updated=true, currentVersion = i+2\n \u2713 Final version = 101 (1 + 100 updates)\n\nTest 7: Stale writer conflict after reopen\n \u2713 Insert record, read version N\n \u2713 Other writer updates with expectedVersion=N \u2192 success, version=N+1\n \u2713 Stale writer tries expectedVersion=N \u2192 conflict, currentVersion=N+1\n\nTest 8: Failed CAS leaves state unchanged\n \u2713 Insert record with nested structure\n \u2713 50 failed CAS attempts with expectedVersion=999\n \u2713 Verify: version unchanged, all fields unchanged (including nested)\n\nTest 9: User __version ignored\n \u2713 Insert record (version = 1)\n \u2713 CAS with __version: 999 in updates\n \u2713 Result: currentVersion = 2, not 999\n \u2713 Verify: stored __version = 2\n\nTest 10: Partial updates preserve fields\n \u2713 Insert record with multiple fields\n \u2713 CAS with only some fields in updates\n \u2713 Verify: updated fields changed, others preserved\n\nTest 11: No mutation event on failed CAS\n \u2713 Subscribe to changes for record\n \u2713 50 failed CAS attempts\n \u2713 Verify: no change events fired\n\nTest 12: Exactly one mutation event on success\n \u2713 Subscribe to changes for record\n \u2713 CAS success\n \u2713 Verify: exactly 1 change event fired\n";
21
+ //# sourceMappingURL=indexeddb-conformance.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb-conformance.spec.d.ts","sourceRoot":"","sources":["../src/indexeddb-conformance.spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,eAAO,MAAM,uBAAuB,s8EAsEnC,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * IndexedDB CAS Conformance Tests - Chromium/Playwright
3
+ *
4
+ * Note: IndexedDB conformance testing requires a browser environment with
5
+ * ES modules support. For now, this file documents the test structure.
6
+ *
7
+ * To run these tests:
8
+ * 1. Create a simple HTML page that imports the compiled FeltDB modules
9
+ * 2. Run `npx playwright test` in this directory
10
+ * 3. Tests will run in Chromium and verify IndexedDB CAS semantics
11
+ *
12
+ * Validation points:
13
+ * - Concurrent transaction isolation
14
+ * - Version persistence across reopen
15
+ * - Stale writer conflict detection
16
+ * - Version increment atomicity
17
+ * - Failed CAS leaves state unchanged
18
+ * - __version cannot be supplied by caller
19
+ */
20
+ // This file serves as documentation for the IndexedDB conformance tests.
21
+ // Implementation would require:
22
+ // 1. A test HTML page that loads compiled FeltDB modules
23
+ // 2. Playwright test harness using page.evaluate() for each operation
24
+ // 3. Tests running in real Chromium with IndexedDB available
25
+ export const playwrightTestStructure = `
26
+ Required test coverage (Playwright + Chromium):
27
+
28
+ Test 1: Single process CAS increments version
29
+ ✓ Insert record (version = 1)
30
+ ✓ CAS update (expectedVersion: 1)
31
+ ✓ Result: updated=true, currentVersion=2
32
+ ✓ Verify persisted: version=2
33
+
34
+ Test 2: Version conflict on mismatch
35
+ ✓ Insert record (version = 1)
36
+ ✓ CAS with wrong expectedVersion (999)
37
+ ✓ Result: updated=false, currentVersion=1
38
+ ✓ Verify no mutation: version=1, data unchanged
39
+
40
+ Test 3: Two concurrent writers (Promise.all)
41
+ ✓ Insert record (version = 1)
42
+ ✓ Race 2 CAS requests on same version
43
+ ✓ Result: 1 success, 1 conflict
44
+ ✓ Verify final version = 2, not 3
45
+
46
+ Test 4: Three concurrent writers
47
+ ✓ Insert record (version = 1)
48
+ ✓ Race 3 CAS requests on same version
49
+ ✓ Result: 1 success, 2 conflicts
50
+ ✓ Verify final version = 2
51
+
52
+ Test 5: 50 concurrent races
53
+ ✓ For each i in 0..49:
54
+ - Insert record
55
+ - Race 2 writers on version 1
56
+ - Verify: 1 success, 1 conflict
57
+
58
+ Test 6: 100 sequential updates
59
+ ✓ Insert counter (version = 1)
60
+ ✓ For each i in 0..99:
61
+ - CAS with expectedVersion = i+1
62
+ - Verify updated=true, currentVersion = i+2
63
+ ✓ Final version = 101 (1 + 100 updates)
64
+
65
+ Test 7: Stale writer conflict after reopen
66
+ ✓ Insert record, read version N
67
+ ✓ Other writer updates with expectedVersion=N → success, version=N+1
68
+ ✓ Stale writer tries expectedVersion=N → conflict, currentVersion=N+1
69
+
70
+ Test 8: Failed CAS leaves state unchanged
71
+ ✓ Insert record with nested structure
72
+ ✓ 50 failed CAS attempts with expectedVersion=999
73
+ ✓ Verify: version unchanged, all fields unchanged (including nested)
74
+
75
+ Test 9: User __version ignored
76
+ ✓ Insert record (version = 1)
77
+ ✓ CAS with __version: 999 in updates
78
+ ✓ Result: currentVersion = 2, not 999
79
+ ✓ Verify: stored __version = 2
80
+
81
+ Test 10: Partial updates preserve fields
82
+ ✓ Insert record with multiple fields
83
+ ✓ CAS with only some fields in updates
84
+ ✓ Verify: updated fields changed, others preserved
85
+
86
+ Test 11: No mutation event on failed CAS
87
+ ✓ Subscribe to changes for record
88
+ ✓ 50 failed CAS attempts
89
+ ✓ Verify: no change events fired
90
+
91
+ Test 12: Exactly one mutation event on success
92
+ ✓ Subscribe to changes for record
93
+ ✓ CAS success
94
+ ✓ Verify: exactly 1 change event fired
95
+ `;
96
+ // Implementation note: For production conformance, uncomment and implement
97
+ // the actual Playwright tests once ES module resolution is available in test runner.
98
+ //
99
+ // import { test, expect, Page } from '@playwright/test';
100
+ //
101
+ // test.describe('IndexedDB CAS Conformance', () => {
102
+ // // Test implementations here
103
+ // });
@@ -38,6 +38,14 @@ export declare class IndexedDbJsDb implements JsDb {
38
38
  insert(key: string, value: string): Promise<JsResult>;
39
39
  update(key: string, value: string): Promise<JsResult>;
40
40
  delete(key: string): Promise<JsResult>;
41
+ cas(params: {
42
+ key: string;
43
+ expectedVersion: number;
44
+ value: string;
45
+ }): Promise<{
46
+ updated: boolean;
47
+ currentVersion: number;
48
+ }>;
41
49
  get(key: string): Promise<JsResult>;
42
50
  query(collection: string): Promise<JsResult>;
43
51
  private request;
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb-db.d.ts","sourceRoot":"","sources":["../src/indexeddb-db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"indexeddb-db.d.ts","sourceRoot":"","sources":["../src/indexeddb-db.ts"],"names":[],"mappings":"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"}
@@ -91,6 +91,75 @@ export class IndexedDbJsDb {
91
91
  insert(key, value) { return this.mutate(key, JSON.parse(value), 'put'); }
92
92
  update(key, value) { return this.mutate(key, JSON.parse(value), 'put'); }
93
93
  delete(key) { return this.mutate(key, undefined, 'delete'); }
94
+ async cas(params) {
95
+ try {
96
+ const db = await this.database;
97
+ let result = { updated: false, currentVersion: 0 };
98
+ let committedSequence = 0;
99
+ const collection = this.splitKey(params.key);
100
+ await new Promise((resolve, reject) => {
101
+ let transaction;
102
+ try {
103
+ transaction = db.transaction(['rows', 'changes'], 'readwrite', { durability: 'strict' });
104
+ }
105
+ catch {
106
+ transaction = db.transaction(['rows', 'changes'], 'readwrite');
107
+ }
108
+ const rowsStore = transaction.objectStore('rows');
109
+ const changesStore = transaction.objectStore('changes');
110
+ // Read current value inside transaction boundary
111
+ const getRequest = rowsStore.get(params.key);
112
+ getRequest.onsuccess = () => {
113
+ const existing = getRequest.result;
114
+ if (existing === undefined) {
115
+ result = { updated: false, currentVersion: 0 };
116
+ return;
117
+ }
118
+ const existingRecord = existing;
119
+ const currentVersion = existingRecord.__version ?? 1;
120
+ // Version check happens inside transaction
121
+ if (currentVersion !== params.expectedVersion) {
122
+ result = { updated: false, currentVersion };
123
+ return;
124
+ }
125
+ // Version matches - update it
126
+ const parsed = JSON.parse(params.value);
127
+ const newVersion = params.expectedVersion + 1;
128
+ const updatedRecord = { ...parsed, __version: newVersion };
129
+ rowsStore.put(updatedRecord, params.key);
130
+ const timestamp = Date.now();
131
+ const change = changesStore.add({
132
+ collection,
133
+ key: params.key,
134
+ type: 'put',
135
+ value: updatedRecord,
136
+ timestamp,
137
+ origin: this.origin,
138
+ id: `${this.origin}:${timestamp}:${Math.random().toString(36).slice(2)}`
139
+ });
140
+ change.onsuccess = () => {
141
+ committedSequence = Number(change.result);
142
+ result = { updated: true, currentVersion: newVersion };
143
+ };
144
+ };
145
+ getRequest.onerror = () => {
146
+ transaction.abort();
147
+ };
148
+ transaction.oncomplete = () => resolve();
149
+ transaction.onerror = () => reject(transaction.error ?? new Error('IndexedDB CAS failed'));
150
+ transaction.onabort = () => reject(transaction.error ?? new Error('IndexedDB CAS aborted'));
151
+ });
152
+ if (result.updated && committedSequence > 0) {
153
+ this.sequence += 1;
154
+ this.announceLocalChange(collection, committedSequence);
155
+ this.channel?.postMessage({ collection, sequence: committedSequence });
156
+ }
157
+ return result;
158
+ }
159
+ catch (error) {
160
+ return { updated: false, currentVersion: 0 };
161
+ }
162
+ }
94
163
  async get(key) {
95
164
  try {
96
165
  const value = await this.request('rows', store => store.get(key));
@@ -27,6 +27,20 @@ export declare class MemoryJsDb implements JsDb {
27
27
  update(key: string, value: string): JsResult;
28
28
  get(key: string): JsResult;
29
29
  delete(key: string): JsResult;
30
+ putIfAbsent(key: string, value: string): Promise<{
31
+ inserted: boolean;
32
+ value: string;
33
+ }>;
34
+ cas(params: {
35
+ key: string;
36
+ expectedVersion: number;
37
+ expectedEpoch?: number;
38
+ value: string;
39
+ }): Promise<{
40
+ updated: boolean;
41
+ currentVersion: number;
42
+ currentEpoch?: number;
43
+ }>;
30
44
  query(capability: string): JsResult;
31
45
  get_capability_records(capability: string): JsResult;
32
46
  execute_op(): JsResult;
@@ -1 +1 @@
1
- {"version":3,"file":"memory-db.d.ts","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,UAAU,QAAQ;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE;AAIrK,mEAAmE;AACnE,qBAAa,UAAW,YAAW,IAAI;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;gBAE/B,SAAS,EAAE,MAAM;IAU7B,OAAO,CAAC,KAAK;IAMb,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ;IAU5C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ;IAO5C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAO1B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAM7B,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ;IAQnC,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ;IAIpD,UAAU,IAAI,QAAQ;IAItB,SAAS,IAAI,QAAQ;IAIrB,QAAQ,IAAI,QAAQ;IACpB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IACvC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAC1C,2BAA2B,IAAI,QAAQ;IACvC,oBAAoB,IAAI,QAAQ;IAChC,WAAW,IAAI,MAAM;IACrB,YAAY,IAAI,MAAM;IACtB,YAAY;IACZ,iBAAiB,CAAC,aAAa,EAAE,MAAM;IACvC,uBAAuB,CAAC,UAAU,EAAE,aAAa,EAAE;;;;CAapD"}
1
+ {"version":3,"file":"memory-db.d.ts","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,UAAU,QAAQ;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE;AAIrK,mEAAmE;AACnE,qBAAa,UAAW,YAAW,IAAI;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;gBAE/B,SAAS,EAAE,MAAM;IAU7B,OAAO,CAAC,KAAK;IAMb,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ;IAU5C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ;IAO5C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAO1B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAM7B,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAiBtF,GAAG,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiC1K,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ;IAQnC,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ;IAIpD,UAAU,IAAI,QAAQ;IAItB,SAAS,IAAI,QAAQ;IAIrB,QAAQ,IAAI,QAAQ;IACpB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IACvC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAC1C,2BAA2B,IAAI,QAAQ;IACvC,oBAAoB,IAAI,QAAQ;IAChC,WAAW,IAAI,MAAM;IACrB,YAAY,IAAI,MAAM;IACtB,YAAY;IACZ,iBAAiB,CAAC,aAAa,EAAE,MAAM;IACvC,uBAAuB,CAAC,UAAU,EAAE,aAAa,EAAE;;;;CAapD"}
package/dist/memory-db.js CHANGED
@@ -45,6 +45,48 @@ export class MemoryJsDb {
45
45
  this.event(key.split(':')[0], key, 'delete');
46
46
  return { success: true, data: key };
47
47
  }
48
+ putIfAbsent(key, value) {
49
+ const existing = this.rows.get(key);
50
+ if (existing !== undefined) {
51
+ return Promise.resolve({
52
+ inserted: false,
53
+ value: JSON.stringify(existing),
54
+ });
55
+ }
56
+ const parsed = JSON.parse(value);
57
+ this.rows.set(key, parsed);
58
+ this.event(key.split(':')[0], key, 'put', parsed);
59
+ return Promise.resolve({
60
+ inserted: true,
61
+ value,
62
+ });
63
+ }
64
+ cas(params) {
65
+ const existing = this.rows.get(params.key);
66
+ const parsed = JSON.parse(params.value);
67
+ if (existing === undefined) {
68
+ // Key doesn't exist - conflict: current version is 0
69
+ return Promise.resolve({ updated: false, currentVersion: 0 });
70
+ }
71
+ const existingRecord = existing;
72
+ const currentVersion = existingRecord.__version ?? 1;
73
+ const currentEpoch = existingRecord.authority?.epoch ?? 0;
74
+ if (currentVersion !== params.expectedVersion) {
75
+ // Version mismatch - conflict
76
+ return Promise.resolve({ updated: false, currentVersion, currentEpoch });
77
+ }
78
+ // Check epoch atomically with version if provided
79
+ if (params.expectedEpoch !== undefined && currentEpoch !== params.expectedEpoch) {
80
+ // Epoch mismatch - conflict
81
+ return Promise.resolve({ updated: false, currentVersion, currentEpoch });
82
+ }
83
+ // Both version and epoch match - update atomically
84
+ const newVersion = params.expectedVersion + 1;
85
+ const updated = { ...parsed, __version: newVersion };
86
+ this.rows.set(params.key, updated);
87
+ this.event(params.key.split(':')[0], params.key, 'put', updated);
88
+ return Promise.resolve({ updated: true, currentVersion: newVersion, currentEpoch });
89
+ }
48
90
  query(capability) {
49
91
  const prefix = `${capability}:`;
50
92
  const values = [...this.rows]
@@ -1,4 +1,4 @@
1
- import { RevisionRecoveryInput, RevisionRecoveryResult } from './revision-recovery';
1
+ import { RevisionRecoveryInput, RevisionRecoveryResult } from './revision-recovery.js';
2
2
  /** Transport types for the Rust-owned FeltDB state contract. */
3
3
  export type PrimitiveType = 'string' | 'integer' | 'number' | 'boolean' | 'timestamp' | 'date' | 'time' | 'json' | 'uuid' | 'decimal' | 'money' | 'bigint' | 'email' | 'url' | 'phone' | 'binary' | 'file' | 'geo_point' | 'object';
4
4
  export type FieldType = {
@@ -1 +1 @@
1
- {"version":3,"file":"state-contract.d.ts","sourceRoot":"","sources":["../src/state-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAGpF,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAC,QAAQ,GAAC,SAAS,GAAC,QAAQ,GAAC,SAAS,GAAC,WAAW,GAAC,MAAM,GAAC,MAAM,GAAC,MAAM,GAAC,MAAM,GAAC,SAAS,GAAC,OAAO,GAAC,QAAQ,GAAC,OAAO,GAAC,KAAK,GAAC,OAAO,GAAC,QAAQ,GAAC,MAAM,GAAC,WAAW,GAAC,QAAQ,CAAC;AAC9L,MAAM,MAAM,SAAS,GAAC;IAAC,IAAI,EAAC,WAAW,CAAC;IAAA,SAAS,EAAC,aAAa,CAAA;CAAC,GAAC;IAAC,IAAI,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,EAAE,CAAA;CAAC,GAAC;IAAC,IAAI,EAAC,WAAW,CAAC;IAAA,UAAU,EAAC,MAAM,CAAA;CAAC,GAAC;IAAC,IAAI,EAAC,OAAO,CAAC;IAAA,KAAK,EAAC,SAAS,CAAA;CAAC,GAAC;IAAC,IAAI,EAAC,KAAK,CAAC;IAAA,MAAM,EAAC,SAAS,CAAA;CAAC,GAAC;IAAC,IAAI,EAAC,QAAQ,CAAC;IAAA,UAAU,CAAC,EAAC,MAAM,CAAA;CAAC,CAAC;AACpO,MAAM,WAAW,UAAU;IAAC,IAAI,EAAC,MAAM,CAAC;IAAA,UAAU,EAAC,SAAS,CAAC;IAAA,QAAQ,CAAC,EAAC,OAAO,CAAC;IAAA,QAAQ,CAAC,EAAC,OAAO,CAAC;IAAA,OAAO,CAAC,EAAC,OAAO,CAAC;IAAA,WAAW,CAAC,EAAC;QAAC,OAAO,CAAC,EAAC,MAAM,CAAC;QAAA,OAAO,CAAC,EAAC,MAAM,CAAC;QAAA,UAAU,CAAC,EAAC,MAAM,CAAC;QAAA,UAAU,CAAC,EAAC,MAAM,CAAC;QAAA,OAAO,CAAC,EAAC,MAAM,CAAA;KAAC,CAAC;IAAA,QAAQ,CAAC,EAAC,MAAM,CAAA;CAAC;AACxO,MAAM,WAAW,WAAW;IAAC,gBAAgB,EAAC,MAAM,CAAC;IAAA,cAAc,EAAC,MAAM,CAAC;IAAA,cAAc,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC;QAAC,IAAI,EAAC,MAAM,CAAC;QAAA,OAAO,EAAC,MAAM,CAAC;QAAA,MAAM,EAAC,UAAU,EAAE,CAAC;QAAA,OAAO,EAAC;YAAC,IAAI,EAAC,MAAM,CAAC;YAAA,MAAM,EAAC,MAAM,EAAE,CAAC;YAAA,MAAM,CAAC,EAAC,OAAO,CAAC;YAAA,MAAM,CAAC,EAAC,OAAO,CAAC;YAAA,OAAO,EAAC,MAAM,CAAA;SAAC,EAAE,CAAA;KAAC,EAAE,CAAA;CAAC;AAC1Q,MAAM,MAAM,WAAW,GAAC;IAAC,QAAQ,EAAC,IAAI,GAAC,KAAK,GAAC,IAAI,GAAC,KAAK,GAAC,IAAI,GAAC,KAAK,CAAC;IAAA,KAAK,EAAC,MAAM,CAAC;IAAA,KAAK,EAAC,OAAO,CAAA;CAAC,GAAC;IAAC,QAAQ,EAAC,IAAI,CAAC;IAAA,KAAK,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,OAAO,EAAE,CAAA;CAAC,GAAC;IAAC,QAAQ,EAAC,UAAU,CAAC;IAAA,KAAK,EAAC,MAAM,CAAC;IAAA,KAAK,EAAC,OAAO,CAAA;CAAC,GAAC;IAAC,QAAQ,EAAC,YAAY,GAAC,UAAU,CAAC;IAAA,KAAK,EAAC,MAAM,CAAC;IAAA,KAAK,EAAC,MAAM,CAAA;CAAC,GAAC;IAAC,QAAQ,EAAC,QAAQ,CAAC;IAAA,KAAK,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,OAAO,CAAA;CAAC,GAAC;IAAC,QAAQ,EAAC,KAAK,GAAC,IAAI,CAAC;IAAA,OAAO,EAAC,WAAW,EAAE,CAAA;CAAC,GAAC;IAAC,QAAQ,EAAC,KAAK,CAAC;IAAA,MAAM,EAAC,WAAW,CAAA;CAAC,CAAC;AAC3X,MAAM,WAAW,cAAc;IAAC,UAAU,EAAC,MAAM,CAAC;IAAA,MAAM,CAAC,EAAC,WAAW,CAAC;IAAA,QAAQ,CAAC,EAAC;QAAC,KAAK,EAAC,MAAM,CAAC;QAAA,SAAS,EAAC,KAAK,GAAC,MAAM,CAAA;KAAC,EAAE,CAAC;IAAA,KAAK,CAAC,EAAC,MAAM,CAAC;IAAA,MAAM,CAAC,EAAC,MAAM,CAAC;IAAA,MAAM,CAAC,EAAC,MAAM,CAAC;IAAA,UAAU,CAAC,EAAC,MAAM,EAAE,CAAC;IAAA,QAAQ,CAAC,EAAC,MAAM,EAAE,CAAC;IAAA,UAAU,CAAC,EAAC;QAAC,IAAI,EAAC,MAAM,CAAC;QAAA,QAAQ,EAAC,OAAO,GAAC,KAAK,GAAC,KAAK,GAAC,KAAK,GAAC,KAAK,CAAC;QAAA,KAAK,CAAC,EAAC,MAAM,CAAA;KAAC,EAAE,CAAC;IAAA,UAAU,CAAC,EAAC;QAAC,KAAK,EAAC,MAAM,CAAC;QAAA,UAAU,EAAC,MAAM,CAAC;QAAA,UAAU,CAAC,EAAC,MAAM,EAAE,CAAC;QAAA,OAAO,EAAC,MAAM,CAAA;KAAC,EAAE,CAAA;CAAC;AAClX,MAAM,WAAW,WAAW,CAAC,CAAC,GAAC,MAAM,CAAC,MAAM,EAAC,OAAO,CAAC;IAAE,QAAQ,EAAC,MAAM,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC;IAAA,oBAAoB,EAAC,MAAM,CAAC;IAAA,cAAc,EAAC,MAAM,CAAC;IAAA,aAAa,EAAC,MAAM,CAAC;IAAA,aAAa,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CAAC;IAAA,OAAO,EAAC,CAAC,EAAE,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC,MAAM,EAAC,OAAO,CAAC,EAAE,CAAC;IAAA,WAAW,CAAC,EAAC,MAAM,CAAC;IAAA,IAAI,EAAC;QAAC,cAAc,EAAC,MAAM,CAAC;QAAA,UAAU,EAAC,MAAM,CAAC;QAAA,KAAK,CAAC,EAAC,MAAM,CAAC;QAAA,aAAa,EAAC,OAAO,CAAA;KAAC,CAAA;CAAC;AAC3V,MAAM,WAAW,oBAAoB;IAAC,IAAI,EAAC,QAAQ,GAAC,QAAQ,GAAC,QAAQ,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC;IAAA,EAAE,EAAC,MAAM,CAAC;IAAA,KAAK,CAAC,EAAC,OAAO,CAAC;IAAA,UAAU,CAAC,EAAC,MAAM,CAAA;CAAC;AACpI,MAAM,WAAW,iBAAiB;IAAC,cAAc,EAAC,MAAM,CAAC;IAAA,YAAY,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,aAAa,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CAAC;IAAA,SAAS,EAAC,OAAO,CAAC;IAAA,KAAK,EAAC,OAAO,CAAA;CAAC;AACpK,MAAM,WAAW,YAAY;IAAC,IAAI,EAAC,mBAAmB,GAAC,qBAAqB,GAAC,sBAAsB,GAAC,iBAAiB,GAAC,UAAU,GAAC,iBAAiB,GAAC,eAAe,GAAC,eAAe,GAAC,oBAAoB,GAAC,yBAAyB,GAAC,gBAAgB,GAAC,mBAAmB,CAAC;IAAA,OAAO,EAAC,MAAM,CAAC;IAAA,QAAQ,CAAC,EAAC,OAAO,CAAC;IAAA,MAAM,CAAC,EAAC,OAAO,CAAC;IAAA,QAAQ,CAAC,EAAC,MAAM,CAAC;IAAA,WAAW,CAAC,EAAC,MAAM,CAAC;IAAA,eAAe,CAAC,EAAC,MAAM,CAAA;CAAC;AAErX,cAAM,kBAAkB;IACtB,QAAQ,CAAC,UAAU,EAAC,oBAAoB,EAAE,CAAI;IAC9C,UAAU,CAAC,IAAI,EAAC,MAAM;qBAAoB,MAAM,SAAO,OAAO;qBAA0F,MAAM,SAAO,OAAO,YAAU;YAAC,SAAS,CAAC,EAAC,MAAM,CAAA;SAAC;qBAA8G,MAAM,YAAU;YAAC,SAAS,CAAC,EAAC,MAAM,CAAA;SAAC;;CAC3V;AACD,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAA8D,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAA5F,MAAM,EAAC;QAAC,aAAa,EAAC,MAAM,CAAC;QAAA,UAAU,EAAC,MAAM,CAAC;QAAA,WAAW,CAAC,EAAC,MAAM,CAAA;KAAC,EAAkB,OAAO,SAAG;YAC9G,OAAO;IAmBrB,MAAM;gBAA4L,WAAW;;IAC7M,YAAY;IACZ,KAAK,CAAC,CAAC,GAAC,MAAM,CAAC,MAAM,EAAC,OAAO,CAAC,EAAE,KAAK,EAAC,cAAc;IAC9C,WAAW,CAAC,IAAI,EAAC,CAAC,EAAE,EAAC,kBAAkB,KAAG,IAAI,GAAC,OAAO,CAAC,IAAI,CAAC,EAAC,OAAO,CAAC,EAAC;QAAC,aAAa,CAAC,EAAC,MAAM,CAAC;QAAA,YAAY,CAAC,EAAC,MAAM,CAAA;KAAC;IACxH,0BAA0B,CAAC,KAAK,EAAC,qBAAqB;CACvD"}
1
+ {"version":3,"file":"state-contract.d.ts","sourceRoot":"","sources":["../src/state-contract.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { FeltDBErrorCode } from './error-codes';
1
+ import { FeltDBErrorCode } from './error-codes.js';
2
2
  class TransactionBuilder {
3
3
  constructor() {
4
4
  this.operations = [];