{"id":30067098,"url":"https://github.com/fluttercandies/fjs","last_synced_at":"2026-03-16T06:24:04.683Z","repository":{"id":308314309,"uuid":"932635075","full_name":"fluttercandies/fjs","owner":"fluttercandies","description":"A high-performance JavaScript runtime for Flutter applications, built with Rust and powered by QuickJS.","archived":false,"fork":false,"pushed_at":"2026-01-21T07:57:11.000Z","size":3303,"stargazers_count":61,"open_issues_count":0,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-21T18:58:33.688Z","etag":null,"topics":["flutter","flutter-js","js-engine","js-runtime","quickjs","rust"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/fjs","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluttercandies.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-14T08:40:29.000Z","updated_at":"2026-01-21T08:08:08.000Z","dependencies_parsed_at":"2025-10-25T16:12:19.084Z","dependency_job_id":null,"html_url":"https://github.com/fluttercandies/fjs","commit_stats":null,"previous_names":["fluttercandies/fjs"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/fluttercandies/fjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluttercandies","download_url":"https://codeload.github.com/fluttercandies/fjs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffjs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28846765,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T15:15:36.453Z","status":"ssl_error","status_checked_at":"2026-01-28T15:15:13.020Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","flutter-js","js-engine","js-runtime","quickjs","rust"],"created_at":"2025-08-08T08:07:40.367Z","updated_at":"2026-03-16T06:24:04.671Z","avatar_url":"https://github.com/fluttercandies.png","language":"Dart","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"fjs.png\" alt=\"FJS Logo\" width=\"240\"\u003e\n\n  # 🚀 FJS - Flutter JavaScript Engine\n\n  High-performance JavaScript runtime for Flutter ⚡\n  Built with Rust and powered by QuickJS 🦀\n\n  [![pub package](https://img.shields.io/pub/v/fjs.svg)](https://pub.dev/packages/fjs)\n  [![GitHub stars](https://img.shields.io/github/stars/fluttercandies/fjs.svg?style=flat\u0026logo=github\u0026colorB=deeppink\u0026label=stars)](https://github.com/fluttercandies/fjs)\n  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/fluttercandies/fjs/blob/main/LICENSE)\n\n  *[🌏 中文文档](README_zh.md)*\n\u003c/div\u003e\n\n## ✨ Why FJS?\n\n- **High Performance** - Rust-powered, optimized for mobile platforms\n- **ES6 Modules** - Full support for import/export syntax\n- **Async/Await** - Native async JavaScript execution\n- **Type Safe** - Strongly typed Dart API with sealed classes\n- **Bridge Communication** - Bidirectional Dart-JS communication\n- **Cross Platform** - Android, iOS, Linux, macOS, Windows\n- **Memory Safe** - Built-in GC with configurable limits\n\n## 🎯 Real-world Usage\n\n**[Mikan Flutter](https://github.com/iota9star/mikan_flutter)** - A Flutter client for [Mikan Project](https://mikanani.me), an anime subscription and management platform. FJS powers its core JavaScript execution engine.\n\n## 📦 Installation\n\n```yaml\ndependencies:\n  fjs: any\n```\n\n## 🚀 Quick Start\n\n```dart\nimport 'package:fjs/fjs.dart';\n\nvoid main() async {\n  await LibFjs.init();\n\n  // Create runtime with builtin modules\n  final runtime = await JsAsyncRuntime.withOptions(\n    builtin: JsBuiltinOptions(\n      console: true,\n      fetch: true,\n      timers: true,\n    ),\n  );\n\n  // Create context\n  final context = await JsAsyncContext.from(runtime: runtime);\n\n  // Create engine\n  final engine = JsEngine(context: context);\n  await engine.init(bridge: (jsValue) {\n    return JsResult.ok(JsValue.string('Hello from Dart'));\n  });\n\n  // Execute JavaScript\n  final result = await engine.eval(source: JsCode.code('''\n    console.log('Hello from FJS!');\n    1 + 2\n  '''));\n  print(result.value); // 3\n\n  await engine.dispose();\n}\n```\n\n## 🏗️ Runtime \u0026 Context APIs\n\n```dart\n// Create an async runtime with web-style builtins and one extra ES module.\nfinal runtime = await JsAsyncRuntime.withOptions(\n  builtin: JsBuiltinOptions.web(),\n  additional: [\n    JsModule.code(\n      module: 'app/math',\n      code: 'export function add(a, b) { return a + b; }',\n    ),\n  ],\n);\n\n// Apply runtime-level safety and diagnostic limits.\nawait runtime.setInfo(info: 'main-runtime');\nawait runtime.setMemoryLimit(limit: BigInt.from(64 * 1024 * 1024));\nawait runtime.setGcThreshold(threshold: BigInt.from(8 * 1024 * 1024));\nawait runtime.setMaxStackSize(limit: BigInt.from(512 * 1024));\n\n// Create a context from that runtime.\nfinal context = await JsAsyncContext.from(runtime: runtime);\n\n// Evaluate a simple expression and read the structured JsResult.\nfinal evalResult = await context.eval(code: '21 + 21');\nprint(evalResult.ok.value); // 42\n\n// Enable top-level await / Promise handling explicitly.\nfinal asyncResult = await context.evalWithOptions(\n  code: 'await Promise.resolve(40 + 2)',\n  options: JsEvalOptions.withPromise(),\n);\nprint(asyncResult.ok.value); // 42\n\n// Load code from disk.\nfinal fileResult = await context.evalFile(path: '/absolute/path/to/script.js');\nfinal strictFileResult = await context.evalFileWithOptions(\n  path: '/absolute/path/to/script.js',\n  options: JsEvalOptions.defaults(),\n);\n\n// Call an exported function from a module that is already available in the runtime.\nfinal functionResult = await context.evalFunction(\n  module: 'app/math',\n  method: 'add',\n  params: [JsValue.integer(2), JsValue.integer(3)],\n);\nprint(functionResult.ok.value); // 5\n\n// Inspect which modules the context can currently import.\nfinal availableModules = await context.getAvailableModules();\nprint(availableModules);\n\n// Advance or fully drain pending async work when you need explicit control.\nif (await runtime.isJobPending()) {\n  await runtime.executePendingJob();\n}\nawait runtime.idle();\n```\n\nLow-level context APIs return `JsResult`, which is useful when you want structured success or error handling instead of exceptions.\n\n### Synchronous Runtime \u0026 Context\n\n```dart\n// Build a synchronous runtime when you do not need async JavaScript execution.\nfinal runtime = await JsRuntime.withOptions(\n  builtin: JsBuiltinOptions.essential(),\n);\nfinal context = JsContext.from(runtime: runtime);\n\n// Sync contexts return JsResult directly.\nfinal result = context.eval(code: '6 * 7');\nprint(result.ok.value); // 42\n\n// Apply eval flags such as strict mode.\nfinal strictResult = context.evalWithOptions(\n  code: '\"use strict\"; 8 * 8',\n  options: JsEvalOptions.defaults(),\n);\nprint(strictResult.ok.value); // 64\n\n// File-based sync evaluation uses the same JsResult shape.\nfinal fileResult = context.evalFile(path: '/absolute/path/to/script.js');\nfinal fileWithOptions = context.evalFileWithOptions(\n  path: '/absolute/path/to/script.js',\n  options: JsEvalOptions.defaults(),\n);\n\n// Introspect the modules visible to this context.\nfinal modules = context.getAvailableModules();\nprint(modules);\n\n// Pump the QuickJS job queue manually in sync mode.\nwhile (runtime.isJobPending()) {\n  runtime.executePendingJob();\n}\n\n// Configure runtime limits and collect memory statistics.\nruntime.setMemoryLimit(limit: BigInt.from(32 * 1024 * 1024));\nruntime.setGcThreshold(threshold: BigInt.from(4 * 1024 * 1024));\nruntime.setMaxStackSize(limit: BigInt.from(256 * 1024));\nruntime.setInfo(info: 'sync-runtime');\nprint(runtime.memoryUsage().summary());\nruntime.runGc();\n```\n\n## 🧱 Source Inputs \u0026 Eval Options\n\n```dart\nimport 'dart:convert';\nimport 'dart:typed_data';\n\n// Source code can come from a string, a file path, or UTF-8 bytes.\nfinal inlineCode = JsCode.code('1 + 1');\nfinal fileCode = JsCode.path('/absolute/path/to/script.js');\nfinal bytesCode = JsCode.bytes(Uint8List.fromList(utf8.encode('2 + 2')));\n\n// Modules support the same three source forms.\nfinal inlineModule = JsModule.code(\n  module: 'feature/inline',\n  code: 'export const enabled = true;',\n);\nfinal fileModule = JsModule.path(\n  module: 'feature/file',\n  path: '/absolute/path/to/feature.js',\n);\nfinal bytesModule = JsModule.bytes(\n  module: 'feature/bytes',\n  bytes: utf8.encode('export const answer = 42;'),\n);\n\n// Eval options control whether code runs as global script, async code, or module-style code.\nfinal defaultEval = JsEvalOptions.defaults();\nfinal asyncEval = JsEvalOptions.withPromise();\nfinal moduleEval = JsEvalOptions.module();\n```\n\n## 📦 ES6 Modules\n\n```dart\n// Declare modules\nawait engine.declareNewModule(\n  module: JsModule.code(module: 'math', code: '''\n    export const add = (a, b) =\u003e a + b;\n    export const multiply = (a, b) =\u003e a * b;\n  '''),\n);\n\n// Use modules\nawait engine.eval(source: JsCode.code('''\n  const { add, multiply } = await import('math');\n  console.log(add(2, 3));        // 5\n  console.log(multiply(4, 5));   // 20\n'''));\n\n// Or call an exported function directly without writing an import wrapper yourself.\nfinal sum = await engine.call(\n  module: 'math',\n  method: 'add',\n  params: [JsValue.integer(2), JsValue.integer(3)],\n);\nprint(sum.value); // 5\n\n// Batch-register multiple modules in one request.\nawait engine.declareNewModules(modules: [\n  JsModule.code(\n    module: 'numbers/double',\n    code: 'export const double = (value) =\u003e value * 2;',\n  ),\n  JsModule.code(\n    module: 'numbers/triple',\n    code: 'export const triple = (value) =\u003e value * 3;',\n  ),\n]);\n\n// Execute a module immediately and leave it cached in the current context.\nawait engine.evaluateModule(\n  module: JsModule.code(\n    module: 'startup',\n    code: 'globalThis.started = true; export default \"ready\";',\n  ),\n);\n\n// Inspect the dynamic modules declared on this engine.\nfinal declaredModules = await engine.getDeclaredModules();\nfinal hasMath = await engine.isModuleDeclared(moduleName: 'math');\nprint(declaredModules);\nprint(hasMath); // true\n```\n\nDynamic modules can be cleared only before they are loaded. After a module has been imported or evaluated in a context, recreate the context to replace it.\n\n## 📚 Module Inventory\n\n```dart\nfinal modules = await engine.getAvailableModules();\nprint(modules);\n\nfinal hasConsole = await engine.isModuleAvailable(moduleName: 'console');\nfinal hasXml = await engine.isModuleAvailable(moduleName: 'llrt:xml');\nprint('console: $hasConsole, llrt:xml: $hasXml');\n```\n\n## 🔄 Engine Lifecycle Notes\n\n- `JsEngine` wraps an existing `JsAsyncContext`; disposing the engine does not dispose the underlying context or runtime\n- `dispose()` detaches the `fjs` bridge object, drains pending runtime work, and then runs GC before the engine becomes unusable\n- `clearPendingModules()` only removes dynamic modules that have not been loaded into the current context yet\n- `declareNewModules()` and `declareNewBytecodeModules()` reject duplicate module names in a single request\n\n## 📦 Module Bytecode\n\n```dart\n// Compile an ES module into QuickJS bytecode without touching the current engine.\nfinal bytecode = await JsBytecode.compile(\n  module: JsModule.code(\n    module: 'plugin/main.js',\n    code: 'export function run() { return \"ready\"; }',\n  ),\n  options: JsModuleBytecodeOptions.defaults(),\n);\n\n// Validate the bytecode payload before declaring it.\nawait JsBytecode.validate(module: bytecode);\n\n// Register the precompiled module on the engine.\nawait engine.declareNewBytecodeModule(module: bytecode);\n\n// Import and execute the declared module like any other ES module.\nfinal result = await engine.eval(source: JsCode.code('''\n  const { run } = await import('plugin/main.js');\n  run();\n'''));\n\n// Reconstruct bytecode from persisted bytes when loading from storage.\nfinal restored = JsModuleBytecode(\n  name: bytecode.name,\n  bytes: bytecode.bytes,\n);\nJsBytecode.validateSync(module: restored);\n```\n\n`JsBytecode.compile()` runs in an isolated QuickJS context, so compiling does not declare or cache the module inside the current engine. `JsBytecode.validate()` only checks structural validity and embedded module name; it does not execute the module. `compileSync()` / `validateSync()` are also available for synchronous callers, but the async variants are safer on the main isolate.\n\nQuickJS bytecode is version-specific and must be treated as trusted input. Recompile bytecode whenever the embedded QuickJS version changes.\n\n### Bytecode Bundles\n\n```dart\n// Compile a full module graph into one distributable bundle.\nfinal bundle = await JsBytecode.compileModuleBundle(\n  entry: 'plugins/main.js',\n  modules: [\n    JsModule.code(\n      module: 'plugins/deps/math.js',\n      code: 'export const double = (value) =\u003e value * 2;',\n    ),\n    JsModule.code(\n      module: 'plugins/main.js',\n      code: '''\n        import { double } from './deps/math.js';\n        export default { ready: true, answer: double(21) };\n      ''',\n    ),\n  ],\n);\n\n// Validate the bundle structure before loading it.\nawait JsBytecode.validateBundle(bundle: bundle);\n\n// Execute the bundle entry and cache the involved modules.\nawait engine.evaluateBytecodeBundle(bundle: bundle);\n\n// Read exports by importing the entry module afterwards.\nfinal result = await engine.eval(source: JsCode.code('''\n  const { default: plugin } = await import('plugins/main.js');\n  plugin\n'''));\nprint(result.value); // { ready: true, answer: 42 }\n```\n\nBundles are useful when a plugin ships as a module graph instead of a single file. Relative imports are preserved inside the compiled bundle, and `declareNewBytecodeBundle()` is available when you want to register the bundle without executing its entry yet. `validateBundle()` is structural: it checks entry presence, duplicate names, and that each payload is readable by the embedded QuickJS version. `evaluateBytecodeBundle()` executes the entry and populates the module cache; import the entry afterwards to read its exports.\n\n### Classic Script Bytecode\n\n```dart\n// Compile classic script source into non-module bytecode.\nfinal script = await JsBytecode.compileScript(\n  name: 'startup.js',\n  source: JsCode.code('''\n    await Promise.resolve();\n    globalThis.launchCount = (globalThis.launchCount ?? 0) + 1;\n    ({ mode: 'script', launchCount: globalThis.launchCount })\n  '''),\n  options: const JsScriptBytecodeOptions(\n    promise: true,\n    strict: true,\n    stripSource: true,\n    stripDebug: true,\n    endianness: JsBytecodeEndianness.little,\n  ),\n);\n\n// Validate before evaluation.\nawait JsBytecode.validateScript(script: script);\n\n// Execute the script bytecode and read its completion value.\nfinal result = await engine.evaluateScriptBytecode(script: script);\nprint(result.value); // { mode: 'script', launchCount: 1 }\n```\n\nScript bytecode is the non-module counterpart to ES module bytecode. `validateScript()` is structural only: it ensures the bytes decode as executable non-module bytecode under the embedded QuickJS version. QuickJS does not expose an embedded script name to verify at load time, so the `name` acts as compile-time metadata and the source filename shown in stack traces.\n\n## 🧾 Values, Results, and Errors\n\n```dart\nimport 'dart:typed_data';\nimport 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';\n\n// Convert common Dart values into structured JsValue instances automatically.\nfinal payload = JsValue.from({\n  'enabled': true,\n  'count': 3,\n  'tags': ['a', 'b'],\n  'buffer': Uint8List.fromList([1, 2, 3]),\n});\nprint(payload.typeName()); // Object\nprint(payload.value); // Dart Map\u003cString, dynamic\u003e\n\n// Or build typed JsValue trees yourself when you need exact control.\nfinal typed = JsValue.object({\n  'big': JsValue.bigint('9007199254740993'),\n  'createdAt': JsValue.date(DateTime.now().millisecondsSinceEpoch),\n});\nprint(typed.value);\n\n// Low-level context APIs return JsResult instead of throwing.\nfinal result = await context.eval(code: '40 + 2');\nif (result.isOk) {\n  print(result.ok.value); // 42\n} else {\n  print('${result.err.code()}: ${result.err}');\n}\n\n// JsError values are useful for structured error handling and retry decisions.\nconst syntaxError = JsError.syntax(\n  message: 'Unexpected token',\n  line: 1,\n  column: 10,\n);\nprint(syntaxError.code());\nprint(syntaxError.isRecoverable());\n\n// High-level execution APIs still throw AnyhowException on failure.\ntry {\n  await engine.eval(source: JsCode.code('invalid.code()'));\n} on AnyhowException catch (e) {\n  print('Execution failed: ${e.message}');\n}\n```\n\n`JsError` is returned inside `JsResult.err(...)` for structured bridge and low-level context results. Public execution APIs like `eval()` and `call()` currently surface Rust-side failures as `AnyhowException`.\n\n## 🌉 Bridge Communication\n\n```dart\n// The bridge receives a JsValue and returns a JsResult back to JavaScript.\nawait engine.init(bridge: (jsValue) async {\n  final data = jsValue.value;\n\n  if (data is Map \u0026\u0026 data['action'] == 'fetchUser') {\n    final user = await fetchUser(data['id']);\n    return JsResult.ok(JsValue.from(user));\n  }\n\n  return JsResult.ok(JsValue.none());\n});\n\n// In JavaScript, call back into Dart through the injected fjs object.\nawait engine.eval(source: JsCode.code('''\n  const user = await fjs.bridge_call({ action: 'fetchUser', id: 123 });\n  console.log(user);\n'''));\n```\n\n## 🧠 Memory Management\n\n```dart\n// Set runtime safety limits.\nawait runtime.setMemoryLimit(limit: BigInt.from(50 * 1024 * 1024)); // 50MB\nawait runtime.setGcThreshold(threshold: BigInt.from(10 * 1024 * 1024)); // 10MB\nawait runtime.setMaxStackSize(limit: BigInt.from(512 * 1024)); // 512KB\n\n// Inspect current memory usage.\nfinal usage = await runtime.memoryUsage();\nprint(usage.summary());\n\n// Force a garbage collection pass when you need immediate cleanup.\nawait runtime.runGc();\n```\n\n## 📚 Core API\n\n### JsAsyncRuntime \u0026 JsAsyncContext\n\n```dart\nabstract class JsAsyncRuntime {\n  factory JsAsyncRuntime();\n  static Future\u003cJsAsyncRuntime\u003e withOptions({\n    JsBuiltinOptions? builtin,\n    List\u003cJsModule\u003e? additional,\n  });\n\n  Future\u003cbool\u003e isJobPending();\n  Future\u003cbool\u003e executePendingJob();\n  Future\u003cvoid\u003e idle();\n  Future\u003cMemoryUsage\u003e memoryUsage();\n  Future\u003cvoid\u003e setMemoryLimit({required BigInt limit});\n  Future\u003cvoid\u003e setGcThreshold({required BigInt threshold});\n  Future\u003cvoid\u003e setMaxStackSize({required BigInt limit});\n  Future\u003cvoid\u003e setInfo({required String info});\n  Future\u003cvoid\u003e runGc();\n}\n\nabstract class JsAsyncContext {\n  static Future\u003cJsAsyncContext\u003e from({required JsAsyncRuntime runtime});\n\n  Future\u003cJsResult\u003e eval({required String code});\n  Future\u003cJsResult\u003e evalWithOptions({required String code, required JsEvalOptions options});\n  Future\u003cJsResult\u003e evalFile({required String path});\n  Future\u003cJsResult\u003e evalFileWithOptions({required String path, required JsEvalOptions options});\n  Future\u003cJsResult\u003e evalFunction({\n    required String module,\n    required String method,\n    List\u003cJsValue\u003e? params,\n  });\n\n  Future\u003cList\u003cString\u003e\u003e getAvailableModules();\n}\n```\n\n### JsRuntime \u0026 JsContext\n\n```dart\nabstract class JsRuntime {\n  factory JsRuntime();\n  static Future\u003cJsRuntime\u003e withOptions({\n    JsBuiltinOptions? builtin,\n    List\u003cJsModule\u003e? additional,\n  });\n\n  bool isJobPending();\n  bool executePendingJob();\n  MemoryUsage memoryUsage();\n  void setMemoryLimit({required BigInt limit});\n  void setGcThreshold({required BigInt threshold});\n  void setMaxStackSize({required BigInt limit});\n  void setInfo({required String info});\n  void runGc();\n}\n\nabstract class JsContext {\n  static JsContext from({required JsRuntime runtime});\n\n  JsResult eval({required String code});\n  JsResult evalWithOptions({required String code, required JsEvalOptions options});\n  JsResult evalFile({required String path});\n  JsResult evalFileWithOptions({required String path, required JsEvalOptions options});\n  List\u003cString\u003e getAvailableModules();\n}\n```\n\n### JsEngine\n\n```dart\nclass JsEngine {\n  factory JsEngine({required JsAsyncContext context});\n\n  Future\u003cvoid\u003e init({required FutureOr\u003cJsResult\u003e Function(JsValue) bridge});\n  Future\u003cvoid\u003e initWithoutBridge();\n  Future\u003cJsValue\u003e eval({required JsCode source, JsEvalOptions? options});\n  Future\u003cJsValue\u003e call({required String module, required String method, List\u003cJsValue\u003e? params});\n\n  Future\u003cvoid\u003e declareNewModule({required JsModule module});\n  Future\u003cvoid\u003e declareNewModules({required List\u003cJsModule\u003e modules}); // rejects duplicate names in one request\n  Future\u003cvoid\u003e declareNewBytecodeBundle({required JsModuleBytecodeBundle bundle});\n  Future\u003cvoid\u003e declareNewBytecodeModule({required JsModuleBytecode module});\n  Future\u003cvoid\u003e declareNewBytecodeModules({required List\u003cJsModuleBytecode\u003e modules}); // rejects duplicate names in one request\n  Future\u003cvoid\u003e clearPendingModules();\n  Future\u003cList\u003cString\u003e\u003e getAvailableModules();\n  Future\u003cbool\u003e isModuleDeclared({required String moduleName});\n  Future\u003cbool\u003e isModuleAvailable({required String moduleName});\n  Future\u003cList\u003cString\u003e\u003e getDeclaredModules();\n  Future\u003cJsValue\u003e evaluateBytecodeBundle({required JsModuleBytecodeBundle bundle});\n  Future\u003cJsValue\u003e evaluateModule({required JsModule module});\n  Future\u003cJsValue\u003e evaluateBytecodeModule({required JsModuleBytecode module});\n  Future\u003cJsValue\u003e evaluateScriptBytecode({required JsScriptBytecode script});\n\n  Future\u003cvoid\u003e dispose(); // drains pending runtime work, then runs GC\n  bool get running;\n  bool get disposed;\n  JsAsyncContext get context; // engine does not own the returned context\n}\n```\n\n### MemoryUsage\n\n```dart\nabstract class MemoryUsage {\n  int get totalMemory;\n  int get totalAllocations;\n  int get mallocSize;\n  int get objCount;\n  int get strCount;\n  String summary();\n}\n```\n\n### JsValue\n\n```dart\nsealed class JsValue {\n  const factory JsValue.none();\n  const factory JsValue.boolean(bool value);\n  const factory JsValue.integer(PlatformInt64 value);\n  const factory JsValue.float(double value);\n  const factory JsValue.bigint(String value);\n  const factory JsValue.string(String value);\n  const factory JsValue.bytes(Uint8List value);\n  const factory JsValue.array(List\u003cJsValue\u003e value);\n  const factory JsValue.object(Map\u003cString, JsValue\u003e value);\n  const factory JsValue.date(PlatformInt64 value);\n  const factory JsValue.symbol(String value);\n  const factory JsValue.function(String value);\n\n  static JsValue from(Object? any);\n  String typeName();\n  dynamic get value;\n}\n```\n\n### JsBuiltinOptions \u0026 JsEvalOptions\n\n```dart\nsealed class JsBuiltinOptions {\n  const factory JsBuiltinOptions({\n    bool? console,\n    bool? fetch,\n    bool? timers,\n    bool? crypto,\n    bool? fs,\n    bool? url,\n    bool? process,\n    bool? path,\n    bool? util,\n    bool? intl,\n    bool? temporal,\n    // ... other builtin toggles\n  });\n\n  static JsBuiltinOptions none();\n  static JsBuiltinOptions essential();\n  static JsBuiltinOptions web();\n  static JsBuiltinOptions node();\n  static JsBuiltinOptions all();\n}\n\nsealed class JsEvalOptions {\n  factory JsEvalOptions({\n    bool? global,\n    bool? strict,\n    bool? backtraceBarrier,\n    bool? promise,\n  });\n\n  static JsEvalOptions defaults();\n  static JsEvalOptions withPromise();\n  static JsEvalOptions module();\n}\n```\n\n### JsCode, JsModule, and Bytecode\n\n```dart\nsealed class JsCode {\n  const factory JsCode.code(String value);    // Inline code\n  const factory JsCode.path(String value);    // File path\n  const factory JsCode.bytes(Uint8List value); // Raw UTF-8 source bytes\n}\n\nsealed class JsModule {\n  static JsModule code({required String module, required String code});\n  static JsModule path({required String module, required String path});\n  static JsModule bytes({required String module, required List\u003cint\u003e bytes}); // UTF-8 source bytes\n}\n\nsealed class JsModuleBytecode {\n  factory JsModuleBytecode({required String name, required List\u003cint\u003e bytes});\n}\n\nsealed class JsModuleBytecodeBundle {\n  factory JsModuleBytecodeBundle({\n    String? entry,\n    required List\u003cJsModuleBytecode\u003e modules,\n  });\n}\n\nsealed class JsScriptBytecode {\n  factory JsScriptBytecode({required String name, required List\u003cint\u003e bytes});\n}\n\nclass JsBytecode {\n  static JsModuleBytecode compileSync({\n    required JsModule module,\n    JsModuleBytecodeOptions? options,\n  });\n\n  static Future\u003cJsModuleBytecode\u003e compile({\n    required JsModule module,\n    JsModuleBytecodeOptions? options,\n  });\n\n  static JsModuleBytecodeBundle compileModuleBundleSync({\n    required List\u003cJsModule\u003e modules,\n    String? entry,\n    JsModuleBytecodeOptions? options,\n  });\n\n  static Future\u003cJsModuleBytecodeBundle\u003e compileModuleBundle({\n    required List\u003cJsModule\u003e modules,\n    String? entry,\n    JsModuleBytecodeOptions? options,\n  });\n\n  static JsScriptBytecode compileScriptSync({\n    required String name,\n    required JsCode source,\n    JsScriptBytecodeOptions? options,\n  });\n\n  static Future\u003cJsScriptBytecode\u003e compileScript({\n    required String name,\n    required JsCode source,\n    JsScriptBytecodeOptions? options,\n  });\n\n  static void validateSync({required JsModuleBytecode module});\n  static Future\u003cvoid\u003e validate({required JsModuleBytecode module});\n  static void validateBundleSync({required JsModuleBytecodeBundle bundle});\n  static Future\u003cvoid\u003e validateBundle({required JsModuleBytecodeBundle bundle});\n  static void validateScriptSync({required JsScriptBytecode script});\n  static Future\u003cvoid\u003e validateScript({required JsScriptBytecode script});\n}\n\nsealed class JsModuleBytecodeOptions {\n  const factory JsModuleBytecodeOptions({\n    JsBytecodeEndianness? endianness,\n    bool? stripSource,\n    bool? stripDebug,\n  });\n\n  static JsModuleBytecodeOptions defaults();\n}\n\nsealed class JsScriptBytecodeOptions {\n  const factory JsScriptBytecodeOptions({\n    JsBytecodeEndianness? endianness,\n    bool? stripSource,\n    bool? stripDebug,\n    bool? strict,\n    bool? backtraceBarrier,\n    bool? promise,\n  });\n\n  static JsScriptBytecodeOptions defaults();\n}\n```\n\n### JsResult \u0026 JsError\n\n```dart\nsealed class JsResult {\n  const factory JsResult.ok(JsValue value);\n  const factory JsResult.err(JsError error);\n\n  bool get isOk;\n  bool get isErr;\n  JsValue get ok;\n  JsError get err;\n}\n\nsealed class JsError {\n  const factory JsError.promise(String message);\n  const factory JsError.module({String? module, String? method, required String message});\n  const factory JsError.context(String message);\n  const factory JsError.storage(String message);\n  const factory JsError.io({String? path, required String message});\n  const factory JsError.runtime(String message);\n  const factory JsError.generic(String message);\n  const factory JsError.engine(String message);\n  const factory JsError.bridge(String message);\n  const factory JsError.conversion({\n    required String from,\n    required String to,\n    required String message,\n  });\n  const factory JsError.timeout({\n    required String operation,\n    required BigInt timeoutMs,\n  });\n  const factory JsError.memoryLimit({\n    required BigInt current,\n    required BigInt limit,\n  });\n  const factory JsError.stackOverflow(String message);\n  const factory JsError.syntax({int? line, int? column, required String message});\n  const factory JsError.reference(String message);\n  const factory JsError.type(String message);\n  const factory JsError.cancelled(String message);\n\n  String code();\n  bool isRecoverable();\n}\n```\n\n## 🧩 Built-in Runtime Features\n\nSome builtin options expose importable modules, and some install globals directly on the runtime.\n\n| Option | Description |\n|--------|-------------|\n| `abort` | `AbortController` and abort-related globals |\n| `assert` | Assertion helpers |\n| `asyncHooks` | Async lifecycle tracking |\n| `buffer` | Buffer utilities for binary data |\n| `childProcess` | Child process spawning |\n| `console` | Console logging (`console.log`, `console.error`, etc.) |\n| `crypto` | Cryptographic functions and Web Crypto globals |\n| `dgram` | UDP sockets |\n| `dns` | DNS resolution |\n| `events` | `EventEmitter` support |\n| `exceptions` | Exception helpers installed globally |\n| `fetch` | Fetch API globals |\n| `fs` | File system operations |\n| `https` | HTTPS client module |\n| `intl` | Lightweight `Intl.DateTimeFormat` timezone support |\n| `navigator` | Navigator globals |\n| `net` | TCP sockets |\n| `os` | Operating system utilities (`not available on iOS`) |\n| `path` | Path manipulation (POSIX/Windows) |\n| `perfHooks` | Performance measurement APIs |\n| `process` | Process information and environment |\n| `streamWeb` | Web Streams API |\n| `stringDecoder` | String decoding from buffers |\n| `temporal` | `Temporal` global |\n| `timers` | Timer functions (`setTimeout`, `setInterval`, `setImmediate`) |\n| `tty` | Terminal utilities |\n| `url` | URL parsing and formatting |\n| `util` | Utility functions |\n| `zlib` | Compression/decompression (gzip, deflate) |\n| `json` | JSON static method compatibility helpers |\n\n### Quick Presets\n\n```dart\n// Essential: console, timers, buffer, util, json\nJsBuiltinOptions.essential()\n\n// Web: console, timers, fetch, url, crypto, streamWeb, navigator, exceptions, intl, json\nJsBuiltinOptions.web()\n\n// Node.js: Most Node-compatible modules, plus https and intl\nJsBuiltinOptions.node()\n\n// All modules\nJsBuiltinOptions.all()\n\n// Custom selection\nJsBuiltinOptions(\n  console: true,\n  fetch: true,\n  timers: true,\n  // ... other options\n)\n```\n\n## ⚡ Performance Tips\n\n1. **Reuse Engines** - Create once, use many times\n2. **Set Memory Limits** - Configure appropriate limits\n3. **Use Source Bytes** - Prefer `JsCode.bytes()` / `JsModule.bytes()` when your JavaScript source is already in UTF-8 bytes\n4. **Batch Operations** - Group related operations\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE) file.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Ffjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluttercandies%2Ffjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Ffjs/lists"}