@ferscloud/fers-calculation-web 0.2.22 → 0.2.26
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 +100 -4
- package/fers_calculations.d.ts +11 -0
- package/fers_calculations.js +1 -1
- package/fers_calculations_bg.js +34 -0
- package/fers_calculations_bg.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,106 @@
|
|
|
1
1
|
# @ferscloud/fers-calculation
|
|
2
2
|
|
|
3
|
-
High-performance structural
|
|
4
|
-
|
|
5
|
-
This package is the WebAssembly build of your Rust solver so it can be used from JavaScript and TypeScript (browser apps with a bundler, and in some Node.js setups). It is designed to take structured input (for example JSON) and return results efficiently.
|
|
3
|
+
High-performance structural engineering FEM solver compiled from Rust to WebAssembly. Runs entirely in the browser — no server round-trip per calculation.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
|
-
npm install @ferscloud/fers-calculation
|
|
8
|
+
npm install @ferscloud/fers-calculation
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start — free tier (up to 100 members)
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import init, { calculate_from_json } from "@ferscloud/fers-calculation";
|
|
15
|
+
|
|
16
|
+
await init(); // load the WASM module once
|
|
17
|
+
|
|
18
|
+
const result = calculate_from_json(JSON.stringify(myModel));
|
|
19
|
+
const data = JSON.parse(result);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
No API key required. Works for any model with up to 100 members.
|
|
23
|
+
|
|
24
|
+
## Authenticated tier — Pro (up to 10 000 members)
|
|
25
|
+
|
|
26
|
+
Pro limits are unlocked by passing a short-lived signed token issued by the FERS Cloud server. The token is verified inside the WASM using an Ed25519 public key baked into the binary — it cannot be forged.
|
|
27
|
+
|
|
28
|
+
### How it works
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Your server → POST https://ferscloud.com/api/solver/token → signed 30-min token
|
|
32
|
+
(X-API-Key: <your-api-key>)
|
|
33
|
+
|
|
34
|
+
Browser → calculate_from_json_with_token(model, token) → Pro limits unlocked
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 1. Get an API key
|
|
38
|
+
|
|
39
|
+
Log in at [ferscloud.com](https://ferscloud.com), go to **Profile → API Keys**, and create a key. Store it as an environment variable on your server — never in browser code.
|
|
40
|
+
|
|
41
|
+
### 2. Backend: fetch a solve token
|
|
42
|
+
|
|
43
|
+
Your server fetches and caches the token. Example for a Next.js API route:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// pages/api/solve-token.ts
|
|
47
|
+
const FERS_API_KEY = process.env.FERS_API_KEY!;
|
|
48
|
+
|
|
49
|
+
let cached: { token: string; expiresAt: number } | null = null;
|
|
50
|
+
|
|
51
|
+
export default async function handler(req, res) {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
|
|
54
|
+
// Re-use if more than 5 minutes remain
|
|
55
|
+
if (cached && cached.expiresAt - now > 5 * 60 * 1000) {
|
|
56
|
+
return res.json({ token: cached.token });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const resp = await fetch("https://ferscloud.com/api/solver/token", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: { "X-API-Key": FERS_API_KEY },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!resp.ok) return res.status(502).json({ error: "Token fetch failed" });
|
|
65
|
+
|
|
66
|
+
const { token, expiresAt } = await resp.json();
|
|
67
|
+
cached = { token, expiresAt: new Date(expiresAt).getTime() };
|
|
68
|
+
return res.json({ token });
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Same pattern works for Express, Deno, Bun, Cloudflare Workers, or any server-side runtime.
|
|
73
|
+
|
|
74
|
+
### 3. Frontend: call the solver with the token
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import init, { calculate_from_json_with_token } from "@ferscloud/fers-calculation";
|
|
78
|
+
|
|
79
|
+
await init();
|
|
80
|
+
|
|
81
|
+
const { token } = await fetch("/api/solve-token").then(r => r.json());
|
|
82
|
+
|
|
83
|
+
const result = calculate_from_json_with_token(JSON.stringify(myModel), token);
|
|
84
|
+
const data = JSON.parse(result);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If the token is missing, expired, or invalid, the solver falls back to the free 100-member limit — it never throws.
|
|
88
|
+
|
|
89
|
+
## Tier comparison
|
|
90
|
+
|
|
91
|
+
| Feature | Free | Pro |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Max members | 100 | 10 000 |
|
|
94
|
+
| WASM function | `calculate_from_json` | `calculate_from_json_with_token` |
|
|
95
|
+
| Requires token | No | Yes |
|
|
96
|
+
| Token TTL | — | 30 minutes |
|
|
97
|
+
|
|
98
|
+
## Security note
|
|
99
|
+
|
|
100
|
+
Keep your `FERS_API_KEY` server-side only. The solve token it fetches is safe to pass to the browser — it is short-lived and cryptographically signed. Only FERS Cloud can issue valid tokens; the browser WASM can only verify them.
|
|
101
|
+
|
|
102
|
+
## Links
|
|
103
|
+
|
|
104
|
+
- [Full documentation & getting started](https://ferscloud.com/getting-started)
|
|
105
|
+
- [FERS Cloud](https://ferscloud.com)
|
|
106
|
+
- [FERS_core Python package](https://pypi.org/project/fers-core/)
|
package/fers_calculations.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Free-tier solver (100-member limit). Used when no valid solve token is present.
|
|
6
|
+
*/
|
|
4
7
|
export function calculate_from_json(json_data: string): string;
|
|
5
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Tier-aware solver. Verifies the Ed25519-signed solve token issued by the
|
|
11
|
+
* FERS Cloud server; grants Premium limits (10 000 members) when the token
|
|
12
|
+
* is valid and contains `"tier":"premium"`. Falls back to Free on any
|
|
13
|
+
* failure — expired, malformed, or wrong signature.
|
|
14
|
+
*/
|
|
15
|
+
export function calculate_from_json_with_token(json_data: string, solve_token: string): string;
|
|
16
|
+
|
|
6
17
|
export function load_fers_from_file(path: string): string;
|
package/fers_calculations.js
CHANGED
|
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./fers_calculations_bg.js";
|
|
|
5
5
|
__wbg_set_wasm(wasm);
|
|
6
6
|
wasm.__wbindgen_start();
|
|
7
7
|
export {
|
|
8
|
-
calculate_from_json, load_fers_from_file
|
|
8
|
+
calculate_from_json, calculate_from_json_with_token, load_fers_from_file
|
|
9
9
|
} from "./fers_calculations_bg.js";
|
package/fers_calculations_bg.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Free-tier solver (100-member limit). Used when no valid solve token is present.
|
|
2
3
|
* @param {string} json_data
|
|
3
4
|
* @returns {string}
|
|
4
5
|
*/
|
|
@@ -17,6 +18,32 @@ export function calculate_from_json(json_data) {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Tier-aware solver. Verifies the Ed25519-signed solve token issued by the
|
|
23
|
+
* FERS Cloud server; grants Premium limits (10 000 members) when the token
|
|
24
|
+
* is valid and contains `"tier":"premium"`. Falls back to Free on any
|
|
25
|
+
* failure — expired, malformed, or wrong signature.
|
|
26
|
+
* @param {string} json_data
|
|
27
|
+
* @param {string} solve_token
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function calculate_from_json_with_token(json_data, solve_token) {
|
|
31
|
+
let deferred3_0;
|
|
32
|
+
let deferred3_1;
|
|
33
|
+
try {
|
|
34
|
+
const ptr0 = passStringToWasm0(json_data, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
35
|
+
const len0 = WASM_VECTOR_LEN;
|
|
36
|
+
const ptr1 = passStringToWasm0(solve_token, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
37
|
+
const len1 = WASM_VECTOR_LEN;
|
|
38
|
+
const ret = wasm.calculate_from_json_with_token(ptr0, len0, ptr1, len1);
|
|
39
|
+
deferred3_0 = ret[0];
|
|
40
|
+
deferred3_1 = ret[1];
|
|
41
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
42
|
+
} finally {
|
|
43
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
20
47
|
/**
|
|
21
48
|
* @param {string} path
|
|
22
49
|
* @returns {string}
|
|
@@ -35,6 +62,13 @@ export function load_fers_from_file(path) {
|
|
|
35
62
|
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
|
|
36
63
|
}
|
|
37
64
|
}
|
|
65
|
+
export function __wbg___wbindgen_throw_1506f2235d1bdba0(arg0, arg1) {
|
|
66
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
67
|
+
}
|
|
68
|
+
export function __wbg_now_190933fa139cc119() {
|
|
69
|
+
const ret = Date.now();
|
|
70
|
+
return ret;
|
|
71
|
+
}
|
|
38
72
|
export function __wbindgen_init_externref_table() {
|
|
39
73
|
const table = wasm.__wbindgen_externrefs;
|
|
40
74
|
const offset = table.grow(4);
|
|
Binary file
|