@sema-lang/sema 1.9.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.
@@ -0,0 +1,299 @@
1
+ /**
2
+ * @sema-lang/sema — Sema Lisp interpreter for JavaScript
3
+ *
4
+ * A client-side scripting engine powered by WebAssembly.
5
+ * Embed Sema as a scripting language in your web applications.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * import { SemaInterpreter } from "@sema-lang/sema";
10
+ *
11
+ * const sema = await SemaInterpreter.create();
12
+ * const result = sema.evalStr("(+ 1 2 3)");
13
+ * console.log(result.value); // "6"
14
+ * ```
15
+ */
16
+ import type { VFSBackend } from "./vfs.js";
17
+ /** Result of evaluating Sema code. */
18
+ export interface EvalResult {
19
+ /** The string representation of the result value, or null if the expression returned nil. */
20
+ value: string | null;
21
+ /** Lines printed to stdout during evaluation (via `print`, `println`, `display`). */
22
+ output: string[];
23
+ /** Error message if evaluation failed, or null on success. */
24
+ error: string | null;
25
+ }
26
+ /** Options for creating a SemaInterpreter. */
27
+ export interface InterpreterOptions {
28
+ /**
29
+ * URL to the `.wasm` binary. Required when loading from a CDN or
30
+ * when the default resolution doesn't work.
31
+ *
32
+ * @example
33
+ * ```js
34
+ * const sema = await SemaInterpreter.create({
35
+ * wasmUrl: "https://cdn.jsdelivr.net/npm/@sema-lang/sema-wasm@1.9.0/sema_wasm_bg.wasm"
36
+ * });
37
+ * ```
38
+ */
39
+ wasmUrl?: string | URL;
40
+ /**
41
+ * Whether to include the standard library. Default: `true`.
42
+ * Set to `false` for a minimal interpreter with only special forms.
43
+ */
44
+ stdlib?: boolean;
45
+ /**
46
+ * Array of capabilities to deny. Available capabilities:
47
+ * - `"network"` — deny HTTP functions (http/get, http/post, etc.)
48
+ * - `"fs-read"` — deny VFS read operations
49
+ * - `"fs-write"` — deny VFS write operations
50
+ *
51
+ * @example
52
+ * ```js
53
+ * const sema = await SemaInterpreter.create({ deny: ["network"] });
54
+ * ```
55
+ */
56
+ deny?: Array<"network" | "fs-read" | "fs-write">;
57
+ /**
58
+ * Optional VFS backend for persisting files across page reloads.
59
+ *
60
+ * Built-in backends:
61
+ * - {@link MemoryBackend} — ephemeral, no persistence (default behavior)
62
+ * - {@link LocalStorageBackend} — persist to localStorage (~5 MB limit)
63
+ * - {@link SessionStorageBackend} — persist within the tab session
64
+ * - {@link IndexedDBBackend} — persist to IndexedDB (recommended for production)
65
+ *
66
+ * @example
67
+ * ```js
68
+ * import { SemaInterpreter, IndexedDBBackend } from "@sema-lang/sema";
69
+ * const sema = await SemaInterpreter.create({
70
+ * vfs: new IndexedDBBackend({ namespace: "my-project" }),
71
+ * });
72
+ * ```
73
+ */
74
+ vfs?: VFSBackend;
75
+ }
76
+ /** Virtual filesystem usage statistics. */
77
+ export interface VFSStats {
78
+ /** Number of files currently in the VFS. */
79
+ files: number;
80
+ /** Total bytes used. */
81
+ bytes: number;
82
+ /** Maximum number of files allowed. */
83
+ maxFiles: number;
84
+ /** Maximum total bytes allowed. */
85
+ maxBytes: number;
86
+ /** Maximum bytes per individual file. */
87
+ maxFileBytes: number;
88
+ }
89
+ /**
90
+ * A Sema Lisp interpreter instance.
91
+ *
92
+ * Each interpreter has its own isolated environment — variables defined in one
93
+ * interpreter are not visible in another.
94
+ *
95
+ * @example
96
+ * ```js
97
+ * const sema = await SemaInterpreter.create();
98
+ *
99
+ * // Evaluate expressions
100
+ * sema.evalStr("(define x 42)");
101
+ * const r = sema.evalStr("(* x x)");
102
+ * console.log(r.value); // "1764"
103
+ *
104
+ * // Register JS functions
105
+ * sema.registerFunction("greet", (name) => `Hello, ${name}!`);
106
+ * sema.evalStr('(greet "world")'); // => "Hello, world!"
107
+ *
108
+ * // Preload modules
109
+ * sema.preloadModule("utils", "(define (double x) (* x 2))");
110
+ * sema.evalStr('(import "utils")');
111
+ * sema.evalStr("(double 21)"); // => "42"
112
+ * ```
113
+ */
114
+ export declare class SemaInterpreter {
115
+ private _inner;
116
+ private _vfsBackend;
117
+ private constructor();
118
+ /**
119
+ * Create a new SemaInterpreter instance.
120
+ *
121
+ * This initializes the WASM module (once, globally) and creates an interpreter.
122
+ * The WASM module is cached — subsequent calls are fast.
123
+ *
124
+ * @param opts - Configuration options
125
+ * @returns A ready-to-use SemaInterpreter
126
+ *
127
+ * @example
128
+ * ```js
129
+ * // Default: full standard library
130
+ * const sema = await SemaInterpreter.create();
131
+ *
132
+ * // Minimal: only special forms
133
+ * const minimal = await SemaInterpreter.create({ stdlib: false });
134
+ *
135
+ * // From CDN
136
+ * const cdn = await SemaInterpreter.create({
137
+ * wasmUrl: "https://cdn.jsdelivr.net/npm/@sema-lang/sema-wasm@1.9.0/sema_wasm_bg.wasm"
138
+ * });
139
+ * ```
140
+ */
141
+ static create(opts?: InterpreterOptions): Promise<SemaInterpreter>;
142
+ private _vfsHost;
143
+ /**
144
+ * Evaluate a string of Sema code.
145
+ *
146
+ * Definitions persist across calls — you can `define` a function in one call
147
+ * and use it in the next.
148
+ *
149
+ * @param code - Sema source code to evaluate
150
+ * @returns The evaluation result
151
+ *
152
+ * @example
153
+ * ```js
154
+ * const r = sema.evalStr("(map (lambda (x) (* x x)) '(1 2 3 4 5))");
155
+ * console.log(r.value); // "(1 4 9 16 25)"
156
+ * console.log(r.output); // [] (no print statements)
157
+ * console.log(r.error); // null (no error)
158
+ * ```
159
+ */
160
+ evalStr(code: string): EvalResult;
161
+ /**
162
+ * Evaluate code with async HTTP support.
163
+ *
164
+ * Use this when your Sema code uses `http/get` or other network functions.
165
+ * The interpreter will automatically handle the async fetch operations.
166
+ *
167
+ * @param code - Sema source code to evaluate
168
+ * @returns The evaluation result
169
+ *
170
+ * @example
171
+ * ```js
172
+ * const r = await sema.evalStrAsync('(http/get "https://api.example.com/data")');
173
+ * ```
174
+ */
175
+ evalStrAsync(code: string): Promise<EvalResult>;
176
+ /**
177
+ * Register a JavaScript function that can be called from Sema code.
178
+ *
179
+ * Arguments are passed as native JavaScript values (numbers, strings,
180
+ * booleans, null, arrays, objects). The return value is converted back
181
+ * to a Sema value.
182
+ *
183
+ * @param name - The function name in Sema (e.g., "my-fn")
184
+ * @param fn - The JavaScript function to call
185
+ *
186
+ * @example
187
+ * ```js
188
+ * // Simple function — args are native JS values
189
+ * sema.registerFunction("add1", (n) => n + 1);
190
+ *
191
+ * // Multiple args
192
+ * sema.registerFunction("greet", (greeting, name) => `${greeting}, ${name}!`);
193
+ *
194
+ * // Returning structured data (objects become Sema maps)
195
+ * sema.registerFunction("get-user", (id) => ({ name: "Alice", age: 30 }));
196
+ * ```
197
+ */
198
+ registerFunction(name: string, fn: (...args: any[]) => any): void;
199
+ /**
200
+ * Preload a virtual module so that `(import "name")` works without a file.
201
+ *
202
+ * @param name - The module name (used in `(import "name")`)
203
+ * @param source - Sema source code defining the module's exports
204
+ * @throws If the module source has syntax or evaluation errors
205
+ *
206
+ * @example
207
+ * ```js
208
+ * sema.preloadModule("utils", `
209
+ * (define (double x) (* x 2))
210
+ * (define pi 3.14159)
211
+ * `);
212
+ *
213
+ * sema.evalStr('(import "utils")');
214
+ * sema.evalStr("(double pi)"); // => "6.28318"
215
+ * ```
216
+ */
217
+ preloadModule(name: string, source: string): void;
218
+ /**
219
+ * Read a file from the virtual filesystem.
220
+ * @returns The file contents, or null if the file doesn't exist.
221
+ */
222
+ readFile(path: string): string | null;
223
+ /**
224
+ * Write a file to the virtual filesystem.
225
+ * Quotas: 1 MB per file, 16 MB total, 256 files max.
226
+ * @throws If a VFS quota is exceeded.
227
+ */
228
+ writeFile(path: string, content: string): void;
229
+ /**
230
+ * Delete a file from the virtual filesystem.
231
+ * @returns true if the file existed and was deleted.
232
+ */
233
+ deleteFile(path: string): boolean;
234
+ /**
235
+ * List entries in a VFS directory.
236
+ * @returns Array of file and directory names (not full paths).
237
+ */
238
+ listFiles(dir?: string): string[];
239
+ /**
240
+ * Check if a path exists in the VFS (file or directory).
241
+ */
242
+ fileExists(path: string): boolean;
243
+ /**
244
+ * Create a directory (and parent directories) in the VFS.
245
+ */
246
+ mkdir(path: string): void;
247
+ /**
248
+ * Check if a path is a directory in the VFS.
249
+ */
250
+ isDirectory(path: string): boolean;
251
+ /**
252
+ * Get VFS usage statistics (file count, bytes used, quotas).
253
+ */
254
+ vfsStats(): VFSStats;
255
+ /**
256
+ * Clear all files and directories from the VFS.
257
+ */
258
+ resetVFS(): void;
259
+ /**
260
+ * Persist VFS changes to the configured backend.
261
+ *
262
+ * No-op if no VFS backend was provided during creation.
263
+ * Call this after eval to save files.
264
+ *
265
+ * @example
266
+ * ```js
267
+ * await sema.evalStrAsync(code);
268
+ * await sema.flushVFS(); // persist to localStorage/IndexedDB/etc.
269
+ * ```
270
+ */
271
+ flushVFS(): Promise<void>;
272
+ /**
273
+ * Clear the VFS and the persistent backend (if configured).
274
+ */
275
+ resetVFSAndBackend(): Promise<void>;
276
+ /**
277
+ * Get the Sema interpreter version.
278
+ *
279
+ * @returns Version string (e.g., "1.9.0")
280
+ */
281
+ version(): string;
282
+ /**
283
+ * Free the interpreter's WASM memory.
284
+ *
285
+ * Call this when you're done with the interpreter to release resources.
286
+ * The interpreter cannot be used after calling this method.
287
+ */
288
+ dispose(): void;
289
+ }
290
+ export type { VFSBackend, VFSHost } from "./vfs.js";
291
+ export { MemoryBackend } from "./backends/memory.js";
292
+ export { LocalStorageBackend } from "./backends/local-storage.js";
293
+ export type { LocalStorageBackendOptions } from "./backends/local-storage.js";
294
+ export { SessionStorageBackend } from "./backends/session-storage.js";
295
+ export type { SessionStorageBackendOptions } from "./backends/session-storage.js";
296
+ export { IndexedDBBackend } from "./backends/indexed-db.js";
297
+ export type { IndexedDBBackendOptions } from "./backends/indexed-db.js";
298
+ /** @deprecated Use `SemaInterpreter` instead. */
299
+ export { SemaInterpreter as Interpreter };
package/dist/index.js ADDED
@@ -0,0 +1,324 @@
1
+ /**
2
+ * @sema-lang/sema — Sema Lisp interpreter for JavaScript
3
+ *
4
+ * A client-side scripting engine powered by WebAssembly.
5
+ * Embed Sema as a scripting language in your web applications.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * import { SemaInterpreter } from "@sema-lang/sema";
10
+ *
11
+ * const sema = await SemaInterpreter.create();
12
+ * const result = sema.evalStr("(+ 1 2 3)");
13
+ * console.log(result.value); // "6"
14
+ * ```
15
+ */
16
+ // Internal state
17
+ let _init = null;
18
+ let _SemaInterpreter = null;
19
+ let _initialized = false;
20
+ let _initPromise = null;
21
+ async function ensureInit(wasmUrl) {
22
+ if (_initialized)
23
+ return;
24
+ if (_initPromise) {
25
+ await _initPromise;
26
+ return;
27
+ }
28
+ _initPromise = (async () => {
29
+ // Dynamic import so bundlers can tree-shake when not used
30
+ const mod = await import("@sema-lang/sema-wasm");
31
+ _init = mod.default;
32
+ _SemaInterpreter = mod.SemaInterpreter;
33
+ if (wasmUrl) {
34
+ await _init(wasmUrl);
35
+ }
36
+ else {
37
+ await _init();
38
+ }
39
+ _initialized = true;
40
+ })();
41
+ await _initPromise;
42
+ }
43
+ /**
44
+ * A Sema Lisp interpreter instance.
45
+ *
46
+ * Each interpreter has its own isolated environment — variables defined in one
47
+ * interpreter are not visible in another.
48
+ *
49
+ * @example
50
+ * ```js
51
+ * const sema = await SemaInterpreter.create();
52
+ *
53
+ * // Evaluate expressions
54
+ * sema.evalStr("(define x 42)");
55
+ * const r = sema.evalStr("(* x x)");
56
+ * console.log(r.value); // "1764"
57
+ *
58
+ * // Register JS functions
59
+ * sema.registerFunction("greet", (name) => `Hello, ${name}!`);
60
+ * sema.evalStr('(greet "world")'); // => "Hello, world!"
61
+ *
62
+ * // Preload modules
63
+ * sema.preloadModule("utils", "(define (double x) (* x 2))");
64
+ * sema.evalStr('(import "utils")');
65
+ * sema.evalStr("(double 21)"); // => "42"
66
+ * ```
67
+ */
68
+ export class SemaInterpreter {
69
+ constructor(inner, vfsBackend = null) {
70
+ this._inner = inner;
71
+ this._vfsBackend = vfsBackend;
72
+ }
73
+ /**
74
+ * Create a new SemaInterpreter instance.
75
+ *
76
+ * This initializes the WASM module (once, globally) and creates an interpreter.
77
+ * The WASM module is cached — subsequent calls are fast.
78
+ *
79
+ * @param opts - Configuration options
80
+ * @returns A ready-to-use SemaInterpreter
81
+ *
82
+ * @example
83
+ * ```js
84
+ * // Default: full standard library
85
+ * const sema = await SemaInterpreter.create();
86
+ *
87
+ * // Minimal: only special forms
88
+ * const minimal = await SemaInterpreter.create({ stdlib: false });
89
+ *
90
+ * // From CDN
91
+ * const cdn = await SemaInterpreter.create({
92
+ * wasmUrl: "https://cdn.jsdelivr.net/npm/@sema-lang/sema-wasm@1.9.0/sema_wasm_bg.wasm"
93
+ * });
94
+ * ```
95
+ */
96
+ static async create(opts) {
97
+ await ensureInit(opts?.wasmUrl);
98
+ const needsOptions = opts?.stdlib === false || (opts?.deny && opts.deny.length > 0);
99
+ let inner;
100
+ if (needsOptions) {
101
+ inner = _SemaInterpreter.createWithOptions({
102
+ stdlib: opts?.stdlib ?? true,
103
+ deny: opts?.deny,
104
+ });
105
+ }
106
+ else {
107
+ inner = new _SemaInterpreter();
108
+ }
109
+ const interp = new SemaInterpreter(inner, opts?.vfs ?? null);
110
+ if (interp._vfsBackend) {
111
+ await interp._vfsBackend.init?.();
112
+ await interp._vfsBackend.hydrate(interp._vfsHost());
113
+ }
114
+ return interp;
115
+ }
116
+ _vfsHost() {
117
+ return {
118
+ readFile: (p) => this.readFile(p),
119
+ writeFile: (p, c) => this.writeFile(p, c),
120
+ deleteFile: (p) => this.deleteFile(p),
121
+ mkdir: (p) => this.mkdir(p),
122
+ listFiles: (d) => this.listFiles(d),
123
+ fileExists: (p) => this.fileExists(p),
124
+ isDirectory: (p) => this.isDirectory(p),
125
+ resetVFS: () => this.resetVFS(),
126
+ };
127
+ }
128
+ /**
129
+ * Evaluate a string of Sema code.
130
+ *
131
+ * Definitions persist across calls — you can `define` a function in one call
132
+ * and use it in the next.
133
+ *
134
+ * @param code - Sema source code to evaluate
135
+ * @returns The evaluation result
136
+ *
137
+ * @example
138
+ * ```js
139
+ * const r = sema.evalStr("(map (lambda (x) (* x x)) '(1 2 3 4 5))");
140
+ * console.log(r.value); // "(1 4 9 16 25)"
141
+ * console.log(r.output); // [] (no print statements)
142
+ * console.log(r.error); // null (no error)
143
+ * ```
144
+ */
145
+ evalStr(code) {
146
+ return this._inner.evalGlobal(code);
147
+ }
148
+ /**
149
+ * Evaluate code with async HTTP support.
150
+ *
151
+ * Use this when your Sema code uses `http/get` or other network functions.
152
+ * The interpreter will automatically handle the async fetch operations.
153
+ *
154
+ * @param code - Sema source code to evaluate
155
+ * @returns The evaluation result
156
+ *
157
+ * @example
158
+ * ```js
159
+ * const r = await sema.evalStrAsync('(http/get "https://api.example.com/data")');
160
+ * ```
161
+ */
162
+ async evalStrAsync(code) {
163
+ return (await this._inner.evalAsync(code));
164
+ }
165
+ /**
166
+ * Register a JavaScript function that can be called from Sema code.
167
+ *
168
+ * Arguments are passed as native JavaScript values (numbers, strings,
169
+ * booleans, null, arrays, objects). The return value is converted back
170
+ * to a Sema value.
171
+ *
172
+ * @param name - The function name in Sema (e.g., "my-fn")
173
+ * @param fn - The JavaScript function to call
174
+ *
175
+ * @example
176
+ * ```js
177
+ * // Simple function — args are native JS values
178
+ * sema.registerFunction("add1", (n) => n + 1);
179
+ *
180
+ * // Multiple args
181
+ * sema.registerFunction("greet", (greeting, name) => `${greeting}, ${name}!`);
182
+ *
183
+ * // Returning structured data (objects become Sema maps)
184
+ * sema.registerFunction("get-user", (id) => ({ name: "Alice", age: 30 }));
185
+ * ```
186
+ */
187
+ registerFunction(name, fn) {
188
+ this._inner.registerFunction(name, fn);
189
+ }
190
+ /**
191
+ * Preload a virtual module so that `(import "name")` works without a file.
192
+ *
193
+ * @param name - The module name (used in `(import "name")`)
194
+ * @param source - Sema source code defining the module's exports
195
+ * @throws If the module source has syntax or evaluation errors
196
+ *
197
+ * @example
198
+ * ```js
199
+ * sema.preloadModule("utils", `
200
+ * (define (double x) (* x 2))
201
+ * (define pi 3.14159)
202
+ * `);
203
+ *
204
+ * sema.evalStr('(import "utils")');
205
+ * sema.evalStr("(double pi)"); // => "6.28318"
206
+ * ```
207
+ */
208
+ preloadModule(name, source) {
209
+ const result = this._inner.preloadModule(name, source);
210
+ if (!result.ok) {
211
+ throw new Error(`Failed to preload module "${name}": ${result.error}`);
212
+ }
213
+ }
214
+ /**
215
+ * Read a file from the virtual filesystem.
216
+ * @returns The file contents, or null if the file doesn't exist.
217
+ */
218
+ readFile(path) {
219
+ const result = this._inner.readFile(path);
220
+ return result === null || result === undefined ? null : result;
221
+ }
222
+ /**
223
+ * Write a file to the virtual filesystem.
224
+ * Quotas: 1 MB per file, 16 MB total, 256 files max.
225
+ * @throws If a VFS quota is exceeded.
226
+ */
227
+ writeFile(path, content) {
228
+ const error = this._inner.writeFile(path, content);
229
+ if (typeof error === "string") {
230
+ throw new Error(error);
231
+ }
232
+ }
233
+ /**
234
+ * Delete a file from the virtual filesystem.
235
+ * @returns true if the file existed and was deleted.
236
+ */
237
+ deleteFile(path) {
238
+ return this._inner.deleteFile(path);
239
+ }
240
+ /**
241
+ * List entries in a VFS directory.
242
+ * @returns Array of file and directory names (not full paths).
243
+ */
244
+ listFiles(dir) {
245
+ return Array.from(this._inner.listFiles(dir ?? "/"));
246
+ }
247
+ /**
248
+ * Check if a path exists in the VFS (file or directory).
249
+ */
250
+ fileExists(path) {
251
+ return this._inner.fileExists(path);
252
+ }
253
+ /**
254
+ * Create a directory (and parent directories) in the VFS.
255
+ */
256
+ mkdir(path) {
257
+ this._inner.mkdir(path);
258
+ }
259
+ /**
260
+ * Check if a path is a directory in the VFS.
261
+ */
262
+ isDirectory(path) {
263
+ return this._inner.isDirectory(path);
264
+ }
265
+ /**
266
+ * Get VFS usage statistics (file count, bytes used, quotas).
267
+ */
268
+ vfsStats() {
269
+ return this._inner.vfsStats();
270
+ }
271
+ /**
272
+ * Clear all files and directories from the VFS.
273
+ */
274
+ resetVFS() {
275
+ this._inner.resetVFS();
276
+ }
277
+ /**
278
+ * Persist VFS changes to the configured backend.
279
+ *
280
+ * No-op if no VFS backend was provided during creation.
281
+ * Call this after eval to save files.
282
+ *
283
+ * @example
284
+ * ```js
285
+ * await sema.evalStrAsync(code);
286
+ * await sema.flushVFS(); // persist to localStorage/IndexedDB/etc.
287
+ * ```
288
+ */
289
+ async flushVFS() {
290
+ if (this._vfsBackend) {
291
+ await this._vfsBackend.flush(this._vfsHost());
292
+ }
293
+ }
294
+ /**
295
+ * Clear the VFS and the persistent backend (if configured).
296
+ */
297
+ async resetVFSAndBackend() {
298
+ this._inner.resetVFS();
299
+ await this._vfsBackend?.reset?.();
300
+ }
301
+ /**
302
+ * Get the Sema interpreter version.
303
+ *
304
+ * @returns Version string (e.g., "1.9.0")
305
+ */
306
+ version() {
307
+ return this._inner.version();
308
+ }
309
+ /**
310
+ * Free the interpreter's WASM memory.
311
+ *
312
+ * Call this when you're done with the interpreter to release resources.
313
+ * The interpreter cannot be used after calling this method.
314
+ */
315
+ dispose() {
316
+ this._inner.free();
317
+ }
318
+ }
319
+ export { MemoryBackend } from "./backends/memory.js";
320
+ export { LocalStorageBackend } from "./backends/local-storage.js";
321
+ export { SessionStorageBackend } from "./backends/session-storage.js";
322
+ export { IndexedDBBackend } from "./backends/indexed-db.js";
323
+ /** @deprecated Use `SemaInterpreter` instead. */
324
+ export { SemaInterpreter as Interpreter };
package/dist/vfs.d.ts ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Host bridge — methods the backend calls to read/write the in-memory WASM VFS.
3
+ * Provided by SemaInterpreter, not implemented by users.
4
+ */
5
+ export interface VFSHost {
6
+ readFile(path: string): string | null;
7
+ writeFile(path: string, content: string): void;
8
+ deleteFile(path: string): boolean;
9
+ mkdir(path: string): void;
10
+ listFiles(dir: string): string[];
11
+ fileExists(path: string): boolean;
12
+ isDirectory(path: string): boolean;
13
+ resetVFS(): void;
14
+ }
15
+ /**
16
+ * Pluggable VFS storage backend.
17
+ *
18
+ * Implement this interface to persist VFS state across page reloads.
19
+ * The backend runs outside the eval loop, so async is allowed.
20
+ *
21
+ * Built-in implementations:
22
+ * - {@link MemoryBackend} — ephemeral, no persistence
23
+ * - {@link LocalStorageBackend} — persist to localStorage (~5 MB limit)
24
+ * - {@link SessionStorageBackend} — persist within the tab session
25
+ * - {@link IndexedDBBackend} — persist to IndexedDB (recommended for production)
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { SemaInterpreter, IndexedDBBackend } from "@sema-lang/sema";
30
+ *
31
+ * const sema = await SemaInterpreter.create({
32
+ * vfs: new IndexedDBBackend({ namespace: "my-app" }),
33
+ * });
34
+ * await sema.evalStrAsync(code);
35
+ * await sema.flushVFS(); // persist changes
36
+ * ```
37
+ */
38
+ export interface VFSBackend {
39
+ /** Optional: open DB connections, request permissions, etc. */
40
+ init?(): Promise<void>;
41
+ /**
42
+ * Populate the in-memory WASM VFS from persistent storage.
43
+ * Called once during `SemaInterpreter.create()`.
44
+ */
45
+ hydrate(host: VFSHost): Promise<void>;
46
+ /**
47
+ * Persist current in-memory VFS state to storage.
48
+ * Called explicitly via `sema.flushVFS()`.
49
+ */
50
+ flush(host: VFSHost): Promise<void>;
51
+ /** Optional: clear all persistent data. */
52
+ reset?(): Promise<void>;
53
+ }
package/dist/vfs.js ADDED
@@ -0,0 +1 @@
1
+ export {};