@lix-js/sdk 0.6.0-preview.0 → 0.6.0-preview.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 (196) hide show
  1. package/README.md +9 -0
  2. package/SKILL.md +468 -0
  3. package/dist/engine-wasm/index.d.ts +15 -11
  4. package/dist/engine-wasm/index.js +105 -38
  5. package/dist/engine-wasm/wasm/lix_engine.d.ts +14 -2
  6. package/dist/engine-wasm/wasm/lix_engine.js +18 -17
  7. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  8. package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +2 -1
  9. package/dist/generated/builtin-schemas.d.ts +31 -41
  10. package/dist/generated/builtin-schemas.js +52 -56
  11. package/dist/open-lix.d.ts +141 -24
  12. package/dist/open-lix.js +199 -35
  13. package/dist/sqlite/index.js +99 -22
  14. package/dist-engine-src/README.md +18 -0
  15. package/dist-engine-src/src/backend/kv.rs +358 -0
  16. package/dist-engine-src/src/backend/mod.rs +12 -0
  17. package/dist-engine-src/src/backend/testing.rs +658 -0
  18. package/dist-engine-src/src/backend/types.rs +96 -0
  19. package/dist-engine-src/src/binary_cas/chunking.rs +31 -0
  20. package/dist-engine-src/src/binary_cas/codec.rs +346 -0
  21. package/dist-engine-src/src/binary_cas/context.rs +139 -0
  22. package/dist-engine-src/src/binary_cas/kv.rs +1063 -0
  23. package/dist-engine-src/src/binary_cas/mod.rs +11 -0
  24. package/dist-engine-src/src/binary_cas/types.rs +127 -0
  25. package/dist-engine-src/src/cel/context.rs +86 -0
  26. package/dist-engine-src/src/cel/error.rs +19 -0
  27. package/dist-engine-src/src/cel/mod.rs +8 -0
  28. package/dist-engine-src/src/cel/provider.rs +9 -0
  29. package/dist-engine-src/src/cel/runtime.rs +167 -0
  30. package/dist-engine-src/src/cel/value.rs +50 -0
  31. package/dist-engine-src/src/changelog/codec.rs +321 -0
  32. package/dist-engine-src/src/changelog/context.rs +92 -0
  33. package/dist-engine-src/src/changelog/materialization.rs +121 -0
  34. package/dist-engine-src/src/changelog/mod.rs +13 -0
  35. package/dist-engine-src/src/changelog/reader.rs +20 -0
  36. package/dist-engine-src/src/changelog/storage.rs +220 -0
  37. package/dist-engine-src/src/changelog/types.rs +38 -0
  38. package/dist-engine-src/src/commit_graph/context.rs +1588 -0
  39. package/dist-engine-src/src/commit_graph/mod.rs +12 -0
  40. package/dist-engine-src/src/commit_graph/types.rs +145 -0
  41. package/dist-engine-src/src/commit_graph/walker.rs +780 -0
  42. package/dist-engine-src/src/common/error.rs +313 -0
  43. package/dist-engine-src/src/common/fingerprint.rs +3 -0
  44. package/dist-engine-src/src/common/fs_path.rs +1336 -0
  45. package/dist-engine-src/src/common/identity.rs +135 -0
  46. package/dist-engine-src/src/common/metadata.rs +35 -0
  47. package/dist-engine-src/src/common/mod.rs +23 -0
  48. package/dist-engine-src/src/common/types.rs +105 -0
  49. package/dist-engine-src/src/common/wire.rs +222 -0
  50. package/dist-engine-src/src/engine.rs +239 -0
  51. package/dist-engine-src/src/entity_identity.rs +285 -0
  52. package/dist-engine-src/src/functions/context.rs +327 -0
  53. package/dist-engine-src/src/functions/deterministic.rs +113 -0
  54. package/dist-engine-src/src/functions/mod.rs +18 -0
  55. package/dist-engine-src/src/functions/provider.rs +130 -0
  56. package/dist-engine-src/src/functions/state.rs +363 -0
  57. package/dist-engine-src/src/functions/types.rs +37 -0
  58. package/dist-engine-src/src/init.rs +505 -0
  59. package/dist-engine-src/src/json_store/compression.rs +77 -0
  60. package/dist-engine-src/src/json_store/context.rs +129 -0
  61. package/dist-engine-src/src/json_store/encoded.rs +15 -0
  62. package/dist-engine-src/src/json_store/mod.rs +9 -0
  63. package/dist-engine-src/src/json_store/store.rs +236 -0
  64. package/dist-engine-src/src/json_store/types.rs +52 -0
  65. package/dist-engine-src/src/lib.rs +61 -0
  66. package/dist-engine-src/src/live_state/context.rs +2241 -0
  67. package/dist-engine-src/src/live_state/mod.rs +15 -0
  68. package/dist-engine-src/src/live_state/overlay.rs +75 -0
  69. package/dist-engine-src/src/live_state/reader.rs +23 -0
  70. package/dist-engine-src/src/live_state/types.rs +239 -0
  71. package/dist-engine-src/src/live_state/visibility.rs +218 -0
  72. package/dist-engine-src/src/plugin/archive.rs +441 -0
  73. package/dist-engine-src/src/plugin/component.rs +183 -0
  74. package/dist-engine-src/src/plugin/install.rs +637 -0
  75. package/dist-engine-src/src/plugin/manifest.rs +516 -0
  76. package/dist-engine-src/src/plugin/materializer.rs +477 -0
  77. package/dist-engine-src/src/plugin/mod.rs +33 -0
  78. package/dist-engine-src/src/plugin/plugin_manifest.json +119 -0
  79. package/dist-engine-src/src/plugin/storage.rs +74 -0
  80. package/dist-engine-src/src/schema/annotations/defaults.rs +280 -0
  81. package/dist-engine-src/src/schema/annotations/mod.rs +1 -0
  82. package/dist-engine-src/src/schema/builtin/lix_account.json +22 -0
  83. package/dist-engine-src/src/schema/builtin/lix_active_account.json +30 -0
  84. package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +30 -0
  85. package/dist-engine-src/src/schema/builtin/lix_change.json +62 -0
  86. package/dist-engine-src/src/schema/builtin/lix_change_author.json +46 -0
  87. package/dist-engine-src/src/schema/builtin/lix_change_set.json +18 -0
  88. package/dist-engine-src/src/schema/builtin/lix_change_set_element.json +75 -0
  89. package/dist-engine-src/src/schema/builtin/lix_commit.json +62 -0
  90. package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +46 -0
  91. package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +53 -0
  92. package/dist-engine-src/src/schema/builtin/lix_entity_label.json +63 -0
  93. package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +53 -0
  94. package/dist-engine-src/src/schema/builtin/lix_key_value.json +41 -0
  95. package/dist-engine-src/src/schema/builtin/lix_label.json +22 -0
  96. package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +31 -0
  97. package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +35 -0
  98. package/dist-engine-src/src/schema/builtin/lix_version_ref.json +49 -0
  99. package/dist-engine-src/src/schema/builtin/mod.rs +271 -0
  100. package/dist-engine-src/src/schema/definition.json +157 -0
  101. package/dist-engine-src/src/schema/definition.rs +636 -0
  102. package/dist-engine-src/src/schema/key.rs +206 -0
  103. package/dist-engine-src/src/schema/mod.rs +20 -0
  104. package/dist-engine-src/src/schema/seed.rs +14 -0
  105. package/dist-engine-src/src/schema/tests.rs +739 -0
  106. package/dist-engine-src/src/schema_registry.rs +294 -0
  107. package/dist-engine-src/src/session/context.rs +366 -0
  108. package/dist-engine-src/src/session/create_version.rs +80 -0
  109. package/dist-engine-src/src/session/execute.rs +447 -0
  110. package/dist-engine-src/src/session/merge/analysis.rs +102 -0
  111. package/dist-engine-src/src/session/merge/apply.rs +23 -0
  112. package/dist-engine-src/src/session/merge/conflicts.rs +62 -0
  113. package/dist-engine-src/src/session/merge/mod.rs +11 -0
  114. package/dist-engine-src/src/session/merge/stats.rs +65 -0
  115. package/dist-engine-src/src/session/merge/version.rs +437 -0
  116. package/dist-engine-src/src/session/mod.rs +25 -0
  117. package/dist-engine-src/src/session/switch_version.rs +121 -0
  118. package/dist-engine-src/src/sql2/change_provider.rs +337 -0
  119. package/dist-engine-src/src/sql2/classify.rs +147 -0
  120. package/dist-engine-src/src/sql2/commit_derived_provider.rs +591 -0
  121. package/dist-engine-src/src/sql2/context.rs +307 -0
  122. package/dist-engine-src/src/sql2/directory_history_provider.rs +623 -0
  123. package/dist-engine-src/src/sql2/directory_provider.rs +2405 -0
  124. package/dist-engine-src/src/sql2/dml.rs +148 -0
  125. package/dist-engine-src/src/sql2/entity_history_provider.rs +444 -0
  126. package/dist-engine-src/src/sql2/entity_provider.rs +2700 -0
  127. package/dist-engine-src/src/sql2/error.rs +196 -0
  128. package/dist-engine-src/src/sql2/execute.rs +3379 -0
  129. package/dist-engine-src/src/sql2/file_history_provider.rs +902 -0
  130. package/dist-engine-src/src/sql2/file_provider.rs +3254 -0
  131. package/dist-engine-src/src/sql2/filesystem_planner.rs +1526 -0
  132. package/dist-engine-src/src/sql2/filesystem_predicates.rs +159 -0
  133. package/dist-engine-src/src/sql2/filesystem_visibility.rs +369 -0
  134. package/dist-engine-src/src/sql2/history_projection.rs +80 -0
  135. package/dist-engine-src/src/sql2/history_provider.rs +418 -0
  136. package/dist-engine-src/src/sql2/history_route.rs +643 -0
  137. package/dist-engine-src/src/sql2/lix_state_provider.rs +2430 -0
  138. package/dist-engine-src/src/sql2/mod.rs +43 -0
  139. package/dist-engine-src/src/sql2/read_only.rs +65 -0
  140. package/dist-engine-src/src/sql2/record_batch.rs +17 -0
  141. package/dist-engine-src/src/sql2/result_metadata.rs +29 -0
  142. package/dist-engine-src/src/sql2/runtime.rs +60 -0
  143. package/dist-engine-src/src/sql2/session.rs +135 -0
  144. package/dist-engine-src/src/sql2/udfs/common.rs +295 -0
  145. package/dist-engine-src/src/sql2/udfs/lix_active_version_commit_id.rs +53 -0
  146. package/dist-engine-src/src/sql2/udfs/lix_empty_blob.rs +47 -0
  147. package/dist-engine-src/src/sql2/udfs/lix_json.rs +100 -0
  148. package/dist-engine-src/src/sql2/udfs/lix_json_get.rs +99 -0
  149. package/dist-engine-src/src/sql2/udfs/lix_json_get_text.rs +99 -0
  150. package/dist-engine-src/src/sql2/udfs/lix_text_decode.rs +82 -0
  151. package/dist-engine-src/src/sql2/udfs/lix_text_encode.rs +85 -0
  152. package/dist-engine-src/src/sql2/udfs/lix_uuid_v7.rs +76 -0
  153. package/dist-engine-src/src/sql2/udfs/mod.rs +82 -0
  154. package/dist-engine-src/src/sql2/version_provider.rs +1187 -0
  155. package/dist-engine-src/src/sql2/version_scope.rs +394 -0
  156. package/dist-engine-src/src/sql2/write_normalization.rs +345 -0
  157. package/dist-engine-src/src/storage/context.rs +356 -0
  158. package/dist-engine-src/src/storage/mod.rs +14 -0
  159. package/dist-engine-src/src/storage/read_scope.rs +88 -0
  160. package/dist-engine-src/src/storage/types.rs +501 -0
  161. package/dist-engine-src/src/storage_bench.rs +3406 -0
  162. package/dist-engine-src/src/test_support.rs +81 -0
  163. package/dist-engine-src/src/tracked_state/by_file_index.rs +102 -0
  164. package/dist-engine-src/src/tracked_state/codec.rs +747 -0
  165. package/dist-engine-src/src/tracked_state/context.rs +983 -0
  166. package/dist-engine-src/src/tracked_state/diff.rs +494 -0
  167. package/dist-engine-src/src/tracked_state/materialization.rs +141 -0
  168. package/dist-engine-src/src/tracked_state/merge.rs +474 -0
  169. package/dist-engine-src/src/tracked_state/mod.rs +31 -0
  170. package/dist-engine-src/src/tracked_state/rebuild.rs +771 -0
  171. package/dist-engine-src/src/tracked_state/storage.rs +243 -0
  172. package/dist-engine-src/src/tracked_state/tree.rs +2744 -0
  173. package/dist-engine-src/src/tracked_state/tree_types.rs +176 -0
  174. package/dist-engine-src/src/tracked_state/types.rs +61 -0
  175. package/dist-engine-src/src/transaction/commit.rs +1224 -0
  176. package/dist-engine-src/src/transaction/context.rs +1307 -0
  177. package/dist-engine-src/src/transaction/live_state_overlay.rs +34 -0
  178. package/dist-engine-src/src/transaction/mod.rs +11 -0
  179. package/dist-engine-src/src/transaction/normalization.rs +1026 -0
  180. package/dist-engine-src/src/transaction/schema_resolver.rs +127 -0
  181. package/dist-engine-src/src/transaction/staging.rs +1436 -0
  182. package/dist-engine-src/src/transaction/types.rs +351 -0
  183. package/dist-engine-src/src/transaction/validation.rs +4811 -0
  184. package/dist-engine-src/src/untracked_state/codec.rs +363 -0
  185. package/dist-engine-src/src/untracked_state/context.rs +82 -0
  186. package/dist-engine-src/src/untracked_state/materialization.rs +157 -0
  187. package/dist-engine-src/src/untracked_state/mod.rs +17 -0
  188. package/dist-engine-src/src/untracked_state/storage.rs +348 -0
  189. package/dist-engine-src/src/untracked_state/types.rs +96 -0
  190. package/dist-engine-src/src/version/context.rs +52 -0
  191. package/dist-engine-src/src/version/mod.rs +12 -0
  192. package/dist-engine-src/src/version/refs.rs +421 -0
  193. package/dist-engine-src/src/version/stage_rows.rs +71 -0
  194. package/dist-engine-src/src/version/types.rs +21 -0
  195. package/dist-engine-src/src/wasm/mod.rs +60 -0
  196. package/package.json +68 -63
