@lemmabase/lemma-engine 0.8.19 → 0.8.21
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.
- package/README.md +7 -3
- package/lemma.bindings.d.ts +2 -4
- package/lemma.bindings.js +7 -37
- package/lemma.d.ts +9 -5
- package/lemma.iife.js +1 -1
- package/lemma_bg.wasm +0 -0
- package/lemma_bg.wasm.d.ts +2 -3
- package/monaco.js +39 -36
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Pricing tiers, tax brackets, leave entitlement, eligibility checks, discount sta
|
|
|
7
7
|
```lemma
|
|
8
8
|
spec pricing 2026-01-01
|
|
9
9
|
|
|
10
|
-
data money:
|
|
10
|
+
data money: measure
|
|
11
11
|
-> unit eur 1.00
|
|
12
12
|
-> decimals 2
|
|
13
13
|
|
|
@@ -42,7 +42,7 @@ The `Response` carries every rule's value (or `veto` if no result could be compu
|
|
|
42
42
|
- **Deterministic.** `(spec, data, effective_date) → result`. No DB, no clock, no ambient state. Same inputs → same outputs, every time.
|
|
43
43
|
- **Explainable.** The `Response` tells you which rules contributed and why; pair it with the [CLI](https://github.com/lemma/lemma) for a full reasoning trace.
|
|
44
44
|
- **Time-aware.** Multiple versions of the same spec coexist. Pass an `effective` date and the engine resolves the version in force on that day.
|
|
45
|
-
- **Statically checked.** Type errors, missing data, cycles,
|
|
45
|
+
- **Statically checked.** Type errors, missing data, cycles, measure-family mismatches - all caught at `load()` time. Bad specs never reach `run()`.
|
|
46
46
|
- **Runs anywhere V8 does.** ~2 MB WASM, no native binary, no postinstall script.
|
|
47
47
|
- **Editor in a tab.** Includes an in-process language server and a Monaco adapter, so you can build a real Lemma editor experience client-side - diagnostics, completion, formatting... even without setting up a server.
|
|
48
48
|
|
|
@@ -130,7 +130,7 @@ Specs that reference `uses … @org/pkg` need that package available. `fetch` on
|
|
|
130
130
|
import { Lemma } from '@lemmabase/lemma-engine';
|
|
131
131
|
|
|
132
132
|
const engine = await Lemma();
|
|
133
|
-
const { source, id } = await engine.fetch('@
|
|
133
|
+
const { source, id } = await engine.fetch('@iso/countries');
|
|
134
134
|
await engine.load_batch({ '': source }, id);
|
|
135
135
|
await engine.load(sourceThatUsesStd, 'app.lemma');
|
|
136
136
|
```
|
|
@@ -141,6 +141,10 @@ In the browser, the registry must allow your origin (CORS). Use `https` or `http
|
|
|
141
141
|
|
|
142
142
|
Lemma is pre-1.0. The WASM API is stable for most use cases, but breaking changes may occur between minor versions. Pin your dependency version and review the [changelog](https://github.com/lemma/lemma/blob/main/CHANGELOG.md) before upgrading.
|
|
143
143
|
|
|
144
|
+
### WASM panic behavior
|
|
145
|
+
|
|
146
|
+
Rust panics cannot unwind on the `wasm32` target, so an internal invariant violation (a bug) traps the WASM instance. The call throws a `RuntimeError` which you can catch with `try/catch` to fail gracefully, but the module's linear memory is poisoned — constructing a new `Engine()` from the same initialized module is not safe. To recover, re-initialize the WASM module (`init()` again) or, for robust containment, run the engine in a Web Worker and respawn the worker on trap. The panic message (prefixed `BUG: ...`) is logged to the console before the trap. All domain-level failures (invalid specs, bad data, impossible rules) are reported as `EngineError[]` or vetoes and never cause traps.
|
|
147
|
+
|
|
144
148
|
## Related
|
|
145
149
|
|
|
146
150
|
- [`lemmabase.com`](https://lemmabase.com): public database for Lemma Specs
|
package/lemma.bindings.d.ts
CHANGED
|
@@ -24,7 +24,6 @@ export class Engine {
|
|
|
24
24
|
* Canonical Lemma source for `repository`, formatted from the in-engine AST (e.g. `"lemma"`).
|
|
25
25
|
*/
|
|
26
26
|
format_repository(repository: string): string;
|
|
27
|
-
invert(spec_name: string, rule_name: string, target_json: string, provided_values_json: string): any;
|
|
28
27
|
/**
|
|
29
28
|
* Same data as [`Engine::list`]: grouped [`ResolvedRepository`] JSON without planning.
|
|
30
29
|
*/
|
|
@@ -125,16 +124,15 @@ export interface InitOutput {
|
|
|
125
124
|
readonly wasmengine_fetch: (a: number, b: number, c: number) => number;
|
|
126
125
|
readonly wasmengine_format: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
127
126
|
readonly wasmengine_format_repository: (a: number, b: number, c: number, d: number) => void;
|
|
128
|
-
readonly wasmengine_invert: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
|
|
129
127
|
readonly wasmengine_list: (a: number, b: number) => void;
|
|
130
128
|
readonly wasmengine_load: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
131
129
|
readonly wasmengine_load_batch: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
132
130
|
readonly wasmengine_new: () => number;
|
|
133
131
|
readonly wasmengine_run: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
|
|
134
132
|
readonly wasmengine_schema: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
|
|
135
|
-
readonly
|
|
133
|
+
readonly __wasm_bindgen_func_elem_12239: (a: number, b: number, c: number, d: number) => void;
|
|
136
134
|
readonly __wasm_bindgen_func_elem_2740: (a: number, b: number, c: number, d: number) => void;
|
|
137
|
-
readonly
|
|
135
|
+
readonly __wasm_bindgen_func_elem_12250: (a: number, b: number, c: number, d: number) => void;
|
|
138
136
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
139
137
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
140
138
|
readonly __wbindgen_export3: (a: number) => void;
|
package/lemma.bindings.js
CHANGED
|
@@ -79,36 +79,6 @@ export class Engine {
|
|
|
79
79
|
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
83
|
-
* @param {string} spec_name
|
|
84
|
-
* @param {string} rule_name
|
|
85
|
-
* @param {string} target_json
|
|
86
|
-
* @param {string} provided_values_json
|
|
87
|
-
* @returns {any}
|
|
88
|
-
*/
|
|
89
|
-
invert(spec_name, rule_name, target_json, provided_values_json) {
|
|
90
|
-
try {
|
|
91
|
-
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
92
|
-
const ptr0 = passStringToWasm0(spec_name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
93
|
-
const len0 = WASM_VECTOR_LEN;
|
|
94
|
-
const ptr1 = passStringToWasm0(rule_name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
95
|
-
const len1 = WASM_VECTOR_LEN;
|
|
96
|
-
const ptr2 = passStringToWasm0(target_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
97
|
-
const len2 = WASM_VECTOR_LEN;
|
|
98
|
-
const ptr3 = passStringToWasm0(provided_values_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
99
|
-
const len3 = WASM_VECTOR_LEN;
|
|
100
|
-
wasm.wasmengine_invert(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
|
|
101
|
-
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
102
|
-
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
103
|
-
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
104
|
-
if (r2) {
|
|
105
|
-
throw takeObject(r1);
|
|
106
|
-
}
|
|
107
|
-
return takeObject(r0);
|
|
108
|
-
} finally {
|
|
109
|
-
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
82
|
/**
|
|
113
83
|
* Same data as [`Engine::list`]: grouped [`ResolvedRepository`] JSON without planning.
|
|
114
84
|
* @returns {any}
|
|
@@ -696,7 +666,7 @@ function __wbg_get_imports() {
|
|
|
696
666
|
const a = state0.a;
|
|
697
667
|
state0.a = 0;
|
|
698
668
|
try {
|
|
699
|
-
return
|
|
669
|
+
return __wasm_bindgen_func_elem_12250(a, state0.b, arg0, arg1);
|
|
700
670
|
} finally {
|
|
701
671
|
state0.a = a;
|
|
702
672
|
}
|
|
@@ -855,8 +825,8 @@ function __wbg_get_imports() {
|
|
|
855
825
|
return addHeapObject(ret);
|
|
856
826
|
},
|
|
857
827
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
858
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
859
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
828
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1410, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
829
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_12239);
|
|
860
830
|
return addHeapObject(ret);
|
|
861
831
|
},
|
|
862
832
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
@@ -898,10 +868,10 @@ function __wbg_get_imports() {
|
|
|
898
868
|
};
|
|
899
869
|
}
|
|
900
870
|
|
|
901
|
-
function
|
|
871
|
+
function __wasm_bindgen_func_elem_12239(arg0, arg1, arg2) {
|
|
902
872
|
try {
|
|
903
873
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
904
|
-
wasm.
|
|
874
|
+
wasm.__wasm_bindgen_func_elem_12239(retptr, arg0, arg1, addHeapObject(arg2));
|
|
905
875
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
906
876
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
907
877
|
if (r1) {
|
|
@@ -926,8 +896,8 @@ function __wasm_bindgen_func_elem_2740(arg0, arg1, arg2) {
|
|
|
926
896
|
}
|
|
927
897
|
}
|
|
928
898
|
|
|
929
|
-
function
|
|
930
|
-
wasm.
|
|
899
|
+
function __wasm_bindgen_func_elem_12250(arg0, arg1, arg2, arg3) {
|
|
900
|
+
wasm.__wasm_bindgen_func_elem_12250(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
931
901
|
}
|
|
932
902
|
|
|
933
903
|
|
package/lemma.d.ts
CHANGED
|
@@ -50,6 +50,10 @@ declare module './lemma.bindings.js' {
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* `repository`: qualifier or `null`/omit for workspace — same as `Engine::run` `repo`.
|
|
53
|
+
*
|
|
54
|
+
* `data_values`: pass integers as numbers, decimals as strings (e.g.
|
|
55
|
+
* `{ quantity: 42, rate: "0.075" }`). Non-integer numbers are rejected
|
|
56
|
+
* to prevent silent precision loss from IEEE 754 doubles.
|
|
53
57
|
*/
|
|
54
58
|
run(
|
|
55
59
|
repository: string | null | undefined,
|
|
@@ -147,7 +151,7 @@ export type LemmaType =
|
|
|
147
151
|
& (
|
|
148
152
|
| { kind: "boolean"; help: string }
|
|
149
153
|
| {
|
|
150
|
-
kind: "
|
|
154
|
+
kind: "measure";
|
|
151
155
|
minimum: string | null;
|
|
152
156
|
maximum: string | null;
|
|
153
157
|
decimals: number | null;
|
|
@@ -155,7 +159,7 @@ export type LemmaType =
|
|
|
155
159
|
help: string;
|
|
156
160
|
}
|
|
157
161
|
| {
|
|
158
|
-
kind: "
|
|
162
|
+
kind: "measure range";
|
|
159
163
|
minimum: string | null;
|
|
160
164
|
maximum: string | null;
|
|
161
165
|
decimals: number | null;
|
|
@@ -220,7 +224,7 @@ export interface RuleResult {
|
|
|
220
224
|
display?: string | null;
|
|
221
225
|
veto_reason?: string | null;
|
|
222
226
|
rule_type: string;
|
|
223
|
-
|
|
227
|
+
measure?: Record<string, string> | null;
|
|
224
228
|
ratio?: Record<string, string> | null;
|
|
225
229
|
number?: string | null;
|
|
226
230
|
boolean?: boolean | null;
|
|
@@ -233,7 +237,7 @@ export interface RuleResult {
|
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
export interface RuleResultPayload {
|
|
236
|
-
|
|
240
|
+
measure?: Record<string, string> | null;
|
|
237
241
|
ratio?: Record<string, string> | null;
|
|
238
242
|
number?: string | null;
|
|
239
243
|
boolean?: boolean | null;
|
|
@@ -252,7 +256,7 @@ export interface EvaluationDataEntry {
|
|
|
252
256
|
export interface SpecSchema {
|
|
253
257
|
spec: string;
|
|
254
258
|
data: Record<string, DataEntry>;
|
|
255
|
-
/** Rule result types;
|
|
259
|
+
/** Rule result types; measure and ratio entries expose `units[]` like their data counterparts. */
|
|
256
260
|
rules: Record<string, LemmaType>;
|
|
257
261
|
meta: Record<string, unknown>;
|
|
258
262
|
}
|