@formata/stof 0.9.15 → 0.9.16

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 CHANGED
@@ -19,61 +19,51 @@
19
19
  <br/>
20
20
 
21
21
  ## Overview
22
+
22
23
  Data and logic have always been separate. That makes things hard. Stof puts them together.
23
24
 
24
- A portable document format where validation, functions, and behavior live alongside the data they belong to, in one document, across any service, language, or runtime.
25
+ A portable document format where validation, functions, and behavior live alongside the data they belong to in one document, across any service, language, or runtime.
25
26
 
26
- > Works with JSON, YAML, TOML, etc. out of the box for seamless interchange. Add sandboxed logic as data where you need it for immediate eval/transforms.
27
+ - **Superset of JSON** valid JSON is always valid Stof. Works with YAML, TOML, and more out of the box.
28
+ - **Sandboxed execution** — logic runs in a secure, isolated runtime. Safe to execute untrusted code from external sources.
29
+ - **Built in Rust, runs everywhere** — native crate, WebAssembly for JS/TS (Node, Deno, Bun, browser), and Python bindings via PyPI.
27
30
 
28
- > Built with Stof: [Limitr](https://limitr.dev) is an open source pricing and enforcement engine. The entire policy - plans, credits, limits, validation logic - lives in a single Stof document.
31
+ > Used in production: [Limitr](https://limitr.dev)'s pricing policy engine plans, credits, limits, validation logic runs entirely on Stof.
32
+
33
+
34
+ ## Data That Does Things
35
+
36
+ Stof starts where JSON ends. Add functions right next to the data they operate on.
29
37
 
30
- ## Define Data and Logic Together - Combine/Split as Needed
31
- `npm i @formata/stof`
32
38
  ```typescript
33
39
  import { stofAsync } from '@formata/stof';
34
40
 
35
- const doc = await stofAsync`{
36
- json: '{"plans":{"pro":{"label":"Pro","price":{"amount":20},"entitlements":{"ai_chat":{"description":"AI Chat Feature","limit":{"credit":"chat-token","value":100000,"resets":true,"reset_inc":1.0}}}}}}'
37
- yaml: ''
41
+ const doc = await stofAsync`
42
+ name: "Alice"
43
+ age: 30
38
44
 
39
- fn transform() {
40
- const policy = new {};
41
- parse(self.json, policy, 'json');
42
-
43
- policy.plans.pro.price.amount = 50;
44
- const entitlements = policy.plans.pro.entitlements;
45
- entitlements.ai_chat.limit.value *= 2;
46
-
47
- self.yaml = stringify('yaml', policy);
48
- Std.pln(self.yaml);
45
+ fn greet() -> str {
46
+ 'Hello, ' + self.name + '!'
49
47
  }
50
- }`;
51
- doc.lib('Std', 'pln', (...args: unknown[])=>console.log(...args));
48
+
49
+ fn can_rent_car() -> bool {
50
+ self.age >= 25
51
+ }
52
+ `;
52
53
 
53
- await doc.call('transform');
54
- ```
55
- ```bash
56
- bun run transform.ts
57
- plans:
58
- pro:
59
- label: Pro
60
- price:
61
- amount: 50
62
- entitlements:
63
- ai_chat:
64
- description: AI Chat Feature
65
- limit:
66
- credit: chat-token
67
- value: 200000
68
- resets: true
69
- reset_inc: 1.0
54
+ console.log(await doc.call('greet')); // Hello, Alice!
55
+ console.log(await doc.call('can_rent_car')); // true
70
56
  ```
71
57
 
58
+ No separate schema file. No external validator. The data knows its own rules.
59
+
60
+
72
61
  ## Units & Types
73
- Rich type system for accuracy and consistency across environments + conversions (time, memory e.g. GB or MiB, temperature, etc.).
62
+
63
+ Rich type system with automatic unit conversions — time, distance, memory, temperature, and more.
74
64
 
75
65
  ```typescript
76
- import { stofAsync } from '../doc.ts';
66
+ import { stofAsync } from '@formata/stof';
77
67
 
78
68
  const doc = await stofAsync`
79
69
  #[type]
@@ -102,10 +92,56 @@ const dist = await doc.call('distance', '{ "x": 3, "y": 4 }');
102
92
  console.log(dist); // 170.52
103
93
  ```
104
94
 
95
+
96
+ ## Format Interop
97
+
98
+ Combine JSON, YAML, TOML, and Stof in a single document. Parse one format, transform it, export as another.
99
+
100
+ ```typescript
101
+ import { stofAsync } from '@formata/stof';
102
+
103
+ const doc = await stofAsync`{
104
+ json: '{"plans":{"pro":{"label":"Pro","price":{"amount":20},"entitlements":{"ai_chat":{"description":"AI Chat Feature","limit":{"credit":"chat-token","value":100000,"resets":true,"reset_inc":1.0}}}}}}'
105
+ yaml: ''
106
+
107
+ fn transform() {
108
+ const policy = new {};
109
+ parse(self.json, policy, 'json');
110
+
111
+ policy.plans.pro.price.amount = 50;
112
+ const entitlements = policy.plans.pro.entitlements;
113
+ entitlements.ai_chat.limit.value *= 2;
114
+
115
+ self.yaml = stringify('yaml', policy);
116
+ Std.pln(self.yaml);
117
+ }
118
+ }`;
119
+ doc.lib('Std', 'pln', (...args: unknown[])=>console.log(...args));
120
+
121
+ await doc.call('transform');
122
+ ```
123
+ ```
124
+ plans:
125
+ pro:
126
+ label: Pro
127
+ price:
128
+ amount: 50
129
+ entitlements:
130
+ ai_chat:
131
+ description: AI Chat Feature
132
+ limit:
133
+ credit: chat-token
134
+ value: 200000
135
+ resets: true
136
+ reset_inc: 1.0
137
+ ```
138
+
139
+
105
140
  ## Self-Expanding Contexts
106
- Documents evolve over time. Stof can even parse itself for immediate use in the same call.
107
141
 
108
- Small surface area, always sandboxed (wasm + host libs), ultra portable, and quick.
142
+ This is the capability that changes everything.
143
+
144
+ Stof documents can parse new Stof into themselves at runtime — receiving code over the network and immediately executing it. The program grows while it runs, always sandboxed.
109
145
 
110
146
  ```typescript
111
147
  import { stofAsync } from '@formata/stof';
@@ -114,9 +150,10 @@ const doc = await stofAsync`
114
150
  api: {}
115
151
 
116
152
  fn load_api(stof: str) {
117
- parse(stof, self.api); // parses itself
153
+ parse(stof, self.api);
118
154
  }`;
119
155
 
156
+ // Imagine this arriving over HTTP, from another service, or from an agent
120
157
  const api = `
121
158
  name: 'Stof'
122
159
  fn message() -> str { 'Hello, ' + self.name ?? 'World' + '!!' }
@@ -128,12 +165,14 @@ fn main() {
128
165
 
129
166
  doc.lib('Std', 'pln', (...args: unknown[])=>console.log(...args));
130
167
  await doc.call('load_api', api);
131
- await doc.run(); // calls #[main] funcs - see docs
168
+ await doc.run(); // calls #[main] funcs
132
169
 
133
170
  // Hello, Stof
134
171
  ```
135
172
 
173
+
136
174
  ## CLI
175
+
137
176
  See [installation docs](https://docs.stof.dev/book/installation) for CLI instructions and more information.
138
177
 
139
178
  ```rust
@@ -147,11 +186,14 @@ fn say_hi() {
147
186
  Hello, world!
148
187
  ```
149
188
 
189
+
150
190
  ## Embedded
191
+
151
192
  Stof is written in Rust, but use it where you work. Join the project [Discord](https://discord.gg/Up5kxdeXZt) to contribute.
152
193
 
153
194
  ### Rust
154
- ``` toml
195
+
196
+ ```toml
155
197
  [dependencies]
156
198
  stof = "0.9.*"
157
199
  ```
@@ -176,6 +218,7 @@ fn main() {
176
218
  ```
177
219
 
178
220
  ### Python
221
+
179
222
  `pip install stof`
180
223
 
181
224
  ```python
@@ -206,9 +249,11 @@ if __name__ == "__main__":
206
249
  ```
207
250
 
208
251
  ### JavaScript/TypeScript
252
+
209
253
  `npm i @formata/stof`
210
254
 
211
255
  #### Initialization
256
+
212
257
  Stof uses WebAssembly, so make sure to initialize it once.
213
258
 
214
259
  ```typescript
@@ -226,39 +271,39 @@ import { initStof } from '@formata/stof';
226
271
  import stofWasm from '@formata/stof/wasm';
227
272
  await initStof(await stofWasm());
228
273
  ```
274
+
275
+ #### Usage
276
+
229
277
  ```typescript
230
278
  import { initStof, StofDoc } from '@formata/stof';
231
279
 
232
- // Initialize wasm once at startup
233
280
  await initStof();
234
281
 
235
- // Create and parse documents
236
282
  const doc = new StofDoc();
237
283
  doc.parse(`
238
284
  name: "Alice"
239
285
  age: 30
240
- fn greet() -> string {
241
- "Hello, " + self.name
286
+ fn greet() -> str {
287
+ 'Hello, ' + self.name
242
288
  }
243
289
  `);
244
290
 
245
- // Call functions and access values
246
291
  const greeting = await doc.call('greet');
247
292
  console.log(greeting); // "Hello, Alice"
248
293
  console.log(doc.get('age')); // 30
249
294
  ```
250
295
 
251
296
  #### JavaScript Interop
297
+
252
298
  ```typescript
253
299
  await initStof();
254
300
  const doc = new StofDoc();
255
301
 
256
- // Register JS functions
257
302
  doc.lib('console', 'log', (...args: unknown[]) => console.log(...args));
258
303
  doc.lib('fetch', 'get', async (url: string) => {
259
304
  const res = await fetch(url);
260
305
  return await res.json();
261
- }, true); // true = async function - full support
306
+ }, true); // true = async function
262
307
 
263
308
  doc.parse(`
264
309
  fn main() {
@@ -271,21 +316,24 @@ await doc.call('main');
271
316
  ```
272
317
 
273
318
  #### Parse & Export
319
+
274
320
  ```typescript
275
- // Parse from JSON
276
321
  doc.parse({ name: "Bob", age: 25 });
277
322
 
278
- // Export to different formats
279
323
  const json = doc.stringify('json');
280
- const obj = doc.record(); // JavaScript object
324
+ const obj = doc.record();
281
325
  ```
282
326
 
283
327
  **Supports**: Node.js, Browser, Deno, Bun, Edge runtimes
284
328
 
329
+
285
330
  ## License
331
+
286
332
  Apache 2.0. See LICENSE for details.
287
333
 
334
+
288
335
  ## Feedback & Community
336
+
289
337
  - Open issues or discussions on [GitHub](https://github.com/dev-formata-io/stof)
290
338
  - Chat with us on [Discord](https://discord.gg/Up5kxdeXZt)
291
339
  - Star the project to support future development!
package/dist/pkg/stof.js CHANGED
@@ -1005,6 +1005,11 @@ function __wbg_get_imports() {
1005
1005
  const ret = arg0.versions;
1006
1006
  return ret;
1007
1007
  };
1008
+ imports.wbg.__wbindgen_cast_19039c21a5ac44b6 = function(arg0, arg1) {
1009
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 7077, function: Function { arguments: [Externref], shim_idx: 7078, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1010
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h72b14ab7db8750ca, wasm_bindgen__convert__closures_____invoke__h53d5cf04cab8438f);
1011
+ return ret;
1012
+ };
1008
1013
  imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(arg0, arg1) {
1009
1014
  // Cast intrinsic for `Ref(String) -> Externref`.
1010
1015
  const ret = getStringFromWasm0(arg0, arg1);
@@ -1015,11 +1020,6 @@ function __wbg_get_imports() {
1015
1020
  const ret = BigInt.asUintN(64, arg0);
1016
1021
  return ret;
1017
1022
  };
1018
- imports.wbg.__wbindgen_cast_79b583b6f4ba1f12 = function(arg0, arg1) {
1019
- // Cast intrinsic for `Closure(Closure { dtor_idx: 7050, function: Function { arguments: [Externref], shim_idx: 7051, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1020
- const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h72b14ab7db8750ca, wasm_bindgen__convert__closures_____invoke__h53d5cf04cab8438f);
1021
- return ret;
1022
- };
1023
1023
  imports.wbg.__wbindgen_cast_9ae0607507abb057 = function(arg0) {
1024
1024
  // Cast intrinsic for `I64 -> Externref`.
1025
1025
  const ret = arg0;
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formata/stof",
3
- "version": "0.9.15",
3
+ "version": "0.9.16",
4
4
  "type": "module",
5
5
  "main": "./dist/doc.js",
6
6
  "types": "./dist/doc.d.ts",