@autochitect/engine 1.1.0 → 1.1.1

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 (3) hide show
  1. package/README.md +10 -12
  2. package/index.mjs +18 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@ A 245KB WebAssembly cost estimation engine. Define cost models in a purpose-buil
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- pnpm install @autochitect/engine
8
+ npm install @autochitect/engine
9
9
  ```
10
10
 
11
11
  ## Quick start
@@ -35,7 +35,7 @@ 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. Build audit trails, trace calculations back to source inputs, or render interactive cost breakdowns.
38
+ **`result.graph`** — the full dependency DAG showing how each value was derived. Nodes have `kind` (input, 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
 
@@ -48,16 +48,16 @@ The language is deliberately small. It's designed for cost estimation and financ
48
48
  revenue: Input("annual_revenue")
49
49
  headcount: Input
50
50
 
51
- # Constants — fixed values
52
- tax_rate: Const(0.21)
53
- avg_salary: Const(85000)
51
+ # Constants — use formula assignment
52
+ tax_rate = 0.21
53
+ avg_salary = 85000
54
54
 
55
- # Params — tunable scenario knobs
55
+ # Params — tunable scenario knobs (passed via inputs)
56
56
  growth: Param
57
57
 
58
58
  # Formulas — define cost relationships
59
59
  labor_cost = headcount * avg_salary
60
- gross_profit = revenue * (1 - cost_ratio)
60
+ gross_profit = revenue * (1 - tax_rate)
61
61
  net_income = gross_profit * (1 - tax_rate)
62
62
 
63
63
  # Array operations — project over time
@@ -68,7 +68,7 @@ monthly = MAP(periods, LAMBDA(p, revenue / 12 * POWER(1 + growth, p)))
68
68
  cumulative = SCAN(monthly, 0, LAMBDA(acc, m, acc + m))
69
69
  ```
70
70
 
71
- **Inputs** bind to external data (your JSON). **Constants** are fixed values. **Params** are tunable scenario knobs.
71
+ **Inputs** bind to external data (your JSON). **Constants** are defined with formula assignment (`name = value`). **Params** are tunable scenario knobs passed via the inputs object.
72
72
 
73
73
  **MAP** transforms arrays element-wise. **SCAN** accumulates (like reduce, but returns intermediate results). **LAMBDA** defines inline functions with named parameters.
74
74
 
@@ -78,8 +78,6 @@ The engine compiles this into a directed acyclic graph, topologically sorts it,
78
78
 
79
79
  ```javascript
80
80
  import { createEngine } from '@autochitect/engine';
81
- import { fileURLToPath } from 'url';
82
- import { dirname, join } from 'path';
83
81
  import { createRequire } from 'module';
84
82
 
85
83
  const require = createRequire(import.meta.url);
@@ -88,8 +86,8 @@ const engine = await createEngine(wasmPath);
88
86
 
89
87
  const result = engine.estimate(`
90
88
  headcount: Input
91
- avg_salary: Const(85000)
92
- benefits_rate: Const(0.3)
89
+ avg_salary = 85000
90
+ benefits_rate = 0.3
93
91
 
94
92
  labor_cost = headcount * avg_salary
95
93
  benefits = labor_cost * benefits_rate
package/index.mjs CHANGED
@@ -88,16 +88,31 @@ export async function createEngine(wasmSource) {
88
88
  } else if (wasmSource instanceof Response || (typeof wasmSource === 'object' && typeof wasmSource.then === 'function')) {
89
89
  const response = await wasmSource;
90
90
  bytes = await response.arrayBuffer();
91
+ } else if (wasmSource instanceof URL) {
92
+ if (wasmSource.protocol === 'file:') {
93
+ const fs = await import('fs');
94
+ bytes = fs.readFileSync(wasmSource);
95
+ } else {
96
+ bytes = await (await fetch(wasmSource)).arrayBuffer();
97
+ }
91
98
  } else if (typeof wasmSource === 'string') {
92
- if (typeof fetch !== 'undefined') {
99
+ const isFilePath = wasmSource.startsWith('/') || wasmSource.startsWith('./') || wasmSource.startsWith('../') || wasmSource.startsWith('file://') || /^[a-zA-Z]:\\/.test(wasmSource);
100
+ if (isFilePath && typeof globalThis.process !== 'undefined') {
101
+ const fs = await import('fs');
102
+ if (wasmSource.startsWith('file://')) {
103
+ const { fileURLToPath } = await import('url');
104
+ bytes = fs.readFileSync(fileURLToPath(wasmSource));
105
+ } else {
106
+ bytes = fs.readFileSync(wasmSource);
107
+ }
108
+ } else if (typeof fetch !== 'undefined') {
93
109
  bytes = await (await fetch(wasmSource)).arrayBuffer();
94
110
  } else {
95
111
  const fs = await import('fs');
96
- const path = await import('path');
97
112
  bytes = fs.readFileSync(wasmSource);
98
113
  }
99
114
  } else {
100
- throw new Error('wasmSource must be a URL string, Response, or ArrayBuffer');
115
+ throw new Error('wasmSource must be a URL, URL string, file path, Response, or ArrayBuffer');
101
116
  }
102
117
 
103
118
  const { instance } = await WebAssembly.instantiate(bytes, imports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autochitect/engine",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
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",