package/dist/open-lix.js CHANGED
@@ -1,5 +1,74 @@
1
1
  import init, { resolveEngineWasmModuleOrPath, Value, } from "./engine-wasm/index.js";
2
2
  import * as wasmModule from "./engine-wasm/index.js";
3
+ export class Row {
4
+ columns;
5
+ valuesByIndex;
6
+ constructor(columns, values) {
7
+ this.columns = columns;
8
+ this.valuesByIndex = values;
9
+ }
10
+ get(columnName) {
11
+ return valueToNative(this.value(columnName));
12
+ }
13
+ tryGet(columnName) {
14
+ const value = this.tryValue(columnName);
15
+ return value === undefined ? undefined : valueToNative(value);
16
+ }
17
+ value(columnName) {
18
+ const index = this.columns.indexOf(columnName);
19
+ if (index === -1) {
20
+ throw createLixError("LIX_COLUMN_NOT_FOUND", `Column "${columnName}" does not exist. Available columns: ${this.availableColumns()}`);
21
+ }
22
+ const value = this.valuesByIndex[index];
23
+ if (value === undefined) {
24
+ throw createLixError("LIX_COLUMN_NOT_FOUND", `Column "${columnName}" is outside row width ${this.valuesByIndex.length}.`);
25
+ }
26
+ return value;
27
+ }
28
+ tryValue(columnName) {
29
+ const index = this.columns.indexOf(columnName);
30
+ return index === -1 ? undefined : this.valuesByIndex[index];
31
+ }
32
+ getAt(index) {
33
+ return valueToNative(this.valueAt(index));
34
+ }
35
+ valueAt(index) {
36
+ const value = this.valuesByIndex[index];
37
+ if (value === undefined) {
38
+ throw createLixError("LIX_COLUMN_NOT_FOUND", `Column index ${index} is outside row width ${this.valuesByIndex.length}.`);
39
+ }
40
+ return value;
41
+ }
42
+ values() {
43
+ return [...this.valuesByIndex];
44
+ }
45
+ toObject() {
46
+ return Object.fromEntries(this.columns.map((column, index) => [
47
+ column,
48
+ valueToNative(this.valueAt(index)),
49
+ ]));
50
+ }
51
+ toValueMap() {
52
+ return Object.fromEntries(this.columns.map((column, index) => [column, this.valueAt(index)]));
53
+ }
54
+ availableColumns() {
55
+ return this.columns.length === 0 ? "<none>" : this.columns.join(", ");
56
+ }
57
+ }
58
+ function valueToNative(value) {
59
+ switch (value.kind) {
60
+ case "null":
61
+ return null;
62
+ case "boolean":
63
+ case "integer":
64
+ case "real":
65
+ case "text":
66
+ case "json":
67
+ return value.value;
68
+ case "blob":
69
+ return value.asBlob() ?? new Uint8Array();
70
+ }
71
+ }
3
72
  let wasmReady = null;
