OS4 DepotLogo by Nickman 
(anonymous IP: 18.97.9.168,2472) 
 HomeRecentStatsSearchSubmitUploadsMirrorsContactInfoDisclaimerConfigAdmin
 Menu

 Features
   Crashlogs
   Bug tracker
   Locale browser
 

 Categories

   o Audio (349)
   o Datatype (51)
   o Demo (205)
   o Development (620)
   o Document (24)
   o Driver (101)
   o Emulation (154)
   o Game (1035)
   o Graphics (514)
   o Library (120)
   o Network (238)
   o Office (67)
   o Utility (952)
   o Video (73)

Total files: 4503

Full index file
Recent index file

 Links

  Amigans.net
  Aminet
  IntuitionBase
  Hyperion Entertainment
  A-Eon
  Amiga Future


Support the site


 Readme for:  Development » Language » nodeamiga.lha

NodeAmiga

Description: JavaScript runtime for AmigaOS
Download: nodeamiga.lha       (TIPS: Use the right click menu if your browser takes you back here all the time)
Size: 1011kb
Version: 0.26.0
Date: 14 May 2026
Author: Pawel Nowak
Submitter: Samir Hawamdeh
Homepage: http://juen.in
Requirements: bsdsocket.library (for networking)
Category: development/language
Replaces: development/language/nodeamiga.lha
License: Other
Distribute: yes
Min OS Version: 4.0
FileID: 13829
 
Comments: 0
Snapshots: 0
Videos: 0
Downloads: 31  (Current version)
254  (Accumulated)
Votes: 0 (0/0)  (30 days/7 days)

Show comments Show snapshots Show videos Show content Show crashlogs Replace file 
A complete JavaScript engine and runtime environment 
for Classic Amiga, MorphOS and AmigaOS 4.x
Built from scratch in C, targeting MC68000 and AmigaOS 2.0+.
Inspired by Node.js, adapted for the Amiga platform.

Documentation:   http://juen.in/NodeAmiga/
Support author:  http://juen.in/support/

