flutter_qjs_next 1.5.1
flutter_qjs_next: ^1.5.1 copied to clipboard
QuickJS bindings for Flutter and Dart through dart:ffi (flutter_qjs_next), with native support for Android, iOS, macOS, Linux, and Windows.
1.5.0 #
- Breaking (Web APIs): optional module dependencies. A module's
optionalmodules are never installed on its behalf; when they are installed anyway they come first and enable extra features.streamsno longer pulls inencoding(TextEncoderStream/TextDecoderStreamappear only withencoding),blobno longer pulls instreams(Blob.prototype.streamonly withstreams), andhttpno longer pulls inblob(blob()/formData()and Blob/FormData bodies only withblob). SoJsWebApis(modules: {JsWebModule.http})no longer definesBlob, andJsWebApis(fetch: ...)alone has noresponse.blob(); addJsWebModule.blobor useJsWebApis.standard(...), which is unchanged.fetchnow declares its direct dependency onevents. - Breaking (Web APIs):
JsWebModule.capabilityis renamedhostConfig(value'JsFetchOptions'). Modules are documented as a functional split, not a permission model: leaving a module out does not sandbox a script; host access is governed byJsFetchOptions, bridges,memoryLimitandtimeout. - Internal:
coreexposeshas(name)and defaultisAbortSignal/isBlob/isFormDatabrand checks thatevents/blobreplace. Modules readinternalonly through one leading destructuring;example/test/web_apis_internal_names_test.dartchecks that every name read comes from a declared dependency and that optional ones are guarded byhas(). - Fix:
jsCallno longer posts a wake-up message to the event-loop port when nodispatch()loop is running, so the port no longer buffers one message per call for the life of the runtime.
1.4.0 #
- Feat:
JsModuleBundle— compile an ES module graph to bytecode once and register it in a context, so imports resolve locally instead of through the module loader.IsolateQjs(bundle: ...)ships the bundle with the spawn message andevaluateBundleEntry()runs it, which removes the per-module cross-isolate round trip (the worker used to park in 1 mssleepsteps while the spawning isolate resolved each module) and the per-load parse.IsolateQjs(moduleSources: {...})is the same round-trip-free path without precompiling. - Feat:
JavascriptRuntime.compile(..., asModule: true)andregisterModuleBytecode(bytecode, resolve: false). - Feat:
readNativeHeapUsage()/trimNativeHeap()— C heap accounting (arena / in use / free / mmapped) and a request to return free pages to the OS. These tell allocator residency apart from a real leak; seedoc/wiki/guides/soak-rss-analysis.md. - Fix: every call from JS into a Dart host function leaked the 16-byte
JSValuebox holding the return value (js_channelnever freed the pointer the host handed back). - Fix: the
ArrayBuffer/TypedArrayprobes in_jsToDartleft a pendingTypeError("not an ArrayBuffer" / "not a TypedArray") on the context for every plain object converted. The next unrelated exception check reported it instead of the real failure. - Fix: a module that cannot be loaded now throws
ReferenceError: could not load module '<name>'instead of failing with no exception, and_parseJSExceptionnever returnsnull. - Native: new exports
jsCompile,jsReadModuleBytecode,jsTrimNativeHeap,jsNativeHeapUsage;EvaluateBytecoderesolves a module's imports before evaluating it (all platform copies synchronized). - Tests:
SOAK_PROFILE=op:<opName>pins the soak to a single operation, andsoak_metrics.jsonlrecordsnativeHeap(C heap arena / in use / free / mmapped) next torss. Together they identify what grows without guessing: process RSS underweb_fetchis the Dart heap (C arena flat at ~30 MB,malloc_trimrecovers ~24 MB of 540), and insideweb_fetchit isfetchAbortalone — 5.1 MB/s against ≤0.26 MB/s for every other fetch operation.example/test/http_control_test.dartreproduces it with no QuickJS in the process (CONTROL_MODE=abort: 150 → 1206 MB over 30 k requests;read/cancel/cancelpausedall plateau), so the retention is indart:io's aborted-request path, not in this package. Findings and how to re-run:doc/wiki/guides/soak-rss-analysis.md. - Tests: the soak's
/slowendpoint no longer parks a server handler forever when the client aborts (it watchesresponse.doneand boundsflush/close); 6682 handlers were stuck after 10 k aborted requests. - Fix:
initChannelFunctionsreports the engine's own message when bridge setup fails instead of an opaque cast error, and frees the setter even if installing the bridge throws. - Build: opening a native library older than the Dart code now fails with the missing symbol and how to rebuild, instead of surfacing much later as a masked
JSErrorduring value conversion.
1.3.0 #
- Feat: Web platform APIs (a WinterTC subset), installed per module with their dependency closure — see
doc/wiki/api/web-apis.md. Modules:core(default: timers,queueMicrotask,reportError,console,performance,structuredClone,atob/btoa,DOMException,crypto.getRandomValues/randomUUID),events,encoding,url,crypto,navigator,streams,blob,http,fetch. Presets:JsWebApis.none(),JsWebApis()(core only),JsWebApis.standard(), orJsWebApis(modules: {JsWebModule.url})to name your own — dependencies are resolved and ordered for you. - Feat:
fetch(JsWebApis(fetch: JsFetchOptions(...)), off by default). It is the only module that carries a capability, and it cannot be installed without that policy object —JsWebApis(modules: {JsWebModule.fetch})alone throwsArgumentError. Per-hopallowUrlpolicy, runtime-side redirect handling,maxResponseBytes, back-pressured response streaming,AbortSignal, and a replaceableJsFetchHandler(default:dart:ioHttpClient, closed with the engine). - Feat:
crypto.subtlewith SHA-1/256/384/512digestand HMAC (generateKey/importKey/exportKey/sign/verify); other algorithms reject withNotSupportedError. - Feat (behavior):
consolenow formats likeutil.format/util.inspect(%s/%d/%o, BigInt,Map/Set, TypedArrays, cycles, getters,Errorstacks) and addsdebug,trace,assert,dir,group,count,time. It calls the logger directly: the internalConsoleLogchannel is gone. - Feat (behavior): timers gained
setInterval/clearIntervaland extra callback arguments;clearTimeout/clearIntervalnow really cancel the DartTimer; callback errors are reported throughreportErrorinstead of being swallowed; a timer callback is followed by a microtask checkpoint. The internalSetTimeoutchannel and the__NATIVE_FLUTTER_JS__*globals are gone, and Web API globals are non-enumerable. - Fix: JS→Dart strings no longer lose a leading BOM (
Utf8Decodersilently drops U+FEFF). - Behavior: installing the
coremodule needs roughly 320 KiB ofmemoryLimit(about 1 MiB forJsWebApis.standard()). Engines with a tighter budget can install fewer modules ({JsWebModule.url}is 224 KiB) or passJsWebApis.none()for a bare context (noconsole, no timers). - API:
JsWebApis(.none()/.standard()/modules:, withresolvedModulesandinstalls()),JsWebModule,JsFetchOptions,JsFetchRequest,JsFetchResponse,JsFetchHandler;webApisonQuickJsRuntime2,getJavascriptRuntimeandJsEnginePoolConfig;JavascriptRuntime.compile(..., stripSource: false). - Native: new exports
jsNewWebNatives(UTF-8 encode/decode, monotonic clock) andjsSetStripInfo/jsGetStripInfo(all platform copies synchronized). - Perf:
_DartFunctionresolves itsthisValparameter once instead of running a regular expression on every host call. - Removed:
assets/js/fetch.js(an unused XHR-based polyfill) and the packageassets/declaration. - Tests: the soak runner gained Web API workloads (
web_core,web_url,web_encoding,web_blob,web_streams,web_crypto,web_fetch,web_all,mixed_all) driven against an in-process HTTP server, plus open-file-descriptor / Dart-handle / engine-heap ceilings, an optional cooldown phase that makes RSS interpretable, and a stubbed-network control (SOAK_FETCH_STUB). Experiment design and pilot results:doc/design/2026-09-16-web-apis-soak.md. - Tests / docs:
example/test/web_apis_*_test.dart(module closure and capability enforcement, core, standard library, URL, streams, Blob/FormData, HTTP types, crypto, fetch), with expectations cross-checked against Node.js 24; new wiki pagedoc/wiki/api/web-apis.md; design notes indoc/design/2026-09-13-web-apis.md.
1.2.2 #
- Fix:
compile()crashed (free(): invalid pointer) — bytecode buffer is now released withjs_free. - Fix: Dart→JS conversion read freed memory when the same
List/Mapappeared more than once (non-cyclic shared references). - Fix (behavior):
softReset()now replaces theJSContexton the sameJSRuntime. Globalvar/let/const/classbindings and builtin prototype changes no longer survive, and builtins such asAggregateError,Iterator,Float16Arrayare no longer deleted. Native heap and engine instance id are kept. - Fix (behavior):
timeoutnow also covers JS run while converting results (getters, Proxy traps). A throwing or interrupted getter makes the whole result an error (evaluate→isError,JSInvokable.invoke→ throwsJSError) instead of silently becomingnull. - Fix: strings containing U+0000 are no longer truncated in either direction (native
jsNewString/jsToCStringtake explicit lengths). - Fix: a Dart host function that throws no longer leaks its
JSRefarguments. - Fix: the
DartObjectclass id is allocated once per process instead of per context, removing per-engineclass_arraygrowth and the ~65k engine-creation limit. - Native: new exports
jsBeginCall/jsEndCall;jsNewStringandjsToCStringsignatures changed (all platform copies synchronized). - Tests / docs:
example/test/review_regression_test.dart; review notes indoc/review/2026-09-13-code-review.md.
1.2.1 #
- Lint: add missing type annotations on
JSErrorconstructor parameters (lib/quickjs/object.dart). - macOS/iOS build: avoid ObjC
BOOLclash with QuickJScutils.h(#if !defined(__OBJC__)). - Apple plugins: pure Objective-C registration (drop Swift) so SPM can compile C/C++ + ObjC in one target.
- SPM: depend on Flutter’s
FlutterFramework; public headers only underSources/.../include/. - CocoaPods: public headers limited to
Classes/; QuickJS headers private; header search path forcxx/. - macOS SPM: rename QuickJS
VERSION→VERSION.txt(APFS case-insensitive clash with C++#include <version>).
1.2.0 #
- Pool default:
JsEnginePoolConfig.resetOnReleaseis nowfalse(warm reuse; better process RSS under churn). Multi-tenant: preferresetMode: soft(not hard as an RSS fix). - Soft wipe:
JavascriptRuntime.softReset()+EngineResetMode(none/soft/hard) onJsEnginePoolConfig.resetMode. Prefersoftfor multi-tenant isolation without full native rebuild;resetOnRelease: truestill maps tohard. - Document soak RSS analysis: process RSS growth is dominated by hard reinitialize churn, not QJS heap / bridge counters.
- Docs: production integration checklist (
doc/wiki/guides/production-checklist.md), multi-tenant recipe updates, and exampleProductionTenantWorker+ tests.
1.1.1 #
- Fix
QuickJsRuntime2.closereference leak: release runtime refs viajsReleaseRuntimeRefsbefore freeing theJSContext.
1.1.0 #
- Perf:
JsTypedArrayTransferand native owned-buffer paths for TypedArray / ArrayBuffer bridging. - Perf:
evaluateJsonBatchfor bulk JSON evaluate and bulk result copy. - Optimize object reference tables on the FFI boundary.
- Fix
Uint8ClampedArraydouble-copy path; expand TypedArray benchmarks (sizes, element types, non-zero offset, both directions). - Feat: native bridge allocation / copy counters (
readBridgeStats/jsBridgeStats*) on all platforms. - Expand micro-benchmarks, soak/stress coverage, and performance wiki docs (measured results, standard
benchmark_results/layout).
1.0.2 #
- Add a complete Flutter example application and include it in the published package.
- Improve the GitHub Actions pub.dev publishing workflow for version tags.
- Expand example-based test and stress-test coverage for package validation.
- Add static analysis configuration and update development dependencies.
- Bump embedded QuickJS to 2026-06-04 (all platforms:
cxx/,cxx-windows/, iOS/macOS SPM trees).
1.0.1 #
- Publish automatically from Github Action
- Fix Non Linux and Windows head file problem
1.0.0 #
- Package name:
flutter_qjs_next(QuickJS engine bindings for Flutter). - QuickJS 2025-09-13 on all platforms; Windows tree aligned with Unix (
dtoa, same sources). - TypedArray detection no longer depends on hard-coded
JS_CLASS_*numeric IDs (constructor name + element size). dart:ffibindings for Android, iOS, macOS, Linux, Windows.- Array / TypedArray marshalling fast paths,
evaluateJson, timeout/memory/stack limits, console logger, safersetTimeoutchannel (cached invokable runner). - Default
memoryLimit64 MiB (kDefaultJsMemoryLimit); pass0for unlimited. - Multi-engine:
JsEnginePool/JsEnginePoolConfigwithresetOnReleaseviaJavascriptRuntime.reinitialize(). - Unique engine instance ids:
qjs-<isolateHash>-<serial>-<us>(notidentityHashCode). QuickJsRuntime2.autoExecutePendingJobs(default true) drains Promise jobs after evaluate / call / bytecode / evaluateJson; documented in README.- Isolate module load: 1ms wait on
IntPtrslot instead of 1µs pointer spin. - Dispose hardening: idempotent
dispose,runtimeOpaquesentry removed on free, disposed engines refuse re-init. - Rename residues:
FLUTTER_QJS_NEXT_LIBRARY(legacyFLUTTER_QJS_ES2023_LIBRARYstill accepted).