4
73
  async function ensureWasmReady() {
5
74
  if (!wasmReady) {
@@ -13,7 +82,7 @@ export async function openLix(options = {}) {
13
82
  await ensureWasmReady();
14
83
  try {
15
84
  const wasmLix = (await wasmModule.openLix(options));
16
- return createLixHandle(wasmLix, options.backend);
85
+ return createLixHandle(wasmLix);
17
86
  }
18
87
  catch (error) {
19
88
  try {
@@ -22,17 +91,11 @@ export async function openLix(options = {}) {
22
91
  catch {
23
92
  // Preserve the original open failure.
24
93
  }
25
- throw error;
94
+ throw normalizeThrownError(error);
26
95
  }
27
96
  }
28
- function createLixHandle(wasmLix, backend) {
29
- let closed = false;
97
+ function createLixHandle(wasmLix) {
30
98
  let operationQueue = Promise.resolve();
31
- const ensureOpen = (methodName) => {
32
- if (closed) {
33
- throw new Error(`lix is closed; ${methodName}() is unavailable`);
34
- }
35
- };
36
99
  const acquireOperationSlot = async () => {
37
100
  const previous = operationQueue;
38
101
  let releaseCurrent;
@@ -48,57 +111,158 @@ function createLixHandle(wasmLix, backend) {
48
111
  try {
49
112
  return await operation();
50
113
  }
114
+ catch (error) {
115
+ throw normalizeThrownError(error);
116
+ }
51
117
  finally {
52
118
  release();
53
119
  }
54
120
  };
55
121
  return {
56
122
  async execute(sql, params = []) {
57
- ensureOpen("execute");
58
- const result = await runQueued(() => wasmLix.execute(sql, params.map((param) => Value.from(param))));
123
+ validateExecuteArguments(sql, params);
124
+ const values = params.map((param, index) => valueFromExecuteParam(param, index));
125
+ const result = await runQueued(() => wasmLix.execute(sql, values));
59
126
  return normalizeExecuteResult(result);
60
127
  },
61
128
  async activeVersionId() {
62
- ensureOpen("activeVersionId");
63
129
  return await runQueued(() => wasmLix.activeVersionId());
64
130
  },
65
131
  async createVersion(options) {
66
- ensureOpen("createVersion");
67
132
  return await runQueued(() => wasmLix.createVersion(options));
68
133
  },
69
134
  async switchVersion(options) {
70
- ensureOpen("switchVersion");
71
135
  return await runQueued(() => wasmLix.switchVersion(options));
72
136
  },
137
+ async mergeVersionPreview(options) {
138
+ return await runQueued(() => wasmLix.mergeVersionPreview(options));
139
+ },
73
140
  async mergeVersion(options) {
74
- ensureOpen("mergeVersion");
75
141
  return await runQueued(() => wasmLix.mergeVersion(options));
76
142
  },
77
143
  async close() {
78
- if (closed)
79
- return;
80
- try {
81
- await runQueued(() => wasmLix.close());
82
- }
83
- finally {
84
- backend?.close?.();
85
- closed = true;
86
- }
144
+ await runQueued(() => wasmLix.close());
87
145
  },
88
146
  };
89
147
  }
90
- function normalizeExecuteResult(result) {
91
- if (result.kind === "rows") {
92
- return {
93
- kind: "rows",
94
- rows: {
95
- columns: [...result.rows.columns],
96
- rows: result.rows.rows.map((row) => row.map((value) => Value.from(value))),
97
- },
98
- };
148
+ function validateExecuteArguments(sql, params) {
149
+ if (typeof sql !== "string") {
150
+ throw invalidArgumentError("execute", "sql", "string", sql);
151
+ }
152
+ if (!Array.isArray(params)) {
153
+ throw invalidArgumentError("execute", "params", "array", params);
154
+ }
155
+ }
156
+ function invalidArgumentError(operation, argument, expected, actualValue) {
157
+ return createLixError("LIX_INVALID_ARGUMENT", `lix.${operation}() expected ${argument} to be ${expectedArticle(expected)} ${expected}`, {
158
+ details: {
159
+ operation,
160
+ argument,
161
+ expected,
162
+ actual: runtimeTypeName(actualValue),
163
+ },
164
+ });
165
+ }
166
+ function valueFromExecuteParam(param, index) {
167
+ try {
168
+ return Value.from(param);
99
169
  }
170
+ catch (error) {
171
+ throw invalidParamError(index, param, error);
172
+ }
173
+ }
174
+ function invalidParamError(index, actualValue, cause) {
175
+ const message = cause instanceof Error && cause.message
176
+ ? cause.message
177
+ : "parameter is not a valid Lix SQL value";
178
+ return createLixError("LIX_INVALID_PARAM", `lix.execute() invalid parameter $${index + 1}: ${message}`, {
179
+ details: {
180
+ operation: "execute",
181
+ parameter_index: index + 1,
182
+ argument: `params[${index}]`,
183
+ actual: runtimeTypeName(actualValue),
184
+ },
185
+ cause,
186
+ });
187
+ }
188
+ function expectedArticle(expected) {
189
+ return /^[aeiou]/i.test(expected) ? "an" : "a";
190
+ }
191
+ function runtimeTypeName(value) {
192
+ if (value === null)
193
+ return "null";
194
+ if (Array.isArray(value))
195
+ return "array";
196
+ if (value instanceof Date)
197
+ return "Date";
198
+ if (value instanceof ArrayBuffer)
199
+ return "ArrayBuffer";
200
+ if (ArrayBuffer.isView(value))
201
+ return value.constructor.name;
202
+ return typeof value;
203
+ }
204
+ function normalizeExecuteResult(result) {
205
+ const columns = [...result.columns];
100
206
  return {
101
- kind: "affectedRows",
102
- affectedRows: result.affectedRows,
207
+ columns,
208
+ rows: result.rows.map((row) => new Row(columns, row.map((value) => Value.from(value)))),
209
+ rowsAffected: result.rowsAffected,
210
+ notices: result.notices ?? [],
103
211
  };
104
212
  }
213
+ function createLixError(code, message, options = {}) {
214
+ const error = new Error(message);
215
+ error.name = "LixError";
216
+ error.code = code;
217
+ if (options.hint !== undefined) {
218
+ error.hint = options.hint;
219
+ }
220
+ if (options.details !== undefined) {
221
+ error.details = options.details;
222
+ }
223
+ if (options.cause !== undefined) {
224
+ error.cause = options.cause;
225
+ }
226
+ return error;
227
+ }
228
+ function normalizeThrownError(error) {
229
+ if (isLixErrorLike(error)) {
230
+ const hint = typeof error.hint === "string"
231
+ ? error.hint
232
+ : extractHintFromMessage(error.message);
233
+ const details = "details" in error ? error.details : undefined;
234
+ if (error instanceof Error) {
235
+ if (hint !== undefined && error.hint === undefined) {
236
+ error.hint = hint;
237
+ }
238
+ if (details !== undefined && error.details === undefined) {
239
+ error.details = details;
240
+ }
241
+ return error;
242
+ }
243
+ const message = typeof error.message === "string" ? error.message : error.code;
244
+ return createLixError(error.code, message, { hint, details });
245
+ }
246
+ if (error instanceof WebAssembly.RuntimeError) {
247
+ return createLixError("LIX_WASM_RUNTIME_ERROR", error.message, {
248
+ hint: "The Lix engine encountered a WebAssembly runtime trap. Please report this as an engine bug with the SQL statement or API call that triggered it.",
249
+ cause: error,
250
+ });
251
+ }
252
+ if (error instanceof Error) {
253
+ return createLixError("LIX_ERROR_UNKNOWN", error.message, { cause: error });
254
+ }
255
+ return createLixError("LIX_ERROR_UNKNOWN", String(error));
256
+ }
257
+ function extractHintFromMessage(message) {
258
+ if (typeof message !== "string")
259
+ return undefined;
260
+ const match = message.match(/(?:^|\n)hint:\s*(.+)$/s);
261
+ return match?.[1]?.trim();
262
+ }
263
+ function isLixErrorLike(error) {
264
+ return (typeof error === "object" &&
265
+ error !== null &&
266
+ typeof error.code === "string" &&
267
+ error.code.startsWith("LIX_"));
268
+ }
@@ -51,21 +51,21 @@ class BetterSqlite3Backend {
51
51
  this.#db = db;
52
52
  this.#registryKey = registryKey;
53
53
  }
54
- beginTransaction(mode) {
54
+ beginReadTransaction() {
55
55
  this.#ensureOpen();
56
56
  if (this.#db.inTransaction) {
57
57
  throw new Error("cannot open nested Lix backend transaction");
58
58
  }
59
- this.#db.exec(mode === "write" ? "BEGIN IMMEDIATE" : "BEGIN DEFERRED");
59
+ this.#db.exec("BEGIN DEFERRED");
60
60
  return new BetterSqlite3Transaction(this.#db);
61
61
  }
62
- kvGet(namespace, key) {
62
+ beginWriteTransaction() {
63
63
  this.#ensureOpen();
64
- return kvGet(this.#db, namespace, key);
65
- }
66
- kvScan(namespace, range, limit) {
67
- this.#ensureOpen();
68
- return kvScan(this.#db, namespace, range, limit);
64
+ if (this.#db.inTransaction) {
65
+ throw new Error("cannot open nested Lix backend transaction");
66
+ }
67
+ this.#db.exec("BEGIN IMMEDIATE");
68
+ return new BetterSqlite3Transaction(this.#db);
69
69
  }
70
70
  close() {
71
71
  if (this.#closed)
@@ -92,27 +92,59 @@ class BetterSqlite3Transaction {
92
92
  constructor(db) {
93
93
  this.#db = db;
94
94
  }
95
- kvGet(namespace, key) {
95
+ getValues(request) {
96
+ this.#ensureOpen();
97
+ return getValues(this.#db, request);
98
+ }
99
+ existsMany(request) {
96
100
  this.#ensureOpen();
97
- return kvGet(this.#db, namespace, key);
101
+ return existsMany(this.#db, request);
98
102
  }
99
- kvScan(namespace, range, limit) {
103
+ scanKeys(request) {
100
104
  this.#ensureOpen();
101
- return kvScan(this.#db, namespace, range, limit);
105
+ const { pairs, resumeAfter } = scanPage(this.#db, request);
106
+ return {
107
+ keys: pairs.map(({ key }) => key),
108
+ resumeAfter,
109
+ };
102
110
  }
103
- kvPut(namespace, key, value) {
111
+ scanValues(request) {
104
112
  this.#ensureOpen();
105
- this.#db
106
- .prepare(`INSERT INTO lix_kv (namespace, key, value)
107
- VALUES (?, ?, ?)
108
- ON CONFLICT(namespace, key) DO UPDATE SET value = excluded.value`)
109
- .run(namespace, sqliteBytes(key), sqliteBytes(value));
113
+ const { pairs, resumeAfter } = scanPage(this.#db, request);
114
+ return {
115
+ values: pairs.map(({ value }) => value),
116
+ resumeAfter,
117
+ };
110
118
  }
111
- kvDelete(namespace, key) {
119
+ scanEntries(request) {
112
120
  this.#ensureOpen();
113
- this.#db
114
- .prepare("DELETE FROM lix_kv WHERE namespace = ? AND key = ?")
115
- .run(namespace, sqliteBytes(key));
121
+ const { pairs, resumeAfter } = scanPage(this.#db, request);
122
+ return {
123
+ keys: pairs.map(({ key }) => key),
124
+ values: pairs.map(({ value }) => value),
125
+ resumeAfter,
126
+ };
127
+ }
128
+ writeKvBatch(batch) {
129
+ this.#ensureOpen();
130
+ const stats = {
131
+ puts: 0,
132
+ deletes: 0,
133
+ bytesWritten: 0,
134
+ };
135
+ for (const group of batch.groups) {
136
+ for (const put of group.puts) {
137
+ stats.puts += 1;
138
+ stats.bytesWritten += put.key.length + put.value.length;
139
+ kvPut(this.#db, group.namespace, put.key, put.value);
140
+ }
141
+ for (const key of group.deletes) {
142
+ stats.deletes += 1;
143
+ stats.bytesWritten += key.length;
144
+ kvDelete(this.#db, group.namespace, key);
145
+ }
146
+ }
147
+ return stats;
116
148
  }
117
149
  commit() {
118
150
  this.#ensureOpen();
@@ -130,6 +162,34 @@ class BetterSqlite3Transaction {
130
162
  }
131
163
  }
132
164
  }
165
+ function getValues(db, request) {
166
+ return {
167
+ groups: request.groups.map((group) => ({
168
+ namespace: group.namespace,
169
+ values: group.keys.map((key) => kvGet(db, group.namespace, key)),
170
+ })),
171
+ };
172
+ }
173
+ function existsMany(db, request) {
174
+ return {
175
+ groups: request.groups.map((group) => ({
176
+ namespace: group.namespace,
177
+ exists: group.keys.map((key) => kvGet(db, group.namespace, key) !== null),
178
+ })),
179
+ };
180
+ }
181
+ function scanPage(db, request) {
182
+ const scanLimit = request.limit + 1 + (request.after ? 1 : 0);
183
+ const pairs = kvScan(db, request.namespace, request.range, scanLimit).filter((pair) => !request.after || compareBytes(pair.key, request.after) > 0);
184
+ const hasMore = pairs.length > request.limit;
185
+ const pagePairs = pairs.slice(0, request.limit);
186
+ return {
187
+ pairs: pagePairs,
188
+ resumeAfter: hasMore
189
+ ? (pagePairs.at(-1)?.key ?? null)
190
+ : null,
191
+ };
192
+ }
133
193
  function kvGet(db, namespace, key) {
134
194
  const row = db
135
195
  .prepare("SELECT value FROM lix_kv WHERE namespace = ? AND key = ?")
@@ -139,6 +199,14 @@ function kvGet(db, namespace, key) {
139
199
  }
140
200
  return bytesFromUnknown(row.value, "lix_kv.value");
141
201
  }
202
+ function kvPut(db, namespace, key, value) {
203
+ db.prepare(`INSERT INTO lix_kv (namespace, key, value)
204
+ VALUES (?, ?, ?)
205
+ ON CONFLICT(namespace, key) DO UPDATE SET value = excluded.value`).run(namespace, sqliteBytes(key), sqliteBytes(value));
206
+ }
207
+ function kvDelete(db, namespace, key) {
208
+ db.prepare("DELETE FROM lix_kv WHERE namespace = ? AND key = ?").run(namespace, sqliteBytes(key));
209
+ }
142
210
  function kvScan(db, namespace, range, limit) {
143
211
  const { sql, params } = scanQuery(namespace, range, limit);
144
212
  return db.prepare(sql).all(...params).map((row) => {
@@ -174,6 +242,15 @@ function scanQuery(namespace, range, limit) {
174
242
  }
175
243
  return { sql, params };
176
244
  }
245
+ function compareBytes(left, right) {
246
+ const length = Math.min(left.length, right.length);
247
+ for (let index = 0; index < length; index++) {
248
+ const delta = left[index] - right[index];
249
+ if (delta !== 0)
250
+ return delta;
251
+ }
252
+ return left.length - right.length;
253
+ }
177
254
  function prefixUpperBound(prefix) {
178
255
  const end = new Uint8Array(prefix);
179
256
  for (let index = end.length - 1; index >= 0; index--) {
@@ -0,0 +1,18 @@
1
+ # Bundled Lix Engine Source
2
+
3
+ This directory is a generated snapshot of the Rust engine source that backs this @lix-js/sdk release.
4
+
5
+ Source in the Lix monorepo: `packages/engine/src`
6
+
7
+ Agents should inspect these files when SDK behavior is unclear instead of relying only on SKILL.md prose.
8
+
9
+ Useful entry points:
10
+
11
+ - `src/sql2/entity_provider.rs` - registered schema SQL surfaces
12
+ - `src/sql2/change_provider.rs` - `lix_change` projection
13
+ - `src/sql2/version_provider.rs` - writable `lix_version` surface
14
+ - `src/transaction/validation.rs` - primary-key, unique, foreign-key, and shape validation
15
+ - `src/schema/definition.json` - Lix schema-definition meta-schema
16
+ - `src/schema/builtin/` - built-in schema definitions
17
+
18
+ Regenerate with `pnpm --filter @lix-js/sdk sync:engine-src` from the repo root.