]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Latest side-stream jaccwabyt/wasmutil.
authorstephan <stephan@noemail.net>
Sat, 22 Nov 2025 02:23:02 +0000 (02:23 +0000)
committerstephan <stephan@noemail.net>
Sat, 22 Nov 2025 02:23:02 +0000 (02:23 +0000)
FossilOrigin-Name: e0b33b51229a977cc3fa8a5a6c8ea59669f8bf566b2a6330fd24da1ad886a716

ext/wasm/common/whwasmutil.js
ext/wasm/jaccwabyt/jaccwabyt.js
ext/wasm/jaccwabyt/jaccwabyt.md
manifest
manifest.uuid

index 0d75675ca5f3e3efd4eb3eff172272193aebec14..bca05a1eefbb07c9472dde1ff656f4c774cce932 100644 (file)
 
   More specifically:
 
-  https://fossil.wanderinghorse.net/r/jaccwabyt/file/common/whwasmutil.js
+  https://fossil.wanderinghorse.net/r/jaccwabyt/dir/wasmutil
 
   and SQLite:
 
   https://sqlite.org
 
   This file is kept in sync between both of those trees.
+
+  This build was generated using:
+
+  ./c-pp -o js/whwasmutil.js -@policy=error wasmutil/whwasmutil.c-pp.js
+
+  by libcmpp 2.x 2fc4afc31f6505c27b9c34988973a2bd9b157d559247cdd26868ae75632c3a5e @ 2025-11-16 23:03:27.352 UTC
 */
 /**
-   The primary goal of this function is to replace, where possible,
-   Emscripten-generated glue code with equivalent utility code which
-   can be used in arbitrary WASM environments built with toolchains
-   other than Emscripten. To that end, it populates the given object
-   with various WASM-specific APIs. These APIs work with both 32- and
-   64-bit WASM builds.
+   The primary goal of this function is to provide JS/WASM utility
+   code similar to some of that provided by Emscripten-generated
+   builds, the difference being that this one can be used in arbitrary
+   WASM environments built with toolchains other than Emscripten. To
+   that end, it populates the given object with various WASM-specific
+   APIs. These APIs work with both 32- and 64-bit WASM builds.
 
    Forewarning: this API explicitly targets only browser environments.
    If a given non-browser environment has the capabilities needed for
    a given feature (e.g. TextEncoder), great, but it does not go out
    of its way to account for them and does not provide compatibility
-   crutches for them.
+   crutches for them. That said: no specific incompatibilities with,
+   e.g., node.js are known (whereas it is known that some folks
+   use this with node.js).
 
    Intended usage:
 
      newly-created (or config-provided) target. The current approach
      seemed better at the time.
 */