Features
--------

 * JavaScript engine (ES5.1 + ES6+ features)
   - Arrow functions, classes with inheritance, super(), static
   - Class fields: public, private (#field), static
   - Template literals, tagged
   - Destructuring, spread/rest, default parameters
   - for-of loops, labeled break/continue
   - Regex literal /pattern/flags
   - Optional chaining (?.), nullish coalescing (??)
   - BigInt (123n, arithmetic, comparison, BigInt())
   - let/const block scoping, numeric separators
   - async/await, Promises, dynamic import()
   - Generators (function*, yield, yield* delegation)
   - Async generators (async function*, for await...of)
   - Generator methods in classes and objects
   - Automatic Semicolon Insertion (ASI)
   - Closures, prototype chain

 * Built-in objects and functions
   - console (log, error, warn, dir, time/timeEnd, table,
     count/countReset)
   - Math (27 functions incl. cbrt/fround/clz32/imul)
   - JSON (with reviver/replacer)
   - Date (full API incl. UTC, getUTC*/setUTC*)
   - RegExp (lookahead, non-capturing groups, quantifiers, lazy,
     named groups, lookbehind, flags g/i/m/s/u/y)
   - Buffer (hex/base64)
   - Promise (then/catch/finally/all/race/allSettled)
   - Map, Set, WeakMap, WeakSet, Symbol
   - setTimeout/setInterval/clearTimeout
   - crypto (MD5, SHA-256), structuredClone
   - TextEncoder, TextDecoder
   - Typed Arrays: Uint8Array, Int8Array, Uint16Array, Int16Array,
     Uint32Array, Int32Array, Float32Array, Float64Array,
     Uint8ClampedArray, ArrayBuffer, DataView
     (from/of, forEach/map/filter/find/every/some/reduce,
     set/fill/slice/subarray/reverse/indexOf/includes/join)
   - fetch() global HTTP client
   - performance.now() timer
   - Error.cause (ES2022)
   - process.stdout.write, process.stdin.read
   - process.hrtime, process.nextTick, queueMicrotask

 * String methods: 29+ (charAt, indexOf, slice, split, replace,
   replaceAll, trim, includes, startsWith, padStart, normalize,
   localeCompare, codePointAt, etc.)

 * Array methods: 37+ (push, pop, map, filter, reduce, reduceRight,
   sort, find, findLast, findLastIndex, forEach, every, some, splice,
   flat, flatMap, entries, keys, values, copyWithin, at,
   Array.from/of/isArray, toReversed, toSorted, toSpliced, with)

 * Object: keys, values, entries, assign, create, freeze, seal, is,
   fromEntries, defineProperty/ies, hasOwn, getPrototypeOf,
   setPrototypeOf, getOwnPropertyNames,
   getOwnPropertyDescriptor(s), preventExtensions, isExtensible,
   groupBy, getOwnPropertySymbols, getters/setters

 * Number: isInteger, isFinite, isNaN, isSafeInteger, parseInt,
   parseFloat, toString(radix), toFixed, toExponential, toPrecision,
   constants (EPSILON, MAX_SAFE_INTEGER, MIN_SAFE_INTEGER, NaN,
   Infinity)

 * Global functions: encodeURIComponent, decodeURIComponent,
   encodeURI, decodeURI, parseInt, parseFloat, isNaN, isFinite,
   eval(), fetch()

 * Symbol: Symbol(), Symbol.for/keyFor, well-known symbols, Symbol
   as property key, Iterator protocol (Symbol.iterator)

 * Amiga Intuition GUI bindings
   - Open windows with title, size, position
   - Graphics: lines, rects, circles, text, pixels
   - Mouse and keyboard events
   - System requesters (alert, confirm)
   - Screen information query

 * GadTools GUI toolkit (gui module)
   - createWindow() with declarative gadget layout
   - 12 widget types: button, string, text, integer, checkbox,
     cycle, slider, listview, mx, number, scroller, area
     (bevel box)
   - gui.gfx: drawing on GadTools windows (setColor, drawLine,
     fillRect, drawCircle, drawText, setPixel, setFont, etc.)
   - innerSize() for drawable area, auto GZZ offset
   - Resizable windows (GIMMEZEROZERO clipping)
   - Percentage layout (left: "50%", width: "80%")
   - Negative positioning (top: -20 = anchor bottom)
   - flex: true - gadget expands to fill available space
   - minWidth/minHeight
   - font: { name, size } per-window custom font (e.g.
     topaz.font 8 for fixed-width column alignment)
   - Event-driven: waitEvent/pollEvent, gadgetup/gadgetdown/
     mousemove/close/key
   - evt.x, evt.y mouse coords on gadget events
   - get/set gadget values at runtime
   - setTitle, listview dynamic item update
   - Menu bar: setMenu() with keyboard shortcuts
   - ASL file requester: fileRequest() with patterns
   - ASL font requester: fontRequest()
   - Proper GadTools cleanup

 * Clipboard module (clipboard)
   - read() - read text from system clipboard
   - write(text) - write text
   - clear() - clear clipboard
   - Uses IFF FTXT/CHRS via iffparse.library

 * ARexx module (arexx)
   - send(port, command) - send ARexx command to app
   - createPort(name) / closePort()
   - getMsg() / waitMsg() / reply()
   - listPorts() - list all public message ports
   - Uses rexxsyslib.library

 * FFI module (amiga)
   - Direct Amiga library function calls from JavaScript
   - openLibrary(name, version) / closeLibrary(lib)
   - call(lib, offset, regs) - call any library function with
     register args
   - peek8/16/32(addr), poke8/16/32(addr, val) - memory access
   - peekString(addr), pokeString(addr, str)
   - allocMem(size, flags) / freeMem(ptr, size)
   - makeTags(array) - build TagItem array for Amiga tag-based APIs
   - Full 32-bit unsigned support (0xDEADBEEF etc.)

 * Interactive debugger (--debug)
   - Step, next, step-out, continue
   - Breakpoints by line number
   - Variable inspection (p varname)
   - Call stack backtrace (bt)
   - Source listing around current line

 * Node.js-compatible modules
   - require() with caching
   - CommonJS exports (module.exports)
   - ES modules: import/export (default, named, namespace)
   - Dynamic import() expression
   - Native modules: fs, http, net, buffer, os, child_process,
     crypto, intuition, gui, readline, dns, clipboard, arexx,
     amiga
   - JS modules: path, events, url, querystring, util, stream,
     assert, repl, timers, string_decoder, punycode, console,
     constants, zlib, iff

 * File I/O (fs module)
   - readFileSync, writeFileSync, appendFileSync
   - existsSync, unlinkSync, renameSync, statSync
   - readdirSync, mkdirSync, rmdirSync, copyFileSync
   - readFile, writeFile (async)
   - createReadStream, createWriteStream
   - Full AmigaOS path support (Volume:dir/file)

 * HTTP/HTTPS server and client
   - http.createServer() non-blocking, 8 concurrent
   - http.get(), http.post(), http.request()
   - HTTPS via AmiSSL (build with -DENABLE_AMISSL)
   - Auto redirect following (301/302/307)
   - 10-second socket timeout, dns.lookup()
   - Requires bsdsocket.library (Roadshow, Miami, AmiTCP)

 * OS integration
   - process.platform ("amigaos"), process.arch ("m68k")
   - process.argv, process.env, process.cwd(), process.exit
   - os.cpus() (detects 68000/020/030/040/060)
   - os.freemem(), os.version() (Kickstart version)
   - child_process.execSync() via SystemTagList()

 * Interactive REPL with command history (arrow up/down)

 * Error types: Error, TypeError, RangeError, ReferenceError,
   SyntaxError, EvalError, URIError

 * Error messages with filename and line number

 * Compiler: bundle JS + interpreter into standalone executable
   - NodeAmiga -compile MyApp script.js
   - Automatic require() and import dependency resolution
   - All JS modules bundled into single executable
   - No NodeAmiga, no libs/ needed to run the output

Usage
-----

  NodeAmiga script.js
    Execute a JavaScript file
  NodeAmiga -e "code"
    Evaluate inline JavaScript
  NodeAmiga -compile out script
    Compile to standalone exe
  NodeAmiga
    Start interactive REPL
  NodeAmiga -help
    Show help
  NodeAmiga -v
    Show version
  NodeAmiga --vm script.js
    Use bytecode VM (experimental)
  NodeAmiga --tree script.js
    Use tree-walking interpreter (default)
  NodeAmiga --debug script.js
    Run with interactive debugger
  NodeAmiga --ast script.js
    Print AST (debug)

Installation
------------

  1. Copy NodeAmiga to C: or any directory in your path
  2. Copy the libs/ directory to PROGDIR: (same directory as
     NodeAmiga), or to LIBS:node/
  3. Optional: copy examples/ for demo scripts

Quick test:

  NodeAmiga -e "console.log('Hello Amiga!')"
  NodeAmiga examples/hello.js
  NodeAmiga examples/gui_hello.js
  NodeAmiga examples/fibonacci.js

Compile to standalone exe:

  NodeAmiga -compile Hello examples/hello.js
  Hello
  ; Runs without NodeAmiga or libs/ !

System Requirements
-------------------

  * MC68000 or higher CPU
  * AmigaOS 2.04 (Kickstart 37) or higher
  * Minimum 1 MB RAM (2+ MB recommended)
  * bsdsocket.library for networking features (Roadshow, Miami,
    AmiTCP)
  * No FPU required (software floating-point)

Technical Details
-----------------

  * Engine: custom-built lexer, recursive descent parser with Pratt
    precedence climbing, tree-walking interpreter (default).
    A bytecode VM is also bundled (--vm) but currently experimental
    and disabled by default while issues are sorted out.
  * Memory: reference counting (no GC pauses), arena allocator for
    AST, integer cache 0-255
  * Stack: auto-allocates 64 KB via StackSwap

Included Examples
-----------------

  hello.js
    Platform info and greeting
  fibonacci.js
    Recursive/iterative benchmark
  file_io.js
    File read/write/append
  http_server.js
    HTTP server with routing
  http_client.js
    HTTP GET and POST requests
  classes.js
    ES6 classes with inheritance
  closures.js
    Closures, IIFE, module pat.
  array_fun.js
    map/filter/reduce/sort
  regex.js
    RegExp /literal/ and methods
  events.js
    EventEmitter custom events
  promises.js
    Promise chains, all, race
  timers.js
    setTimeout and setInterval
  buffer.js
    Binary data manipulation
  streams.js
    Readable/Writable/Transform
  sysinfo.js
    Full system info display
  todo_app.js
    TODO app with persistence
  mini_grep.js
    Pattern search in files
  url_parser.js
    URL and query string parsing
  calculator.js
    Recursive descent expr parser
  json_db.js
    JSON file-based database
  myip.js
    Fetch public IP from internet
  nettime.js
    Internet time via HTTP API
  weather.js
    Weather info for a city
  download.js
    Download file and save
  gui_hello.js
    Simplest Intuition window
  gui_demo.js
    Interactive drawing + mouse
  gui_calculator.js
    GadTools calculator (320x200)
  3d.js
    Rotating 3D wireframe cube
  3d_tunnel.js
    Wireframe tunnel fly-through
  pong.js
    Bouncing ball (XOR, circle)
  gui_translator.js
    Google Translate with GUI
  gui_window.js
    GadTools widget gallery
  gui_menu.js
    Menu bar + ASL requesters
  gui_drawing.js
    gui.gfx primitives (4 scenes)
  gui_gfx_clock.js
    Analog clock (resizable)
  gui_keyboard_and_scrolls.js
    Arrow keys + scrollers demo
  gui_weather.js
    Weather app with GadTools GUI
  aminet_browser.js
    Aminet archive browser + GUI
  aminet_browser_opt.js
    Optimized variant of aminet_browser
  gui_disasm.js
    68k disassembler for Amiga EXE
  gui_monitor.js
    System monitor (mem/tasks/libs)
  gui_ftp_client.js
    FTP client (PASV) with GUI
  gui_extra_demo.js
    Modal dialogs + image + colour
  clipboard.js
    System clipboard read/write
  arexx.js
    ARexx port communication
  dns_lookup.js
    DNS hostname resolution
  readline_chat.js
    Interactive readline + prompt
  ffi.js
    Amiga library FFI demo
  iff_info.js
    IFF/ILBM/8SVX file viewer

Known Limitations
-----------------

  * No Proxy
  * await is synchronous (spin-waits on event loop)

Version History
---------------

0.26.0 (2026-05-13)
  Spec gaps + perf + diagnostics: property
  descriptors complete, Error.stack with
  file:line:col, fetch headers/arrayBuffer,
  cycle-breaking GC, Map/Set hash backing
  (O(1) lookup), named regex captures, tagged
  template raw, typed-array merge sort,
  unhandledRejection / heapSnapshot, locale
  module, all four CPU variants.

0.25.0 (2026-05-07)
  Spec correctness pass + memory hardening,
  driven by a new 2300-assertion test suite
    - test/test_extra.js (2319 assertions over
      50 sections) catches the boundary cases
      test.js skipped: NaN equality, sparse
      arrays, refcount stress, proto chain,
      property descriptors, etc.
    - parseInt("") / parseFloat("") and any
      input whose first non-space char is not
      [-+.0-9] now return NaN. Some libcs ate
      'a' as a hex digit and gave 0.
    - parseFloat("abc") rejects up front
      instead of relying on strtod's endptr.
    - JSON.stringify(undefined / function /
      symbol) returns the JS undefined value
      (not the string "null").
    - JSON.stringify(o, null, "t") accepts
      string indent (was numbers only).
    - JSON.parse on malformed input throws
      SyntaxError (was returning null).
    - Object.prototype.constructor now points
      at the Object global; same for
      Array.prototype.constructor.
    - Plain {} now has Object.prototype as
      proto; Object.getPrototypeOf({}) returns
      Object.prototype, "hasOwnProperty" in
      {} works. Object.create(null) still
      gives a null-proto object.
    - All built-in prototype methods are now
      non-enumerable; for-in over a user
      object no longer yields hasOwnProperty,
      push, map, etc.
    - Array's `length` property is non-enum.
    - Date arithmetic via _timestamp lookup;
      d2 - d1 returns ms delta (was NaN).
    - Array.from(Set/Map) and [...Set/Map]
      walk via [()()iterator]; spread on
      generators ([...g()]) walks via .next().
    - Array length: a[10]=x extends length;
      a.length=N truncates and deletes
      orphan entries.
    - [NaN].includes(NaN) true (SameValueZero).
    - js_new_number(NaN) no longer aliases
      to g_int_cache[0]. (NaN >= 0 evaluates
      true on some -Os/m68k combos, which
      had been silently turning NaN into 0
      everywhere ? Math.sign, isNaN of
      parseInt failures, etc.)
    - Custom math_ceil / floor / round ?
      Amiga -noixemul libc's ceil(0.0)
      returned 1.0; ours uses long-cast
      truncation for inputs in long range.
    - Object.defineProperty {writable:false}
      enforced via PROP_FLAG_NON_WRITABLE on
      JsProperty (checked in both
      js_object_set and js_object_set_by_ref).
    - Arrow function `this` is lexical: is_-
      arrow flag on JsFunction; call_function
      skips the env_define("this") step for
      arrows so lookup walks up to enclosing
      scope.
    - for (let i...) creates a per-iteration
      binding; closures captured in body see
      this iteration's value, not the post-
      update one. Update runs in loop_env so
      iter_env stays "frozen" for closures.
    - WeakMap.set / WeakSet.add throw real
      TypeError on primitive keys (was
      stderr-only).
    - readline.createInterface({input: fs.-
      createReadStream(path)}) drains lines
      synchronously when 'line' attaches.
    - Template `${"a"}-${"b"}` produces
      `a-b` (was `"a"-"b"`).
    - RegExp.flags string in canonical order
      gimsuy.
    - RE_MAX_CAPTURES 16 -> 64; METAR-class
      patterns with 50+ capture groups now
      compile + match. RE_MAX_STEPS 100k -> 1M
      so legitimate big regexes don't spuriously
      bail.
    - fetch() Response gains text() and json()
      methods (were missing ? `await res.text()`
      called undefined).
    - fs.writeFileSync(path, buffer) writes
      raw bytes (was stringifying Buffer to
      "[object Object]").
    - Stack bumped 64 KB -> 256 KB so
      sum(100)-class recursion fits.
    - module_cache_cleanup and interp_destroy
      no longer cascade-release on exit; the
      pool sweep in value_cleanup handles
      everything without traversing references.
      Plugs an ~19 MB-per-run leak that
      survived process termination.
    - examples/readline_file.js demonstrates
      the readline+stream pattern.

  0.24.0 (2026-05-05)
  Readline file streaming + 7 spec bugs caught
  by 1000-test extra suite
    - readline.createInterface({input: stream})
      now actually fires line/close events
      (was a stub that ignored input).
    - Template `${"a"}-${"b"}` produced
      `"a"-"b"`. eval_template_literal now
      uses parts-list parity rather than node
      type to tell template text apart from
      inline string-literal expressions.
    - RegExp.flags string was missing; added
      canonical-order gimsuy string at both
      construction sites (literal + ctor).
    - `"hasOwnProperty" in {}` returned false
      because eval_object never wired up the
      Object.prototype as new-object proto.
    - Array sparse assign (a[10]=x) did not
      bump a.length, and a.length=N did not
      truncate. Both fixed in eval_assign.
    - [NaN].includes(NaN) returned false;
      added SameValueZero NaN special case.
    - (3.5).toFixed(0) returned "3"; rewrote
      to scale-and-round so half-up applies
      at any digits, including digits=0.
    - New test/test_extra.js with 1010
      assertions covering refcount stress,
      proto chain, NaN equality, sparse
      arrays, all option combinations.
    - examples/readline_file.js demonstrates
      the new readline+stream API.
    - Makefile uses wildcard for test/*.js.

  0.23.0 (2026-05-04)
  Refcount leak fix, runtime cycle/mx update, diagnostics
    - FIX: every `var x = LITERAL;` and every property in
      every `{a: 1, b: 2}` was leaking one refcount. The
      JsValue could never reach 0 and stayed pinned in the
      pool for the rest of the process. A budget app with
      hundreds of object-literal accounts would gradually
      exhaust the JsProperty pool, causing
      js_alloc_property to return NULL and env_define to
      silently fail to add the binding -- the script
      seemed to "lose" variables (even consts).
      eval_var_declaration and eval_object_expression now
      release the extra ref ONLY when the init expression
      type is one that is guaranteed to produce a fresh
      JsValue (NUMBER/STRING/BIGINT/OBJECT/ARRAY/BINARY/
      UNARY/UPDATE/FUNCTION/NEW/REGEX/TEMPLATE literals).
      Identifier, member, call, tagged-template, assign,
      logical, conditional and sequence expressions stay
      conservative -- they may return a borrowed ref which
      we must not free.
    - NEW: gui.set(win, id, items) on cycle and mx (radio)
      gadgets accepts an array, replacing the items list
      at runtime. Previously cycle/mx only accepted a
      number to change the active index, which forced
      callers to destroy and rebuild the whole window
      whenever the menu of choices changed.
    - NEW: process.poolStats() returns the live counts in
      each internal pool (jsval, jsobj, jsfn, jsprop,
      env). Useful for spotting refcount leaks before
      they exhaust the heap.
    - FIX: env_define, env_set and js_object_set print to
      stderr when js_alloc_property or PROP_SET_KEY's
      malloc fails. Previously the property simply
      didn't get added and the script saw "var
      undefined" with no clue why.
    - DOC: docs/limitations.html refreshed -- the entries
      claiming Array.prototype.sort is bubble sort and
      that fromCharCode writes only the low byte both
      pre-dated the 0.22.0 audit and were stale.

  0.22.0 (2026-04-30)
  Raw TCP, FTP client example
    - NEW: net.connect(host, port [, timeoutMs]) ? synchronous
      raw-TCP client. Returns a Socket object with .write(data)
      (String or Buffer), .read(maxLen) (Buffer), .readLine()
      (String, strips trailing CRLF, null on EOF), .close(),
      .isOpen() and .setTimeout(ms). Pool of 16 sockets;
      net_cleanup() closes any survivors on exit so fds don't
      leak across runs.
    - NEW: examples/gui_ftp_client.js ? minimal FTP client
      (passive mode) using the new net.connect. Supports
      directory listing, change-dir, upload, download, delete,
      mkdir. Blocks the GUI during transfers and shows
      progress in the status bar.
    - FIX: gui listview gadgets now keep the clicked row
      visually highlighted (GTLV_ShowSelected was missing,
      so the selection vanished on mouse-up).
    - FIX: socket.write now loops until every byte has left
      the socket (or fails). Bsdsocket's send() is allowed
      to return a short write -- the previous one-shot send
      would silently truncate uploads of files larger than
      a few kB.
    - FIX: socket.readLine drains the rest of an over-long
      line up to the next LF before returning, so the next
      readLine starts on a fresh record instead of picking
      up the truncated tail as a new line.
    - FIX: gui_ftp_client wraps every transfer in
      try/finally so a recv timeout / connection drop
      releases the data socket. After enough errors the
      pool of 16 sockets used to fill up and even reconnect
      would fail.
    - NEW: gui_ftp_client also parses Windows / IIS LIST
      output ("MM-DD-YY HH:MMxM <DIR>|size name") in
      addition to Unix-style ls -l listings.
    - FIX: amiga.pokeString accepts an optional maxLen
      argument and refuses to write past it. The old
      one-shot strcpy could clobber arbitrary memory if the
      caller miscounted the destination buffer.
    - FIX: lexer now reports "unterminated block comment"
      and "malformed exponent" (e.g. "1e" or "2.5e+") as
      proper syntax errors instead of silently swallowing
      them.
    - FIX: HTTP server reason phrase matches the status
      code -- res.writeHead(404) now sends "404 Not Found"
      rather than the previous hard-coded "404 OK".
    - FIX: child_process.execSync now captures stderr in
      addition to stdout (via SYS_Error) and returns an
      Error{code,stdout,stderr} value (instead of a string)
      on non-zero return code -- callers can branch on
      typeof out !== 'string'. exec(cmd, cb) passes a real
      Error to cb on failure. Temp files are per-Task so
      two NodeAmiga processes can run execSync concurrently
      without colliding.
    - FIX: fs.readFileSync rejects files over 16 MB so a
      bogus huge size from ftell can't take the process
      down with an unchecked malloc; returns undefined on
      that or on OOM, same as for "file not found".
    - PERF: Array.prototype.sort uses a stable merge sort
      instead of bubble sort -- O(n log n) where it used
      to be O(n^2). Several existing examples (Aminet
      browser, system monitor) sort hundreds of items.
    - SEC: HTTP redirects now reject any Location: target
      whose scheme isn't http://, https:// or a root path.
      A malicious server could previously hand back
      "Location: javascript:..." or "file:///..." which
      do_http_request would happily try to parse.
    - FIX: Buffer.from(str, 'hex') now stops at the first
      invalid character pair and returns the bytes decoded
      so far (matching Node's behaviour). Previously it
      silently substituted zero, corrupting the output.
    - FIX: String.fromCharCode no longer writes a NUL byte
      for codes >= 256. NodeAmiga strings are byte-based,
      so the function is hybrid: codes 0..255 stay a single
      raw byte (preserves charCodeAt round-trip and Latin-1
      Topaz display in libs like iff.js), codes >= 256 are
      encoded as multi-byte UTF-8. So
      String.fromCharCode(0x100) is now "?" (2 UTF-8 bytes)
      instead of "&#65533;".
    - FIX: String.fromCodePoint encodes the full Unicode
      range (0..0x10FFFF) as proper UTF-8, including 4-byte
      sequences for SMP code points. Out-of-range values
      coerce to U+FFFD.
    - FIX: JSON.parse now recognises UTF-16 surrogate pairs
      ("uD83DuDE00") and emits a single 4-byte UTF-8
      code point. Lone surrogates are still passed through
      as 3-byte UTF-8 for tolerance.
    - NEW: JSON.stringify accepts an array as the second
      argument (ES5 allowlist of property names). Numbers
      in the array are coerced to string keys; only
      matching object properties are emitted.
    - FIX: -compile bundler also collects modules pulled
      in via dynamic import("name") expressions, not just
      static require() and ESM `from`.
    - FIX: HTTP client now decodes Transfer-Encoding:
      chunked responses. Many HTTP/1.1 servers reply
      chunked even when our request says HTTP/1.0; the
      previous body parser handed back the raw "sizern
      datarnsizerndatarn0rnrn" sequence which
      JSON.parse, etc. obviously couldn't read. Decode is
      done in place (dechunked body is always <= chunked).
    - FIX: fs.readFile (async variant) gained the same
      ftell-< 0 / 16 MB cap guards as readFileSync; an
      oversize or unreadable file now surfaces through
      the callback with an Error rather than firing an
      unchecked malloc.
    - NEW: gui.alert(msg [,title]) and gui.confirm(msg
      [,title]) modal requesters via intuition's
      EasyRequest. confirm returns a boolean.
    - NEW: gui.prompt(msg [,default [,title]]) ? a small
      modal window with a string gadget; returns the
      entered text, or null on Cancel / close gadget /
      ESC. Enter on the field accepts. ESC cancels.
    - NEW: gui.beep() ? DisplayBeep on the default screen.
    - NEW: gui.colorRequest([initialPen]) ? pop a swatch
      grid sized to the current screen depth, click to
      pick a pen, ESC / close cancels (returns -1). Enter
      accepts the highlighted initial pen.
    - NEW: gui.setMenuItem(win, id, {disabled: bool}) ?
      enable or disable a menu item at runtime via
      OnMenu / OffMenu. Items are looked up by the `id`
      passed into setMenu().
    - NEW: gui.loadImage(path) / gui.freeImage(img) and
      gfx.drawImage(win, img, x, y [,w,h]) ? load any
      image format datatypes.library can decode (IFF,
      JPEG, PNG, GIF, ...) and blit to a window.
      Demoed in examples/gui_extra_demo.js.

  0.21.0 (2026-04-23)
  Bug fixes: lexer, await, iff, web runtime
    - FIX: Unterminated regex literal no longer silently
      returns a slash token; lexer now reports a proper
      syntax error (matches behavior of unterminated
      strings)
    - FIX: await on a Promise that never resolves within
      ~100s now throws Error instead of silently returning
      undefined (made debugging of hanging async code
      impossible)
    - FIX: libs/iff.js parse() and parseChunks() had
      duplicated chunk-walking logic; refactored so parse()
      delegates to parseChunks(), eliminating the fix-twice
      trap
    - FIX: addons/web drag handler installed three
      document-level listeners per opened window that were
      never removed on close (accumulating leak); enableDrag
      now returns a cleanup fn invoked on closeWindow
    - UPDATE: addons/web version bumped to 0.21.0-web
      (was lagging at 0.12.0)
    - NEW: online user documentation at
      http://juen.in/NodeAmiga/ covering the global API,
      all require() modules, the 44 bundled examples, and
      known limitations; link shown in -help / -v / REPL
      banner
    - FIX: compiled executables (-compile output) were left
      reported as "object in use" after running. The old
      compiler appended the JS bundle as raw bytes after a
      HUNK_BREAK marker, which caused LoadSeg to keep a
      Lock on the file alive past the process exit. Bundle
      is now embedded as a real HUNK_DATA hunk inside the
      executable: LoadSeg loads it like any other segment,
      UnLoadSeg releases it on exit, the file is no longer
      locked. Single-file output unchanged.
    - CHANGE: tree-walking interpreter is now the default.
      The bytecode VM still has open issues, so it is opt-in
      via --vm. --tree is kept as a no-op alias for the
      default; --debug always forces tree mode (debugger
      requires AST). When both --vm and --tree are passed,
      --vm wins.
    - FIX: gui.createWindow gadgets using percent or
      negative-anchor sizes (e.g. width: '50%', width: -8)
      could clip the window border or leave a gap on first
      open. The initial layout used the requested
      WA_InnerWidth/Height while subsequent resizes used the
      actual GZZWidth/Height -- if Intuition adjusted the
      inner area on open, the two layouts disagreed. Now if
      the actual inner area differs from what was requested,
      a single rebuild runs before the window goes
      interactive, so the first frame matches every later
      resize.
    - FIX: rebuild_gadgets restored an IDCMP mask that
      dropped IDCMP_MENUPICK and unconditionally added
      IDCMP_NEWSIZE -- so non-resizable windows started
      receiving spurious NEWSIZE handling, and resizing any
      window silently broke menu events. The mask now
      mirrors OpenWindowTagList exactly.

  0.20.0 (2026-04-17)
  Equality, Promise.finally, custom fonts
    - FIX: Strict equality 0 === "0" wrongly returned true with
      tagged ints (now correctly false)
    - FIX: Loose equality 0 == null wrongly returned true with
      tagged ints (now correctly false per spec)
    - FIX: typeof on tagged ints could crash (defensive check
      added in js_typeof)
    - FIX: Promise.finally() was implemented as .then(cb,cb)
      which dropped the original value -- now properly passes
      through resolved value or rejection reason
    - FIX: Promise.finally() use-after-free when callback
      threw (released thrown value before reject_promise
      could retain it)
    - NEW: String.prototype.toString() and valueOf() (were
      missing from prototype registration)
    - NEW: Number.prototype.valueOf()
    - NEW: gui.createWindow accepts font: { name, size }
      option for per-window fixed font (e.g. topaz.font 8 for
      proper column alignment in listviews)
    - aminet_browser.js v1.4: Recent button (browses
      /recent), Find renamed from Search All, version check
      on startup, custom topaz 8 font for column alignment

  0.19.0 (2026-04-16)
  FFI, area gadget, debugger
    - NEW: FFI module (require('amiga')) - call any Amiga library
      function from JavaScript
    - NEW: openLibrary/closeLibrary, call with register args
    - NEW: peek8/16/32, poke8/16/32, peekString, pokeString
    - NEW: allocMem/freeMem, makeTags for tag-based APIs
    - NEW: Area gadget (kind:'area') - clickable bevel box with
      gadgetdown/gadgetup/mousemove events
    - NEW: evt.x, evt.y mouse coordinates on gadget events
    - NEW: Debugger 'p' prints objects/arrays recursively
    - FIX: Scroller/slider gadgetup not firing (added
      GA_RelVerify + GA_Immediate tags)
    - FIX: Regex escape sequences (n, r, t, f, v, &#65533;)
    - FIX: aminet_browser.js eating 'r' chars from readme
    - FIX: VM hex/octal/binary clamped at 0x7FFFFFFF
    - FIX: VM OP_GET_PROP for Number.prototype methods
    - FIX: toString(radix) for values >= 2^31 on soft-float
    - FIX: double-to-ULONG in FFI for values > 0x7FFFFFFF

  0.18.1 (2026-04-14)
    - FIX: Scroller drag ID - switching between scrollers no
      longer emits stale IDs
    - FIX: Non-GZZ window gadget coords aligned with
      gfx.innerSize()
    - FIX: MOUSEMOVE identifies gadget from pointer, not from
      stale active_gad_id

  0.18.0 (2026-04-13)
    - NEW: Arrow keys, F1-F10, Help key events via IDCMP_RAWKEY
      (evt.key = "ArrowUp"/"ArrowDown"/"ArrowLeft"/"ArrowRight"/
      "F1".."F10"/"Help") -- both gui and intuition
    - NEW: Vertical scroller orientation (vertical:true)
    - NEW: gui.set() scroller accepts object
      {top, total, visible}
    - FIX: Duplicate key events prevented (RAWKEY filtered for
      VANILLAKEY codes)
    - FIX: Modifier keys filtered from RAWKEY
    - Example: gui_keyboard_and_scrolls.js

  0.17.0 (2026-04-12)
    - NEW: gui.gfx sub-module -- drawing primitives on GadTools
      windows: setColor, setBColor, setDrawMode, moveTo, lineTo,
      drawLine, drawRect, fillRect, drawCircle, fillCircle,
      drawEllipse, drawText, setPixel, getPixel, clear,
      innerSize, setFont, waitTOF
    - FIX: Intuition openWindow uses WA_InnerWidth/Height so
      dimensions match drawable area (was outer)
    - FIX: Intuition gfx.clear uses EraseRect (GZZ-safe) instead
      of SetRast
    - FIX: Intuition resize events update win.width/height
    - FIX: Intuition keypress includes 'key' property
    - Examples: gui_drawing.js, gui_gfx_clock.js


Credits
-------

  Juen/R3D+Appendix+Nah-Kolor






Copyright © 2004-2026 by Björn Hagström All Rights Reserved