@autochitect/engine 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -27
- package/engine.wasm +0 -0
- package/index.d.ts +3 -3
- package/index.mjs +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @autochitect/engine
|
|
2
2
|
|
|
3
|
-
A 245KB WebAssembly
|
|
3
|
+
A 245KB WebAssembly cost estimation engine. Define cost models in a purpose-built DSL, get instant estimates with full dependency tracing. Runs entirely client-side — no server, no latency, no data leaving the browser.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
pnpm install @autochitect/engine
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Quick start
|
|
12
12
|
|
|
13
13
|
```javascript
|
|
14
|
-
import { createEngine } from '
|
|
14
|
+
import { createEngine } from '@autochitect/engine';
|
|
15
15
|
|
|
16
16
|
const engine = await createEngine(
|
|
17
|
-
new URL('
|
|
17
|
+
new URL('@autochitect/engine/engine.wasm', import.meta.url)
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
-
const result = engine.
|
|
20
|
+
const result = engine.estimate(`
|
|
21
21
|
revenue: Input
|
|
22
22
|
cost_ratio: Input
|
|
23
23
|
costs = revenue * cost_ratio
|
|
@@ -35,66 +35,133 @@ console.log(result.results);
|
|
|
35
35
|
|
|
36
36
|
**`result.results`** — computed values for every variable.
|
|
37
37
|
|
|
38
|
-
**`result.graph`** — the full dependency DAG showing how each value was derived. Nodes have `kind` (input, constant, formula, map, scan) and edges show data flow.
|
|
38
|
+
**`result.graph`** — the full dependency DAG showing how each value was derived. Nodes have `kind` (input, constant, formula, map, scan) and edges show data flow. Build audit trails, trace calculations back to source inputs, or render interactive cost breakdowns.
|
|
39
39
|
|
|
40
40
|
**`result.errors`** / **`result.warnings`** — with line and column numbers.
|
|
41
41
|
|
|
42
42
|
## The DSL
|
|
43
43
|
|
|
44
|
-
The language is deliberately small. It's
|
|
44
|
+
The language is deliberately small. It's designed for cost estimation and financial modeling specifically.
|
|
45
45
|
|
|
46
46
|
```
|
|
47
|
-
#
|
|
47
|
+
# Inputs — bind to external data (your JSON)
|
|
48
48
|
revenue: Input("annual_revenue")
|
|
49
|
+
headcount: Input
|
|
50
|
+
|
|
51
|
+
# Constants — fixed values
|
|
49
52
|
tax_rate: Const(0.21)
|
|
53
|
+
avg_salary: Const(85000)
|
|
54
|
+
|
|
55
|
+
# Params — tunable scenario knobs
|
|
50
56
|
growth: Param
|
|
51
57
|
|
|
52
|
-
# Formulas
|
|
58
|
+
# Formulas — define cost relationships
|
|
59
|
+
labor_cost = headcount * avg_salary
|
|
53
60
|
gross_profit = revenue * (1 - cost_ratio)
|
|
54
61
|
net_income = gross_profit * (1 - tax_rate)
|
|
55
62
|
|
|
56
|
-
# Array operations
|
|
63
|
+
# Array operations — project over time
|
|
57
64
|
periods = SEQUENCE(12, 1, 1)
|
|
58
65
|
monthly = MAP(periods, LAMBDA(p, revenue / 12 * POWER(1 + growth, p)))
|
|
59
66
|
|
|
60
|
-
# Accumulation
|
|
67
|
+
# Accumulation — running totals
|
|
61
68
|
cumulative = SCAN(monthly, 0, LAMBDA(acc, m, acc + m))
|
|
62
69
|
```
|
|
63
70
|
|
|
64
|
-
**Inputs** bind to external data (your JSON). **Constants** are fixed values. **
|
|
71
|
+
**Inputs** bind to external data (your JSON). **Constants** are fixed values. **Params** are tunable scenario knobs.
|
|
65
72
|
|
|
66
73
|
**MAP** transforms arrays element-wise. **SCAN** accumulates (like reduce, but returns intermediate results). **LAMBDA** defines inline functions with named parameters.
|
|
67
74
|
|
|
68
|
-
The engine compiles this into a directed acyclic graph, topologically sorts it, and
|
|
75
|
+
The engine compiles this into a directed acyclic graph, topologically sorts it, and estimates in one pass. The graph is immutable — switching scenarios just swaps the input context, so it's instant.
|
|
76
|
+
|
|
77
|
+
## Node.js usage
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
import { createEngine } from '@autochitect/engine';
|
|
81
|
+
import { fileURLToPath } from 'url';
|
|
82
|
+
import { dirname, join } from 'path';
|
|
83
|
+
import { createRequire } from 'module';
|
|
84
|
+
|
|
85
|
+
const require = createRequire(import.meta.url);
|
|
86
|
+
const wasmPath = require.resolve('@autochitect/engine/engine.wasm');
|
|
87
|
+
const engine = await createEngine(wasmPath);
|
|
88
|
+
|
|
89
|
+
const result = engine.estimate(`
|
|
90
|
+
headcount: Input
|
|
91
|
+
avg_salary: Const(85000)
|
|
92
|
+
benefits_rate: Const(0.3)
|
|
93
|
+
|
|
94
|
+
labor_cost = headcount * avg_salary
|
|
95
|
+
benefits = labor_cost * benefits_rate
|
|
96
|
+
total_people_cost = labor_cost + benefits
|
|
97
|
+
`, {
|
|
98
|
+
headcount: 12,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log(result.results);
|
|
102
|
+
// {
|
|
103
|
+
// headcount: 12,
|
|
104
|
+
// avg_salary: 85000,
|
|
105
|
+
// benefits_rate: 0.3,
|
|
106
|
+
// labor_cost: 1020000,
|
|
107
|
+
// benefits: 306000,
|
|
108
|
+
// total_people_cost: 1326000
|
|
109
|
+
// }
|
|
110
|
+
```
|
|
69
111
|
|
|
70
112
|
## Browser usage
|
|
71
113
|
|
|
72
114
|
```html
|
|
73
115
|
<script type="module">
|
|
74
|
-
import { createEngine } from './node_modules/
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
116
|
+
import { createEngine } from './node_modules/@autochitect/engine/index.mjs';
|
|
117
|
+
|
|
118
|
+
const engine = await createEngine(
|
|
119
|
+
new URL('./node_modules/@autochitect/engine/engine.wasm', import.meta.url)
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const result = engine.estimate(`
|
|
123
|
+
units: Input
|
|
124
|
+
price_per_unit: Input
|
|
125
|
+
discount_rate: Input
|
|
126
|
+
|
|
127
|
+
subtotal = units * price_per_unit
|
|
128
|
+
discount = subtotal * discount_rate
|
|
129
|
+
total = subtotal - discount
|
|
130
|
+
`, {
|
|
131
|
+
units: 1000,
|
|
132
|
+
price_per_unit: 49.99,
|
|
133
|
+
discount_rate: 0.15,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
console.log(result.results);
|
|
137
|
+
// { units: 1000, price_per_unit: 49.99, discount_rate: 0.15,
|
|
138
|
+
// subtotal: 49990, discount: 7498.5, total: 42491.5 }
|
|
78
139
|
</script>
|
|
79
140
|
```
|
|
80
141
|
|
|
81
|
-
|
|
142
|
+
When using a bundler (Vite, webpack, etc.), import the WASM file directly:
|
|
82
143
|
|
|
83
144
|
```javascript
|
|
84
|
-
import { createEngine } from '
|
|
85
|
-
import { fileURLToPath } from 'url';
|
|
86
|
-
import { dirname, join } from 'path';
|
|
145
|
+
import { createEngine } from '@autochitect/engine';
|
|
87
146
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
147
|
+
const engine = await createEngine(
|
|
148
|
+
new URL('@autochitect/engine/engine.wasm', import.meta.url)
|
|
149
|
+
);
|
|
91
150
|
```
|
|
92
151
|
|
|
93
152
|
## Options
|
|
94
153
|
|
|
95
154
|
```javascript
|
|
96
|
-
// Skip the dependency graph for faster
|
|
97
|
-
engine.
|
|
155
|
+
// Skip the dependency graph for faster estimation
|
|
156
|
+
engine.estimate(source, inputs, { graph: false });
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## TypeScript
|
|
160
|
+
|
|
161
|
+
Full type definitions are included. Key types:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import type { Engine, EstimateResult, EstimateOptions } from '@autochitect/engine';
|
|
98
165
|
```
|
|
99
166
|
|
|
100
167
|
## License
|
package/engine.wasm
CHANGED
|
Binary file
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface EstimateResult {
|
|
2
2
|
success: boolean;
|
|
3
3
|
results: Record<string, number | number[] | string | null>;
|
|
4
4
|
errors: Array<{ message: string; line: number; col: number }>;
|
|
@@ -16,12 +16,12 @@ export interface EvalResult {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export interface
|
|
19
|
+
export interface EstimateOptions {
|
|
20
20
|
graph?: boolean;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface Engine {
|
|
24
|
-
|
|
24
|
+
estimate(source: string, inputs?: Record<string, unknown>, options?: EstimateOptions): EstimateResult;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function createEngine(wasmSource: string | Response | ArrayBuffer): Promise<Engine>;
|
package/index.mjs
CHANGED
|
@@ -112,11 +112,11 @@ export async function createEngine(wasmSource) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
return {
|
|
115
|
-
|
|
115
|
+
estimate(source, inputs = {}, options = {}) {
|
|
116
116
|
const includeGraph = options.graph !== false;
|
|
117
117
|
const src = writeString(source);
|
|
118
118
|
const json = writeString(JSON.stringify(inputs));
|
|
119
|
-
const resultLen = instance.exports.
|
|
119
|
+
const resultLen = instance.exports.wasm_estimate(
|
|
120
120
|
src.ptr, src.len,
|
|
121
121
|
json.ptr, json.len,
|
|
122
122
|
includeGraph ? 1 : 0
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autochitect/engine",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A 245KB WebAssembly financial modeling engine. Define cost models in a purpose-built DSL, get instant
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "A 245KB WebAssembly financial modeling engine. Define cost models in a purpose-built DSL, get instant estimates with full dependency tracing. No server required.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.mjs",
|