-globalThis.WhWasmUtilInstaller = function(target){
+'use strict';
+globalThis.WhWasmUtilInstaller =
+function WhWasmUtilInstaller(target){
   'use strict';
   if(undefined===target.bigIntEnabled){
     target.bigIntEnabled = !!globalThis['BigInt64Array'];
@@ -766,6 +776,7 @@ globalThis.WhWasmUtilInstaller = function(target){
   */
   target.uninstallFunction = function(ptr){
     if(!ptr && __NullPtr!==ptr) return undefined;
+
     const ft = target.functionTable();
     cache.freeFuncIndexes.push(ptr);
     const rc = ft.get(ptr);
@@ -2461,7 +2472,8 @@ globalThis.WhWasmUtilInstaller = function(target){
      - If `wasmUtilTarget.alloc` is not set and
        `instance.exports.malloc` is, it installs
        `wasmUtilTarget.alloc()` and `wasmUtilTarget.dealloc()`
-       wrappers for the exports `malloc` and `free` functions.
+       wrappers for the exports' `malloc` and `free` functions
+       if exports.malloc exists.
 
    It returns a function which, when called, initiates loading of the
    module and returns a Promise. When that Promise resolves, it calls
@@ -2484,7 +2496,9 @@ globalThis.WhWasmUtilInstaller = function(target){
    Error handling is up to the caller, who may attach a `catch()` call
    to the promise.
 */
-globalThis.WhWasmUtilInstaller.yawl = function(config){
+globalThis.WhWasmUtilInstaller
+.yawl = function yawl(config){
+  'use strict';
   const wfetch = ()=>fetch(config.uri, {credentials: 'same-origin'});
   const wui = this;
   const finalThen = function(arg){
@@ -2509,7 +2523,7 @@ globalThis.WhWasmUtilInstaller.yawl = function(config){
         tgt.alloc = function(n){
           return exports.malloc(n) || toss("Allocation of",n,"bytes failed.");
         };
-        tgt.dealloc = function(m){exports.free(m)};
+        tgt.dealloc = function(m){m && exports.free(m)};
       }
       wui(tgt);
     }
@@ -2528,4 +2542,6 @@ globalThis.WhWasmUtilInstaller.yawl = function(config){
         .then(finalThen)
   ;
   return loadWasm;
-}.bind(globalThis.WhWasmUtilInstaller)/*yawl()*/;
+}.bind(
+globalThis.WhWasmUtilInstaller
+)/*yawl()*/;
index 894c390ca783f9358621286db2c041a751a86afa..6fa86c34162b10933b9b0de65f8db42be4ac31cc 100644 (file)
   Project homes:
   - https://fossil.wanderinghorse.net/r/jaccwabyt
   - https://sqlite.org/src/dir/ext/wasm/jaccwabyt
+
+  This build was generated using:
+
+  ./c-pp -o js/jaccwabyt.js -@policy=error jaccwabyt/jaccwabyt.c-pp.js
+
+  by libcmpp 2.x 2fc4afc31f6505c27b9c34988973a2bd9b157d559247cdd26868ae75632c3a5e @ 2025-11-16 23:03:27.352 UTC
 */
 'use strict';
-globalThis.Jaccwabyt = function StructBinderFactory(config){
+globalThis.Jaccwabyt =
+function StructBinderFactory(config){
+  'use strict';
 /* ^^^^ it is recommended that clients move that object into wherever
    they'd like to have it and delete the globalThis-held copy.  This
    API does not require the global reference - it is simply installed
@@ -65,18 +73,20 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
 
   //console.warn("config",config);
   let ptr;
-  const ptrIR = config.pointerIR
+  const ptrSize = config.pointerSize
+        || config.ptrSize/*deprecated*/
+        || ('bigint'===typeof (ptr = alloc(1)) ? 8 : 4);
+  const ptrIR = config.pointerIR/*deprecated*/
         || config.ptrIR/*deprecated*/
-        || ('bigint'===typeof (ptr = alloc(1)) ? 'i64' : 'i32');
-  /* Undocumented (on purpose) config options: */
-  const ptrSize = config.ptrSize/*deprecated*/
-        || ('i32'===ptrIR ? 4 : 8);
-  dealloc(ptr);
-  ptr = undefined;
+        || (4===ptrSize ? 'i32' : 'i64');
+  if( ptr ){
+    dealloc(ptr);
+    ptr = undefined;
+  }
   //console.warn("ptrIR =",ptrIR,"ptrSize =",ptrSize);
 
-  if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
   if(ptrSize!==4 && ptrSize!==8) toss("Invalid pointer size:",ptrSize);
+  if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
 
   /** Either BigInt or, if !bigIntEnabled, a function which
       throws complaining that BigInt is not enabled. */
@@ -853,6 +863,8 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
   }/*makeMemberStructWrapper()*/;
 
   /**
+     This is where most of the magic happens.
+
      Pass this a StructBinderImpl-generated constructor, a member
      property name, and the struct member description object. It will
      define property accessors for proto[memberKey] which read
@@ -936,7 +948,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
         }
         if(!this.pointer){
           toss("Cannot set native property on a disposed",
-               this.structSame,"instance.");
+               this.structName,"instance.");
         }
         if( setterProxy ) v = setterProxy.apply(this,[key,v]);
         if( null===v || undefined===v ) v = __NullPtr;
index 5ec3151d505a8bf7aa64bf0305b26d69c178dd6f..5c30268e89e93d8dbe32e53040d567efbff1cc00 100644 (file)
@@ -12,6 +12,35 @@ friction.
 
 (If that means nothing to you, neither will the rest of this page!)
 
+To the best of its creator's fallible knowledge, Jaccwabyt is the only
+library of its kind (as of 2025-11). Aside from wrapping existing
+structs, e.g. to integrate "legacy" C code into JS/WASM, it can also
+model C structs without requiring a native C counterpart, a feature
+which probably has only exceedingly obscure uses in JS-side
+implementations for native callbacks.
+
+How it works:
+
+- The client provides a JSON-friendly description of a C struct,
+  describing the names, sizes, and offsets of each member.
+- Pass that description to a factory function to create
+  a JS constructor for that C struct.
+- That constructor allocates a block of heap memory of the C struct's
+  size and maps it to the new JS-side struct instance.  Each instance
+  inherits property interceptors for each struct member, such that
+  fetching the C struct's members reads directly from the struct's
+  memory and setting them writes to that memory. Similarly, these
+  objects can be provided with memory constructed elsewhere, e.g.
+  a struct pointer returned from a WASM function, and can proxy
+  that memory via the struct's interface.
+- Clients eventually call the `dispose()` method to free the
+  instance's heap memory and disassociate the JS instance with its
+  WASM-side resources.
+
+Easy peasy!
+
+**Build instructions**: [see Appendix B](#appendix-b).
+
 **Browser compatibility**: this library requires a _recent_ browser
 and makes no attempt whatsoever to accommodate "older" or
 lesser-capable ones, where "recent," _very roughly_, means released in
@@ -25,7 +54,10 @@ are based solely on feature compatibility tables provided at
 
 **Non-browser compatibility**: this code does not target non-browser
 JS engines and is completely untested on them. That said, it "might
-work".
+work". These JS APIs do not use the DOM API in any way, so are not
+specifically tied to a browser, but they _are_ fully untested in such
+environments. This code is known to work with both [Emscripten][] builds
+and [WASI-SDK][] SDK builds (at of this writing, 2025-11-08).
 
 **64-bit WASM:** as of 2025-09-21 this API supports 64-bit WASM builds
 but it has to be configured for it (see [](#api-binderfactory) for
@@ -57,7 +89,7 @@ project was spawned:
 
 -----
 
-<a name='overview'></a>
+<a id='overview'></a>
 Table of Contents
 ============================================================
 
@@ -72,16 +104,18 @@ Table of Contents
 - APIs
   - [Struct Binder Factory](#api-binderfactory)
   - [Struct Binder](#api-structbinder)
-  - [Struct Type](#api-structtype)
+     - [Struct Description Objects](#struct-descr)
+- [Struct Type](#api-structtype)
   - [Struct Constructors](#api-structctor)
   - [Struct Protypes](#api-structprototype)
   - [Struct Instances](#api-structinstance)
 - Appendices
   - [Appendix A: Limitations, TODOs, etc.](#appendix-a)
+  - [Appendix B: Build](#appendix-b)
   - [Appendix D: Debug Info](#appendix-d)
   - [Appendix G: Generating Struct Descriptions](#appendix-g)
 
-<a name='overview'></a>
+<a id='overview'></a>
 Overview
 ============================================================
 
@@ -114,15 +148,16 @@ Portability notes:
   because it is the most widespread WASM toolchain, but this code is
   specifically designed to be usable in arbitrary WASM environments.
   It abstracts away a few Emscripten-specific features into
-  configurable options. Similarly, the build tree requires Emscripten
-  but Jaccwabyt does not have any hard Emscripten dependencies.
+  configurable options. The build tree supports both [Emscripten][]
+  and [WASI-SDK][] to demonstrate that it has no dependencies on
+  either.
 - This code is encapsulated into a single JavaScript function. It
   should be trivial to copy/paste into arbitrary WASM/JS-using
   projects.
 - The source tree includes C code, but only for testing and
-  demonstration purposes. It is not part of the core distributable.
+  demonstration purposes. It is not a core distributable.
 
-<a name='architecture'></a>
+<a id='architecture'></a>
 Architecture
 ------------------------------------------------------------
 
@@ -156,9 +191,10 @@ Its major classes and functions are:
   an appropriate configuration, to generate a single...
 - **[StructBinder][]** is a factory function which converts an
   arbitrary number struct descriptions into...
-- **[StructTypes][StructCtors]** are constructors, one per struct
+- **[StructType][]** are [constructors][StructCtor], one per struct
   description, which inherit from
-  **[`StructBinder.StructType`][StructType]** and are used to instantiate...
+  **[`StructBinder.StructType`][StructType]** and are used to
+  instantiate...
 - **[Struct instances][StructInstance]** are objects representing
   individual instances of generated struct types.
 
@@ -167,7 +203,7 @@ need only one. Each StructBinder is effectively a separate
 namespace for struct creation.
 
 
-<a name='creating-binding'></a>
+<a id='creating-binding'></a>
 Creating and Binding Structs
 ============================================================
 
@@ -190,7 +226,7 @@ essentially boils down to:
 
 Detailed instructions for each of those steps follows...
 
-<a name='step-1'></a>
+<a id='step-1'></a>
 Step 1: Configure Jaccwabyt for the Environment
 ------------------------------------------------------------
 
@@ -208,7 +244,7 @@ const MyBinder = StructBinderFactory({
         a Uint8Array or Int8Array view of the WASM memory,
   alloc:   function(howMuchMemory){...},
   dealloc: function(pointerToFree){...},
-  pointerIR: 'i32' or 'i64' // WASM pointer type - default = 'i32'
+  pointerSize: 4 or 8 // WASM pointer size
 });
 ```
 
@@ -234,7 +270,7 @@ a conventional Emscripten setup, that config might simply look like:
 The StructBinder factory function returns a function which can then be
 used to create bindings for our structs.
 
-<a name='step-2'></a>
+<a id='step-2'></a>
 Step 2: Create a Struct Description
 ------------------------------------------------------------
 
@@ -267,100 +303,9 @@ Its JSON description looks like:
 }
 ```
 
-These data _must_ match up with the C-side definition of the struct
-(if any). See [Appendix G][appendix-g] for one way to easily generate
-these from C code.
-
-Each entry in the `members` object maps the member's name to
-its low-level layout:
-
-- `offset`: the byte offset from the start of the struct, as reported
-  by C's `offsetof()` feature.
-- `sizeof`: as reported by C's `sizeof()`.
-- `signature`: described below.
-- `readOnly`: optional. If set to true, the binding layer will
-  throw if JS code tries to set that property.
-
-The order of the `members` entries is not important: their memory
-layout is determined by their `offset` and `sizeof` members. The
-`name` property is technically optional, but one of the steps in the
-binding process requires that either it be passed an explicit name or
-there be one in the struct description. The names of the `members`
-entries need not match their C counterparts. Project conventions may
-call for giving them different names in the JS side and the
-[StructBinderFactory][] can be configured to automatically add a
-prefix and/or suffix to their names.
-
-Nested structs are as-yet unsupported by this tool.
+This is described in more detail in [][StructBinder].
 
-Struct member "signatures" describe the data types of the members and
-are an extended variant of the format used by Emscripten's
-`addFunction()`. A signature for a non-function-pointer member, or
-function pointer member which is to be modelled as an opaque pointer,
-is a single letter. A signature for a function pointer may also be
-modelled as a series of letters describing the call signature. The
-supported letters are:
-
-- **`v`** = `void` (only used as return type for function pointer members)
-- **`i`** = `int32` (4 bytes)
-- **`j`** = `int64` (8 bytes) is only really usable if this code is built
-  with BigInt support (e.g. using the Emscripten `-sWASM_BIGINT` build
-  flag). Without that, this API may throw when encountering the `j`
-  signature entry.
-- **`f`** = `float` (4 bytes)
-- **`d`** = `double` (8 bytes)
-- **`c`** = `int8` (1 byte) char - see notes below!
-- **`C`** = `uint8` (1 byte) unsigned char - see notes below!
-- **`p`** = `int32` (see notes below!)
-- **`P`** = Like `p` but with extra handling. Described below.
-- **`s`** = like `int32` but is a _hint_ that it's a pointer to a
-  string so that _some_ (very limited) contexts may treat it as such,
-  noting that such algorithms must, for lack of information to the
-  contrary, assume both that the encoding is UTF-8 and that the
-  pointer's member is NUL-terminated. If that is _not_ the case for a
-  given string member, do not use `s`: use `i` or `p` instead and do
-  any string handling yourself.
-
-Noting that:
-
-- **All of these types are numeric**. Attempting to set any
-  struct-bound property to a non-numeric value will trigger an
-  exception except in cases explicitly noted otherwise.
-- **"Char" types**: WASM does not define an `int8` type, nor does its
-  JS representation distinguish between signed and unsigned. This API
-  treats `c` as `int8` and `C` as `uint8` for purposes of getting and
-  setting values when using the `DataView` class. It is _not_
-  recommended that client code use these types in new WASM-capable
-  code, but they were added for the sake of binding some immutable
-  legacy code to WASM.
-
-> Sidebar: Emscripten's public docs do not mention `p`, but their
-generated code includes `p` as an alias for `i`, presumably to mean
-"pointer". Though `i` is legal for pointer types in the signature, `p`
-is more descriptive, so this framework encourages the use of `p` for
-pointer-type members. Using `p` for pointers also helps future-proof
-the signatures against the eventuality that WASM eventually supports
-64-bit pointers. Note that sometimes `p` _really_ means a
-pointer-to-pointer. We simply have to be aware of when we need to deal
-with pointers and pointers-to-pointers in JS code.
-
-> Trivia: this API treates `p` as distinctly different from `i` in
-some contexts, so its use is encouraged for pointer types.
-
-Signatures in the form `x(...)` denote function-pointer members and
-`x` denotes non-function members. Functions with no arguments use the
-form `x()`. For function-type signatures, the strings are formulated
-such that they can be passed to Emscripten's `addFunction()` after
-stripping out the `(` and `)` characters. For good measure, to match
-the public Emscripten docs, `p`, `c`, and `C`, should also be replaced
-with `i`. In JavaScript that might look like:
-
->  
-```
-signature.replace(/[^vipPsjfdcC]/g,'').replace(/[pPscC]/g,'i');
-```
-
-<a name='step-2-pvsp'></a>
+<a id='step-2-pvsp'></a>
 ### `P` vs `p` in Method Signatures
 
 *This support is experimental and subject to change.*
@@ -379,7 +324,7 @@ stored in `myStruct.x`. If `y` is neither a pointer nor a
 or `P` is used).
 
 
-<a name='step-3'></a>
+<a id='step-3'></a>
 Step 3: Binding the Struct
 ------------------------------------------------------------
 
@@ -402,7 +347,7 @@ simplify certain later operations. If that is not desired, then feed
 it a copy of the original, e.g. by passing it
 `JSON.parse(JSON.stringify(structDefinition))`.
 
-<a name='step-4'></a>
+<a id='step-4'></a>
 Step 4: Creating, Using, and Destroying Struct Instances
 ------------------------------------------------------------
 
@@ -461,11 +406,11 @@ Now that we have struct instances, there are a number of things we
 can do with them, as covered in the rest of this document.
 
 
-<a name='api'></a>
+<a id='api'></a>
 API Reference
 ============================================================
 
-<a name='api-binderfactory'></a>
+<a id='api-binderfactory'></a>
 API: Binder Factory
 ------------------------------------------------------------
 
@@ -480,14 +425,14 @@ Function StructBinderFactory(object configOptions);
 It returns a function which these docs refer to as a [StructBinder][]
 (covered in the next section). It throws on error.
 
-The binder factory supports the following options in its
-configuration object argument:
+The binder factory supports the following options in its configuration
+object argument:
 
-- `pointerIR` (Added 2025-09-21)  
-  Optionally specify the WASM pointer size with the string `'i32'` or
-  `'i64'`, defaulting to the former. When using with 64-bit WASM
-  builds, this must be set to `'i64'` by the client. Any other value
-  triggers an exception.
+- `pointerSize` (Added 2025-11-15 to replace `pointerIR`)  
+  Optionally specify the WASM pointer size of 4 (32-bit) or 8
+  (64-bit).  Any other truthy value triggers an exception. If
+  `pointerSize` is not set then it will guess the size by `alloc()`ing
+  one byte, checking the result type, and `dealloc()`ing it.
 
 - `heap`  
   Must be either a `WebAssembly.Memory` instance representing the WASM
@@ -498,21 +443,24 @@ configuration object argument:
   for the WASM heap to grow at runtime.
 
 - `alloc`  
-  Must be a function semantically compatible with Emscripten's
-  `Module._malloc()`. That is, it is passed the number of bytes to
-  allocate and it returns a pointer. On allocation failure it may
-  either return 0 or throw an exception. This API will throw an
-  exception if allocation fails or will propagate whatever exception
-  the allocator throws. The allocator _must_ use the same heap as the
-  `heap` config option.
+  Must be a function semantically compatible with C's
+  `malloc(3)`. That is, it is passed the number of bytes to allocate
+  and it returns a pointer. On allocation failure it may either return
+  0 or throw an exception. This API will throw an exception if
+  allocation fails or will propagate whatever exception the allocator
+  throws. The allocator _must_ use the same heap as the `heap` config
+  option.
 
 - `dealloc`  
-  Must be a function semantically compatible with Emscripten's
-  `Module._free()`. That is, it takes a pointer returned from
-  `alloc()` and releases that memory. It must never throw and must
-  accept a value of 0/null to mean "do nothing" (noting that 0 is
-  _technically_ a legal memory address in WASM, but that seems like a
-  design flaw).
+  Must be a function semantically compatible with C's `free(3)`. That
+  is, it takes a pointer returned from `alloc()` and releases that
+  memory. It must never throw and must accept a value of 0/null to
+  mean "do nothing".
+
+- `realloc`  
+  Optional but required for (eventual (and optional) realloc support
+  of structs. If set, it must be a function semantically compatible
+  with C's `realloc()`. See `alloc`, above, for other requirements.
 
 - `bigIntEnabled` (bool=true if BigInt64Array is available, else false)  
   If true, the WASM bits this code is used with must have been
@@ -542,13 +490,13 @@ configuration object argument:
   (like `console.debug` does). See [Appendix D](#appendix-d) for info
   about enabling debugging output.
 
-<a name='api-structbinder'></a>
+<a id='api-structbinder'></a>
 API: Struct Binder
 ------------------------------------------------------------
 
 Struct Binders are factories which are created by the
 [StructBinderFactory][].  A given Struct Binder can process any number
-of distinct structs. In a typical setup, an app will have ony one
+of distinct structs. In a typical setup, an app will have only one
 shared Binder Factory and one Struct Binder. Struct Binders which are
 created via different [StructBinderFactory][] calls are unrelated to each
 other, sharing no state except, perhaps, indirectly via
@@ -568,7 +516,7 @@ The returned object is a constructor for instances of the struct
 described by its argument(s), each of which derives from
 a separate [StructType][] instance.
 
-The Struct Binder has the following members:
+StructBinder has the following members:
 
 - `allocCString(str)`  
   Allocates a new UTF-8-encoded, NUL-terminated copy of the given JS
@@ -583,7 +531,221 @@ The Struct Binder has the following members:
   any of its "significant" configuration values may have undefined
   results.
 
-<a name='api-structtype'></a>
+- `adaptGet(key [,func])`  
+  Gets or sets a "get adaptor" by name - an arbitrary client-defined
+  string, e.g. `"to-js-string"`. Struct description objects may have
+  their `adaptGet` property set to the name of a mapped getter to
+  behave exactly as if that struct description had set the given
+  function as its `get` property. This offers a JSON-friendly way of
+  storing adaptor mappings, with the caveat that the adaptors need to
+  be defined _somewhere_ outside of JSON (typically it should be done
+  immediately after creating the StructBinder).
+
+- `adaptSet(key [,func])`  
+  The "set" counterpart of `adaptGet`.
+
+- `ptrAdd(...)`  
+  Coerces all of its arguments to the WASM pointer type, adds them
+  together, and returns a result of that same type.  This is a
+  workaround for mixed-BigInt/Number pointer math being illegal in JS.
+
+The `structDescription` argument is described in detail in the
+following section.
+
+<a id='struct-descr'></a>
+### Struct Description Object
+
+C structs are described in a JSON-friendly format:
+
+>  
+```json
+{
+  "name": "MyStruct",
+  "sizeof": 16,
+  "members": {
+    "member1": {"offset": 0,"sizeof": 4,"signature": "i"},
+    "member2": {"offset": 4,"sizeof": 4,"signature": "p"},
+    "member3": {"offset": 8,"sizeof": 8,"signature": "j"}
+  }
+}
+```
+
+Forewarning: these data _must_ match up with the C-side definition of
+the struct (if any). See [Appendix G][appendix-g] for one way to
+easily generate these from C code.
+
+Every struct must have a `sizeof`. (Though we _could_ calculate it
+based on the list of members, we don't. Actually, we do, then we throw
+if the values don't match up.) The `name` is required as well but it
+may optionally be passed as the first argument to
+`StructBinder(structName,structDescription)`. the `name` property
+represents the member's symbolic name, typically its native name.
+
+Abstractly speaking, a struct description in an object with the
+properties `sizeof`, `offset`, and either `signature` _or_
+`member`. `offset` is optional only in the top-most object of a struct
+description. Every sub-object (a.k.a. member description object)
+requires the `offset` property.
+
+Member description objects are those in the `members` property:
+
+`"members": {"memberName": {...member description...}, ...}`
+
+A struct description which has its own `members` object represents a
+nested struct, with an identical description syntax to that of a
+top-level struct except that nested structs require an `offset`
+property.
+
+Each entry in a struct/member description object maps the member's
+name to its low-level layout and other metadata:
+
+- `offset`  
+  The byte offset from the start of the struct, as reported by C's
+  `offsetof()` feature. For nested structs's members, this value is
+  relative to the nested struct, not the parent struct.
+- `sizeof`  
+  As reported by C's `sizeof()`.
+- `signature`  
+  A type-id signature for this member. Described below.
+- `readOnly [=false]`  
+  Optional boolean. If set to true, the binding layer will throw if JS
+  code tries to set that property.
+- `zeroOnDispose [=false]`  
+  If true, then the library will zero out the memory of instances of
+  this struct when their `dispose()` method is called. Because
+  `StructType.dispose()` does not free instances which wrap
+  externally-provided memory, those instances are not wiped when
+  disposed (doing so would likely interfere with other users of that
+  memory). (There is no need for a `zeroOnAlloc` counterpart because
+  newly-allocated instances are always zero-filled for sanity's
+  sake.)
+- `members`  
+  This object describes the individual struct members, mapping their
+  names to a member description object. `members` gets processed
+  recursively. Any member with its own `members` property is a
+  nested-struct, and the property accessor for such members will
+  return an instance of the distinct StructType which wraps that
+  member's native memory.  
+  Nested-struct members cannot be assigned over. `signature` is
+  illegal if `members` is set.
+- `get`  
+  Optional function. When fetching this member, this getter is passed
+  `(K,V)`, where `K` is the struct member's key and `V` is the
+  _native_ value. `get()`'s return value becomes the value of the
+  property access operation. This enables custom "native-to-JS"
+  conversions. If the member is a nested struct, the value passed to
+  the getter is a StructType proxy object which provides access to its
+  own members, a subset of the parent object's memory. In the context
+  of the getter call, "this" is the object upon which the get is being
+  performed.
+- `set`  
+  Optional function. When setting this member, this setter is passed
+  `(K,V)`, where `K` is the struct member's key and `V` is the _JS_
+  value the property is being assigned to. The `set()` return value is
+  assigned to the _native_ struct member.  Thus `set()` _must_ return
+  an appropriate numeric value and can perform "JS-to-native"
+  conversions. `set` is not currently legal for nested struct values,
+  but it is on their own non-nested-struct members. In the context of
+  the setter call, "this" is the object upon which the set is being
+  performed.
+- `adaptGet` and `adaptSet`  
+  JSON-friendly variants of `get` and `set`. Each may be assigned a
+  string value, and each such string must be mapped with
+  `StructBinder.adaptGet(key,func)`
+  resp. `StructBinder.adaptSet(key,func)`. With that in place, these
+  behave like `get` resp. `set`.
+- `structName`  
+  Optional descriptive name, possibly distinct from the `name`,
+  primarily used for nested structs. The intent is that this be some
+  form of the struct type's name, optionally with leading parts of
+  this object is a nested struct.
+- `name`  
+  Is usually optional, and is always optional in `members` entries
+  because their name is conveniently derived from their containing
+  object. `name` must be provided only for the top-most struct. The
+  intent is that `name` maps to the member's property name and that
+  `structName` optionally be set for nested structs (it will be
+  derived from the name if it's not set).
+
+The order of the `members` entries is not important: their memory
+layout is determined by their `offset` and `sizeof` members. The
+`name` property is technically optional, but one of the steps in the
+binding process requires that either it be passed an explicit name or
+there be one in the struct description. The names of the `members`
+entries need not match their C counterparts. Project conventions may
+call for giving them different names in the JS side and the
+[StructBinderFactory][] can be configured to automatically add a
+prefix and/or suffix to their names.
+
+Struct member "signatures" describe the data types of the members and
+are an extended variant of the format used by Emscripten's
+`addFunction()`. A signature for a non-function-pointer member, or
+function pointer member which is to be modelled as an opaque pointer,
+is a single letter. A signature for a function pointer may also be
+modelled as a series of letters describing the call signature. The
+supported letters are:
+
+- **`v`** = `void` (only used as return type for function pointer members)
+- **`i`** = `int32` (4 bytes)
+- **`j`** = `int64` (8 bytes) is only really usable if this code is built
+  with BigInt support (e.g. using the Emscripten `-sWASM_BIGINT` build
+  flag). Without that, this API may throw when encountering the `j`
+  signature entry.
+- **`f`** = `float` (4 bytes)
+- **`d`** = `double` (8 bytes)
+- **`c`** = `int8` (1 byte) char - see notes below!
+- **`C`** = `uint8` (1 byte) unsigned char - see notes below!
+- **`p`** = `int32` (see notes below!)
+- **`P`** = Like `p` but with extra handling. Described below.
+- **`s`** = like `int32` but is a _hint_ that it's a pointer to a
+  string so that _some_ (very limited) contexts may treat it as such,
+  noting that such algorithms must, for lack of information to the
+  contrary, assume both that the encoding is UTF-8 and that the
+  pointer's member is NUL-terminated. If that is _not_ the case for a
+  given string member, do not use `s`: use `i` or `p` instead and do
+  any string handling yourself.
+
+Noting that:
+
+- **All of these types are numeric**. Attempting to set any
+  struct-bound property to a non-numeric value will trigger an
+  exception except in cases explicitly noted otherwise.
+- **"Char" types**: WASM does not define an `int8` type, nor does its
+  JS representation distinguish between signed and unsigned. This API
+  treats `c` as `int8` and `C` as `uint8` for purposes of getting and
+  setting values when using the `DataView` class. It is _not_
+  recommended that client code use these types in new WASM-capable
+  code, but they were added for the sake of binding some immutable
+  legacy code to WASM.
+
+> Sidebar: Emscripten's public docs do not mention `p`, but their
+generated code includes `p` as an alias for `i`, presumably to mean
+"pointer". Though `i` is legal for pointer types in the signature, `p`
+is more descriptive, so this framework encourages the use of `p` for
+pointer-type members. Using `p` for pointers also helps future-proof
+the signatures against the eventuality that WASM eventually supports
+64-bit pointers. Note that sometimes `p` _really_ means a
+pointer-to-pointer. We simply have to be aware of when we need to deal
+with pointers and pointers-to-pointers in JS code.
+
+> Trivia: this API treates `p` as distinctly different from `i` in
+some contexts, so its use is encouraged for pointer types.
+
+Signatures in the form `x(...)` denote function-pointer members and
+`x` denotes non-function members. Functions with no arguments use the
+form `x()`. For function-type signatures, the strings are formulated
+such that they can be passed to Emscripten's `addFunction()` after
+stripping out the `(` and `)` characters. For good measure, to match
+the public Emscripten docs, `p`, `c`, and `C`, should also be replaced
+with `i`. In JavaScript that might look like:
+
+>  
+```
+signature.replace(/[^vipPsjfdcC]/g,'').replace(/[pPscC]/g,'i');
+```
+
+
+<a id='api-structtype'></a>
 API: Struct Type
 ------------------------------------------------------------
 
@@ -598,7 +760,7 @@ config options.
 
 The StructType constructor cannot be called from client code. It is
 only called by the [StructBinder][]-generated
-[constructors][StructCtors]. The `StructBinder.StructType` object
+[constructors][StructCtor]. The `StructBinder.StructType` object
 has the following "static" properties (^Which are accessible from
 individual instances via `theInstance.constructor`.):
 
@@ -608,7 +770,8 @@ individual instances via `theInstance.constructor`.):
   a function-typed `ondispose` property, this call replaces it with an
   array and moves that function into the array. In all other cases,
   `ondispose` is assumed to be an array and the argument(s) is/are
-  appended to it. Returns `this`.
+  appended to it. Returns `this`. See `dispose()`, below, for where
+  this applies.
 
 - `allocCString(str)`  
   Identical to the [StructBinder][] method of the same name.
@@ -616,7 +779,7 @@ individual instances via `theInstance.constructor`.):
 - `hasExternalPointer(object)`  
   Returns true if the given object's `pointer` member refers to an
   "external" object. That is the case when a pointer is passed to a
-  [struct's constructor][StructCtors]. If true, the memory is owned by
+  [struct's constructor][StructCtor]. If true, the memory is owned by
   someone other than the object and must outlive the object.
 
 - `isA(value)`  
@@ -633,7 +796,7 @@ individual instances via `theInstance.constructor`.):
 
 The base StructType prototype has the following members, all of which
 are inherited by [struct instances](#api-structinstance) and may only
-legally be called on concrete struct instances unless noted otherwise:
+legally be used with concrete struct instances unless noted otherwise:
 
 - `dispose()`  
   Frees, if appropriate, the WASM-allocated memory which is allocated
@@ -641,11 +804,11 @@ legally be called on concrete struct instances unless noted otherwise:
   cleans up the object, a leak in the WASM heap memory pool will result.  
   When `dispose()` is called, if the object has a property named `ondispose`
   then it is treated as follows:  
-  - If it is a function, it is called with the struct object as its `this`.
-  That method must not throw - if it does, the exception will be
-  ignored.
+  - If it is a function, it is called with the struct object as its
+    `this`.  That method must not throw - if it does, the exception
+    will be ignored.
   - If it is an array, it may contain functions, pointers, other
-    [StructType] instances, and/or JS strings. If an entry is a
+    [StructType][] instances, and/or JS strings. If an entry is a
     function, it is called as described above. If it's a number, it's
     assumed to be a pointer and is passed to the `dealloc()` function
     configured for the parent [StructBinder][]. If it's a
@@ -655,7 +818,12 @@ legally be called on concrete struct instances unless noted otherwise:
     supported primarily for use as debugging information.
   - Some struct APIs will manipulate the `ondispose` member, creating
     it as an array or converting it from a function to array as
-    needed.
+    needed. Most simply, `addOnDispose()` is used to manipulate the
+    on-dispose data.
+
+- `extraBytes` (integer, read-only)  
+  If this instance was allocated with the `extraBytes` option, this is
+  that value, else it is 0.
 
 - `lookupMember(memberName,throwIfNotFound=true)`  
   Given the name of a mapped struct member, it returns the member
@@ -708,6 +876,19 @@ legally be called on concrete struct instances unless noted otherwise:
   the struct will invalidate older serialized data and (B) serializing
   member pointers is useless.
 
+- `pointer` (number, read-only)  
+  A read-only numeric property which is the "pointer" returned by the
+  configured allocator when this object is constructed. After
+  `dispose()` (inherited from [StructType][]) is called, this property
+  has the `undefined` value. When calling C-side code which takes a
+  pointer to a struct of this type, simply pass it `myStruct.pointer`.
+  Whether this member is of type Number or BigInt depends on whether
+  the WASM environment is 32-bit (Number) or 64-bit (BigInt).
+
+- `ptrAdd(args...)`  
+  Equivalent to [StructBinder][]`.ptrAdd(this.pointer, args...)`
+  or [StructCtor][]`.ptrAdd(this.pointer, args...)`.
+
 - `setMemberCString(memberName,str)`  
   Uses `StructType.allocCString()` to allocate a new C-style string,
   assign it to the given member, and add the new string to this
@@ -725,9 +906,13 @@ legally be called on concrete struct instances unless noted otherwise:
   from JS be kept to a minimum or that the relationship be one-way:
   let C manage the strings and only fetch them from JS using, e.g.,
   `memberToJsString()`.
-  
 
-<a name='api-structctor'></a>
+- `zeroOnDispose` (bool, read-only)  
+  True if this instance or its prototype were configured with
+  the `zeroOnDispose` flag.
+
+
+<a id='api-structctor'></a>
 API: Struct Constructors
 ------------------------------------------------------------
 
@@ -741,29 +926,90 @@ const x = new MyStruct;
 ```
 
 Normally they should be passed no arguments, but they optionally
-accept a single argument: a WASM heap pointer address of memory
-which the object will use for storage. It does _not_ take over
-ownership of that memory and that memory must be valid at
-for least as long as this struct instance. This is used, for example,
-to proxy static/shared C-side instances:
+accept a single argument: a WASM heap pointer address of memory which
+the object will use for storage. It does _not_ take over ownership of
+that memory and that memory must remain valid for at least as long as
+this struct instance. This is used, for example, to proxy
+static/shared C-side instances or those which we simply want to
+get access to via this higher-level API for a while:
 
 >  
 ```
 const x = new MyStruct( someCFuncWhichReturnsAMyStructPointer() );
 ...
-x.dispose(); // does NOT free the memory
+x.dispose(); // does NOT free or zero the memory
 ```
 
 The JS-side construct does not own the memory in that case and has no
 way of knowing when the C-side struct is destroyed. Results are
 specifically undefined if the JS-side struct is used after the C-side
-struct's member is freed.
+struct's member is freed. However, if the client has allocated that
+memory themselves and wants to transfer ownership of it to the
+instance, that can be done with:
+
+>  
+```
+x.addOnDispose( thePtr );
+```
+
+Which will free `thePtr` when `x.dispose()` is called.
+
+As of 2025-11-10, a third option is available:
 
-> Potential TODO: add a way of passing ownership of the C-side struct
-to the JS-side object. e.g. maybe simply pass `true` as the second
-argument to tell the constructor to take over ownership. Currently the
-pointer can be taken over using something like
-`myStruct.ondispose=[myStruct.pointer]` immediately after creation.
+>  
+```
+const x = new MyStruct({
+  wrap: ptr,            // as per MyStruct(ptr)
+  takeOwnership: bool,  // If true, take ownership of the wrap ptr.
+  zeroOnDispose: bool , // if true, overrides MyStruct.structInfo.zeroOnDispose
+  extraBytes: int       // bytes to alloc after the end of the struct
+});
+```
+
+- If `wrap` is set then (A) it must be at least
+  `MyStruct.structInfo.sizeof` of memory owned by the caller, (B) it
+  _must_ have been allocated using the same allocator as Jaccwabyt is
+  configured for, and (C) ownership of it is transfered to the new
+  object. `zeroOnDispose` and `extraBytes` are disregarded if `wrap`
+  is set. A falsy `wrap` value is equivalent to not providing one and
+  a non-integer value, or a number less than 0, triggers an error.
+
+- If `takeOwnership` is truthy then this object takes over ownership
+  of the `wrap` pointer (if any). This flag is otherwise ignored.
+
+- If `zeroOnDispose` or `extraBytes` are are used without `wrap`, each
+  which is used is set as a read-only propperty on the resulting
+  `MyStruct` object, except that `zeroOnDispose` is only recorded if
+  it is truthy and `extraBytes` is only recorded if it is not 0 (a
+  negative value, or non-integer, triggers an exception).
+
+- `ondispose`: if set it is passed to the new object's
+  `addOnDispose()` before the constructor returns, so may have any
+  value legal for that method. Results are undefined if `ondispose`
+  and `wrap` have the same pointer value (because `wrap` will already
+  be cleaned up via `dispose()`, as if it had been passed to
+  `addOnDispose()`).
+
+In the case of `extraBytes`, a pointer to the tail of the memory can
+be obtained by adding `theInstance.pointer` to
+`theInstance.structInfo.sizeof`, with the caveat that `pointer` may be
+a BigInt value (on 64-bit WASM), `sizeof` will be a Number and,
+spoiler alert, `(BigInt(1) + Number(1))` is not legal. Thus this API
+adds a small convenience method to work around that portability issue:
+
+>  
+```
+const ptrTail = MyStruct.ptrAdd(theInstance.pointer, theInstance.extraBytes);
+```
+
+`typeof ptrTail` is `'bigint'` in 64-bit builds and `'number'` in
+32-bit.  i.e. it's the same type as `theInstance.pointer`.
+Equivalently, the inherited `MyStruct` instance method with the same
+name adds an instance's own `pointer` value to its arguments:
+
+```  
+const ptrTail = theInstance.ptrAdd(theInstance.extraBytes);
+```
 
 These constructors have the following "static" members:
 
@@ -776,6 +1022,10 @@ These constructors have the following "static" members:
 - `memberKeys(string)`  
   Works exactly as documented for [StructType][].
 
+- `ptrAdd(args...)`  
+  Equivalent to [StructBinder][]`.ptrAdd(args...)`. The [_inherited_
+  method with the same name][StructType] behaves differently.
+
 - `structInfo`  
   The structure description passed to [StructBinder][] when this
   constructor was generated.
@@ -783,14 +1033,14 @@ These constructors have the following "static" members:
 - `structName`  
   The structure name passed to [StructBinder][] when this constructor
   was generated.
-  
 
-<a name='api-structprototype'></a>
+
+<a id='api-structprototype'></a>
 API: Struct Prototypes
 ------------------------------------------------------------
 
 The prototypes of structs created via [the constructors described in
-the previous section][StructCtors] are each a struct-type-specific
+the previous section][StructCtor] are each a struct-type-specific
 instance of [StructType][] and add the following struct-type-specific
 properties to the mix:
 
@@ -802,78 +1052,57 @@ properties to the mix:
   The name of the struct, as it was given to the [StructBinder][] which
   created this class.
 
-<a name='api-structinstance'></a>
+<a id='api-structinstance'></a>
 API: Struct Instances
 ------------------------------------------------------------------------
 
 Instances of structs created via [the constructors described
-above][StructCtors] each have the following instance-specific state in
-common:
-
-- `pointer`  
-  A read-only numeric property which is the "pointer" returned by the
-  configured allocator when this object is constructed. After
-  `dispose()` (inherited from [StructType][]) is called, this property
-  has the `undefined` value. When calling C-side code which takes a
-  pointer to a struct of this type, simply pass it `myStruct.pointer`.
+above][StructCtor]. Each inherits all of the methods and properties
+from their constructor's prototype.
 
-<a name='appendices'></a>
+<a id='appendices'></a>
 Appendices
 ============================================================
 
-<a name='appendix-a'></a>
+<a id='appendix-a'></a>
 Appendix A: Limitations, TODOs, and Non-TODOs
 ------------------------------------------------------------
 
 - This library only supports the basic set of member types supported
-  by WASM: numbers (which includes pointers). Nested structs are not
-  handled except that a member may be a _pointer_ to such a
-  struct. Whether or not it ever will depends entirely on whether its
-  developer ever needs that support. Conversion of strings between
-  JS and C requires infrastructure specific to each WASM environment
-  and is not directly supported by this library.
-
-- Binding functions to struct instances, such that C can see and call
-  JS-defined functions, is not as transparent as it really could be,
-  due to [shortcomings in the Emscripten
-  `addFunction()`/`removeFunction()`
-  interfaces](https://github.com/emscripten-core/emscripten/issues/17323). Until
-  a replacement for that API can be written, this support will be
-  quite limited. It _is_ possible to bind a JS-defined function to a
-  C-side function pointer and call that function from C. What's
-  missing is easier-to-use/more transparent support for doing so.
-  - In the meantime, a [standalone
-  subproject](/file/common/whwasmutil.js) of Jaccwabyt provides such a
-  binding mechanism, but integrating it directly with Jaccwabyt would
-  not only more than double its size but somehow feels inappropriate, so
-  experimentation is in order for how to offer that capability via
-  completely optional [StructBinderFactory][] config options.
-
-- It "might be interesting" to move access of the C-bound members into
-  a sub-object. e.g., from JS they might be accessed via
-  `myStructInstance.s.structMember`. The main advantage is that it would
-  eliminate any potential confusion about which members are part of
-  the C struct and which exist purely in JS. "The problem" with that
-  is that it requires internally mapping the `s` member back to the
-  object which contains it, which makes the whole thing more costly
-  and adds one more moving part which can break. Even so, it's
-  something to try out one rainy day. Maybe even make it optional and
-  make the `s` name configurable via the [StructBinderFactory][]
-  options. (Over-engineering is an arguably bad habit of mine.)
-
-- It "might be interesting" to offer (de)serialization support. It
-  would be very limited, e.g. we can't serialize arbitrary pointers in
-  any meaningful way, but "might" be useful for structs which contain
-  only numeric or C-string state. As it is, it's easy enough for
-  client code to write wrappers for that and handle the members in
-  ways appropriate to their apps. Any impl provided in this library
-  would have the shortcoming that it may inadvertently serialize
-  pointers (since they're just integers), resulting in potential chaos
-  after deserialization. Perhaps the struct description can be
-  extended to tag specific members as serializable and how to
-  serialize them.
-
-<a name='appendix-d'></a>
+  by WASM: numbers (which includes pointers).
+
+- Binding JS functions to struct instances, such that C can see and
+  call JS-defined functions, is not as transparent as it really could
+  be.  [The WhWasmUtil API][whwasmutil.js], and
+  standalone subproject co-developed with Jaccwabyt, provides such a
+  binding mechanism. There is some overlap between the two APIs and
+  they arguably belong bundled together, but doing so would more than
+  triple Jaccwabyt's size. (That said, the only known Jaccwabyt
+  deployment uses both APIs, so maybe it's time to merge them (he says
+  on 2025-11-10). As of this writing, jaccwabyt.js is 38k, half of
+  which is comments/docs, whereas whwasmutil.js is 100kb and 75%
+  docs).
+
+<a id='appendix-b'></a>
+Appendix B: Build
+------------------------------------------------------------------------
+
+In order to support both vanilla JS and ESM (ES6 module) builds from a
+single source, this project uses [a preprocessor][c-pp], which requires
+only a C compiler:
+
+> $ make
+
+The makefile requires GNU make, not BSD or POSIX make.
+
+The resulting files are in the `js/` subdirectory, in both "vanilla"
+JS and ESM formats.
+
+This tree [includes all of the requisite sources](/dir/tool) and
+requires no out-of-tree dependencies beyond the system's libc.
+
+
+<a id='appendix-d'></a>
 Appendix D: Debug Info
 ------------------------------------------------------------
 
@@ -894,7 +1123,7 @@ client code:
   [StructType][].
 
 
-<a name='appendix-g'></a>
+<a id='appendix-g'></a>
 Appendix G: Generating Struct Descriptions From C
 ------------------------------------------------------------
 
@@ -1064,18 +1293,23 @@ div.content h3::before {
 div.content h3 {border-left-width: 2.5em}
 </style>
 
-[sqlite3]: https://sqlite.org
-[emscripten]: https://emscripten.org
-[sgb]: https://wanderinghorse.net/home/stephan/
 [appendix-g]: #appendix-g
-[StructBinderFactory]: #api-binderfactory
-[StructCtors]: #api-structctor
-[StructType]: #api-structtype
+[BigInt64Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array
+[c-pp]: https://fossil.wanderinghorse.net/r/c-pp
+[Emscripten]: https://emscripten.org
+[jaccwabyt.js]: /file/jaccwabyt/jaccwabyt.c-pp.js
+[MDN]: https://developer.mozilla.org/docs/Web/API
+[sgb]: https://wanderinghorse.net/home/stephan/
+[sqlite3]: https://sqlite.org
 [StructBinder]: #api-structbinder
+[StructBinderFactory]: #api-binderfactory
+[StructCtor]: #api-structctor
 [StructInstance]: #api-structinstance
-[^export-func]: In Emscripten, add its name, prefixed with `_`, to the
-  project's `EXPORT_FUNCTIONS` list.
-[BigInt64Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array
+[StructType]: #api-structtype
 [TextDecoder]: https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
 [TextEncoder]: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
-[MDN]: https://developer.mozilla.org/docs/Web/API
+[WASI-SDK]: https://github.com/WebAssembly/wasi-sdk
+[whwasmutil.js]: /file/wasmutil/whwasmutil.c-pp.js
+
+[^export-func]: In Emscripten, add its name, prefixed with `_`, to the
+  project's `EXPORT_FUNCTIONS` list.
index 13a51935e82147bd506e507622db4c8c51b3c1c5..0236d0c8db010e5ddcb35a8ab0904cb66d387cda 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Get\sinitial\sJS\soverrides\sof\sthe\skvvfs\ssqlite3_vfs\sand\ssqlite3_io_methods\sin\splace.\sIt\snow\stracks\sa\sdistinct\sStorage-ish\sobject\sper\ssqlite3_file\sinstance.
-D 2025-11-21T22:13:35.200
+C Latest\sside-stream\sjaccwabyt/wasmutil.
+D 2025-11-22T02:23:02.637
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -611,7 +611,7 @@ F ext/wasm/c-pp-lite.c 943be1a36774d58385dca32de36fc18d4f432fe79f7aa35e6c85dd6a6
 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
 F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
-F ext/wasm/common/whwasmutil.js 804409dec98458f732b23e6e86788934ac6dec002107435cc4055355585d1c15
+F ext/wasm/common/whwasmutil.js 831f07a0d9bb61713164871370811432e96d0f813806a4d2c783d3c77c2373a0
 F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a
 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
 F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
@@ -628,8 +628,8 @@ F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc6
 F ext/wasm/fiddle/index.html a27b8127ef9ecf19612da93b2a6a73bdb3777b5c56b5450bb7200a94bc108ff9
 F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
 F ext/wasm/index.html 54e27db740695ab2cb296e02d42c4c66b3f11b65797340d19fa6590f5b287da1
-F ext/wasm/jaccwabyt/jaccwabyt.js 236464b7c8e2d2540a296ba049b3e812e2697ef8439ac96f0d20716e46ba6809
-F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
+F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b
+F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41
 F ext/wasm/mkdist.sh 64d53f469c823ed311f6696f69cec9093f745e467334b34f5ceabdf9de3c5b28 x
 F ext/wasm/mkwasmbuilds.c ef42e404236dd98cedb6ecea47b6d2474e3c593633ce6d992d316289dfc442b6
 F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
@@ -2178,8 +2178,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 90a33941c69b3581feaed271542f0238ca81ee34fe5b353ca7da48b81ac73a5f
-R 831d8b062b833be06147d18462b6029d
+P 19a3349a2031e2b7fae67847b55643e4f70f8dae863ebc1ace3b09d1f482c8eb
+R f4817f0cbb500ac29ff861fffe4ad699
 U stephan
-Z 6ff913830f5e095f3c74b6184f98d188
+Z a18118b461e622bb9fd359a51fedd9be
 # Remove this line to create a well-formed Fossil manifest.
index 0d050e20e165d3d251ed4c8877455a96a02f73e5..a10954d26a858dbf5ddcd55260ddc6b0476cf74a 100644 (file)
@@ -1 +1 @@
-19a3349a2031e2b7fae67847b55643e4f70f8dae863ebc1ace3b09d1f482c8eb
+e0b33b51229a977cc3fa8a5a6c8ea59669f8bf566b2a6330fd24da1ad886a716