]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add kvvfs URI flag transient=1 to cause the storage object to be removed when the...
authorstephan <stephan@noemail.net>
Mon, 24 Nov 2025 20:14:23 +0000 (20:14 +0000)
committerstephan <stephan@noemail.net>
Mon, 24 Nov 2025 20:14:23 +0000 (20:14 +0000)
FossilOrigin-Name: c6183261be77d03451aed563a5e4c19aa69706aa311cfdaf5db5e9b0a167d814

ext/wasm/api/sqlite3-api-oo1.c-pp.js
ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js
ext/wasm/tester1.c-pp.js
manifest
manifest.uuid

index f2bd5e3c86340f7e644856a71163626cc6b13d0b..154454ffee83550dfd986515ffbb00ddc2895796 100644 (file)
@@ -213,7 +213,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      properties:
 
      - `.filename`: the db filename. It may be a special name like ":memory:"
-       or "".
+       or "". It may also be a URI-style name.
 
      - `.flags`: as documented in the DB constructor.
 
index f0dd63340229a46677479fd02565a7eae1c5f954..eaf548b5b5e927d003592cc2e4e7a5860e88ee74 100644 (file)
@@ -90,6 +90,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
   delete capi.KVVfsFile;
 
   if( !pKvvfs ) return /* nothing to do */;
+  if( 0 ){
+    /* This working would be our proverbial holy grail. */
+    capi.sqlite3_vfs_register(pKvvfs, 1);
+  }
 
   const util = sqlite3.util,
         wasm = sqlite3.wasm,
@@ -180,20 +184,44 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      Create a new instance of the objects which go into
      cache.storagePool.
   */
-  const createStorageObj = (name,storage)=>Object.assign(Object.create(null),{
+  const newStorageObj = (name,storage)=>Object.assign(Object.create(null),{
+    /**
+       JS string value of this KVVfsFile::$zClass. i.e. the storage's
+       name.
+    */
     jzClass: name,
+    /**
+       Refcount to keep dbs and journals pointing to the same storage
+       for the life of both. Managed by xOpen() and xClose().
+    */
     refc: 1,
+    /**
+       isTransient objects will be removed by xClose() when refc
+       reaches 0. The others will persist, to give the illusion of
+       real back-end storage. Managed by xOpen().
+     */
+    isTransient: false,
+    /**
+       The backing store. Must implement the Storage interface.
+    */
     storage: storage || new KVVfsStorage,
-    /* This is the storage prefix used for kvvfs keys.  It is
+    /**
+       The storage prefix used for kvvfs keys.  It is
        "kvvfs-STORAGENAME-" for local/session storage and an empty
-       string for transient storage. local/session storage must
-       use the long form for backwards compatibility.
+       string for transient storage. local/session storage must use
+       the long form (A) for backwards compatibility and (B) so that
+       kvvfs can coexist with non-db client data in those backends.
+       Neither (A) nor (B) are concerns for KVVfsStorage objects.
 
        This prefix mirrors the one generated by os_kv.c's
        kvrecordMakeKey() and must stay in sync with that one.
     */
     keyPrefix: kvvfsKeyPrefix(name),
-    files: [/*KVVfsFile instances currently using this storage*/]
+    /**
+       KVVfsFile instances currently using this storage. Managed by
+       xOpen() and xClose().
+    */
+    files: []
   });
 
 
@@ -205,17 +233,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      that concurrent active xOpen()s on a given name, and within a
      given thread, use the same storage object.
   */
-  /* Start off with mappings for well-known names. */
   cache.storagePool = Object.assign(Object.create(null),{
-    localThread: createStorageObj('localThread')
+    /* Start off with mappings for well-known names. */
+    localThread: newStorageObj('localThread')
   });
 
   if( globalThis.Storage ){
     if( globalThis.localStorage instanceof globalThis.Storage ){
-      cache.storagePool.local = createStorageObj('local');
+      cache.storagePool.local = newStorageObj('local', globalThis.localStorage);
     }
     if( globalThis.sessionStorage instanceof globalThis.Storage ){
-      cache.storagePool.session = createStorageObj('session');
+      cache.storagePool.session = newStorageObj('session', globalThis.sessionStorage);
     }
   }
 
@@ -242,6 +270,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      argument should be one of ('local','session',"") or the name of
      an opened transient kvvfs db.
 
+     Its handling of which=='' is historical: it means to consider
+     both local and session storage. which=='' is also a valid kvvfs
+     storage unit name, though. Prior to that possibility, this API
+     was only availbe in the main UI thread, so the empty string
+     continues to unconditionally work that way in the main UI
+     thread. When, however, it's running where local/session storage
+     are not availble, it treats which=='' as a storage unit name.
+
      It returns an object in the form:
 
      .prefix = the key prefix for this storage. Typically
@@ -259,13 +295,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      in the current environment (e.g. a worker thread).
 
      .cts = the underlying storagePool entry. This will only be set
-     of which is not empty.
+     if which is not empty.
   */
   const kvvfsWhich = function callee(which){
     const rc = Object.assign(Object.create(null),{
       stores: []
     });
-    if( which ){
+    if( which || !globalThis.Storage ){
       const s = storageForZClass(which);
       if( s ){
         //debug("kvvfsWhich",s.jzClass,rc.prefix, s.s);
@@ -276,10 +312,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
         rc.prefix = undefined;
       }
     }else{
-      // Legacy behavior: return both local and session storage.
       rc.prefix = 'kvvfs-';
-      if( globalThis.sessionStorage ) rc.stores.push(globalThis.sessionStorage);
-      if( globalThis.localStorage ) rc.stores.push(globalThis.localStorage);
+      // Legacy behavior: return both local and session storage.
+      if( cache.storagePool.local ) {
+        rc.stores.push(cache.storagePool.local.storage);
+      }
+      if( cache.storagePool.session ) {
+        rc.stores.push(cache.storagePool.session.storage);
+      }
     }
     //debug("kvvfsWhich",which,rc);
     return rc;
@@ -292,8 +332,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      (sqlite3_file*). On success it returns a new KVVfsFile instance
      wrapping that pointer, which the caller must eventual call
      dispose() on (which won't free the underlying pointer, just the
-     wrapper).
-   */
+     wrapper). Returns null if no handle is found (which would
+     indicate either that pDb is not using kvvfs or a severe bug in
+     its management).
+  */
   const fileForDb = function(pDb){
     const stack = pstack.pointer;
     try{
@@ -307,7 +349,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       pstack.restore(stack);
     }
   };
-//#endif nope
 
   /**
      Expects an object from the storagePool map. The $szPage and
@@ -327,89 +368,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       throw e;
     }
   };
-
-  /**
-     Clears all storage used by the kvvfs DB backend, deleting any
-     DB(s) stored there.
-
-     Its argument must be either 'session', 'local', "", or the name
-     of a transient kvvfs storage object file. In the first two cases,
-     only sessionStorage resp. localStorage is cleared. If which is an
-     empty string (the default) then both localStorage and
-     sessionStorage are cleared. Only storage keys which match the
-     pattern used by kvvfs are cleared: any other client-side data are
-     retained.
-
-     This function only manipulates localStorage and sessionStorage in
-     the main UI thread (they don't exist in Worker threads).
-     It affects transient kvvfs objects in any thread.
-
-     Returns the number of entries cleared.
-  */
-  capi.sqlite3_js_kvvfs_clear = function(which=""){
-    let rc = 0;
-    const store = kvvfsWhich(which);
-    const keyPrefix = store.prefix;
-    /**
-       Historically this code had no way to check whether the storage
-       was in use before wiping it, so could not error in that
-       case. Whether or not it should, not that it can (as of late
-       2025-11), is TBD.
-    */
-    store.stores.forEach((s)=>{
-      const toRm = [] /* keys to remove */;
-      let i, n = s.length;
-      //debug("kvvfs_clear",store,s);
-      for( i = 0; i < n; ++i ){
-        const k = s.key(i);
-        //debug("kvvfs_clear ?",k);
-        if(!keyPrefix || k.startsWith(keyPrefix)) toRm.push(k);
-      }
-      toRm.forEach((kk)=>s.removeItem(kk));
-      rc += toRm.length;
-    });
-    if( store.cts ) alertFilesToReload(store.cts);
-    return rc;
-  };
-
-  /**
-     This routine guesses the approximate amount of
-     storage used by the given kvvfs back-end.
-
-     The 'which' argument is as documented for
-     sqlite3_js_kvvfs_clear(), only the operation this performs is
-     different:
-
-     The returned value is twice the "length" value of every matching
-     key and value, noting that JavaScript stores each character in 2
-     bytes.
-
-     If passed 'local' or 'session' or '' from a thread other than the
-     main UI thread, this is effectively a no-op and returns 0.
-
-     The returned size is not authoritative from the perspective of
-     how much data can fit into localStorage and sessionStorage, as
-     the precise algorithms for determining those limits are
-     unspecified and may include per-entry overhead invisible to
-     clients.
-  */
-  capi.sqlite3_js_kvvfs_size = function(which=""){
-    let sz = 0;
-    const store = kvvfsWhich(which);
-    //warn("kvvfs_size storage",store);
-    store?.stores?.forEach?.((s)=>{
-      //warn("kvvfs_size backend",s);
-      let i;
-      for(i = 0; i < s.length; ++i){
-        const k = s.key(i);
-        if(k.startsWith(store.prefix)){
-          sz += k.length;
-          sz += s.getItem(k).length;
-        }
-      }
-    });
-    return sz * 2 /* because JS uses 2-byte char encoding */;
-  };
+//#endif nope
 
   /** pstack-allocates a key. Caller must eventually restore
       the pstack to free the memory. */
@@ -611,13 +570,16 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
               zName = (cache.zEmpty ??= wasm.allocCString(""));
             }
             const n = wasm.cstrlen(zName);
-            if( n > kvvfsMethods.$nKeySize - 8 /*"-journal"*/ - 1 ){
+            if( !n ){
+              warn("file name may not be empty (backwards compatibilty constraint)");
+              return capi.SQLITE_RANGE;
+            }else if( n > kvvfsMethods.$nKeySize - 8 /*"-journal"*/ - 1 ){
               warn("file name is too long:", wasm.cstrToJs(zName));
               return capi.SQLITE_RANGE;
             }
             const jzClass = wasm.cstrToJs(zName);
             if( jzClass?.length != n ){
-              warn("kvvfs file name must be ASCII-only");
+              warn("kvvfs file name must be ASCII-only:",jzClass);
               /* This limitation is to avoide any issues with
                  truncating multi-byte characters in kvvfs's key-size
                  limit. */
@@ -626,12 +588,23 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
             const rc = originalMethods.vfs.xOpen(pProtoVfs, zName, pProtoFile,
                                                  flags, pOutFlags);
             if( rc ) return rc;
+            let transient = false;
+            if(n && wasm.isPtr(zName)){
+              if(capi.sqlite3_uri_boolean(zName, "transient", 0)){
+                transient = true;
+                //warn("transient=",transient);
+              }
+              if(capi.sqlite3_uri_boolean(zName, "wipe-before-open", 0)){
+                // TODO
+              }
+            }
             const f = new KVVfsFile(pProtoFile);
             util.assert(f.$zClass, "Missing f.$zClass");
             let s = storageForZClass(jzClass);
             //debug("xOpen", jzClass, s);
             if( s ){
               ++s.refc;
+              if( true===transient ) s.isTransient = true;
               s.files.push(f);
             }else{
               /* TODO: a url flag which tells it to keep the storage
@@ -646,8 +619,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
                     : jzClass + '-journal';
               s = cache.storagePool[jzClass]
                 = cache.storagePool[other]
-                = createStorageObj(jzClass);
+                = newStorageObj(jzClass);
               s.files.push(f);
+              s.isTransient = transient;
               debug("xOpen installed storage handles [",
                     jzClass, other,"]", s);
             }
@@ -763,7 +737,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
               pFileHandles.delete(pFile);
               const s = storageForZClass(h.jzClass);
               s.files = s.files.filter((v)=>v!==h.file);
-              if( 0===--s.refc ){
+              if( --s.refc<=0 && s.isTransient ){
                 const other = h.file.$isJournal
                       ? h.jzClass.replace(cache.rxJournalSuffix,'')
                       : h.jzClass+'-journal';
@@ -874,6 +848,111 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     }
   }/*native method overrides*/
 
+  /**
+     Clears all storage used by the kvvfs DB backend, deleting any
+     DB(s) stored there.
+
+     Its argument must be the name of a kvvfs storage object:
+
+     - 'session'
+     - 'local'
+     - An empty string means both of 'local' and 'session' storage.
+     - A transient kvvfs storage object name.
+
+     In the first two cases, only sessionStorage resp. localStorage is
+     cleared. If passed an an empty string (the default) then its
+     behavior depends on:
+
+     - If called in the main thread an empty stream means to act on
+     both localStorage and sessionStorage. Only storage keys which
+     match the pattern used by kvvfs are cleared: any other
+     client-side data are retained. Version 1 of this API always
+     behaves this way. (This is backwards-compatibility behavior to
+     account for an admitted misuse of "".)
+
+     - If called from a thread where globalThis.Storage is not available
+     then an empty string is considered to be a legal storage unit name.
+
+     Returns the number of entries cleared.
+
+     As of kvvfs version 2:
+
+     This API is available in Worker threads but does not have access
+     to localStorage or sessionStorage in them. Prior versions did not
+     include this API in Worker threads.
+
+     Differences in this function in version 2:
+
+     - It accepts an arbitrary storage name. In v1 this was a silent
+     no-op for any names other than ('local','session','').
+
+     - In Worker threads, an empty string argument is treated as a
+     storage unit name.
+  */
+  capi.sqlite3_js_kvvfs_clear = function(which=""){
+    let rc = 0;
+    const store = kvvfsWhich(which);
+    const keyPrefix = store.prefix;
+    /**
+       Historically this code had no way to check whether the storage
+       was in use before wiping it, so could not error in that
+       case. Whether or not it should, now that it can (as of late
+       2025-11), is TBD.
+    */
+    store.stores.forEach((s)=>{
+      const toRm = [] /* keys to remove */;
+      let i, n = s.length;
+      //debug("kvvfs_clear",store,s);
+      for( i = 0; i < n; ++i ){
+        const k = s.key(i);
+        //debug("kvvfs_clear ?",k);
+        if(!keyPrefix || k.startsWith(keyPrefix)) toRm.push(k);
+      }
+      toRm.forEach((kk)=>s.removeItem(kk));
+      rc += toRm.length;
+    });
+    //if( store.cts ) alertFilesToReload(store.cts);
+    return rc;
+  };
+
+  /**
+     This routine guesses the approximate amount of
+     storage used by the given kvvfs back-end.
+
+     The 'which' argument is as documented for
+     sqlite3_js_kvvfs_clear(), only the operation this performs is
+     different:
+
+     The returned value is twice the "length" value of every matching
+     key and value, noting that JavaScript stores each character in 2
+     bytes.
+
+     If passed 'local' or 'session' or '' from a thread other than the
+     main UI thread, this is effectively a no-op and returns 0.
+
+     The returned size is not authoritative from the perspective of
+     how much data can fit into localStorage and sessionStorage, as
+     the precise algorithms for determining those limits are
+     unspecified and may include per-entry overhead invisible to
+     clients.
+  */
+  capi.sqlite3_js_kvvfs_size = function(which=""){
+    let sz = 0;
+    const store = kvvfsWhich(which);
+    //warn("kvvfs_size storage",store);
+    store?.stores?.forEach?.((s)=>{
+      //warn("kvvfs_size backend",s);
+      let i;
+      for(i = 0; i < s.length; ++i){
+        const k = s.key(i);
+        if(!store.prefix || k.startsWith(store.prefix)){
+          sz += k.length;
+          sz += s.getItem(k).length;
+        }
+      }
+    });
+    return sz * 2 /* because JS uses 2-byte char encoding */;
+  };
 
   /**
      Copies the entire contents of the given transient storage object
@@ -912,7 +991,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       util.toss3(capi.SQLITE_NOTFOUND,
                  "There is no kvvfs storage named",storageName);
     }
-    debug("store to export=",store);
+    //debug("store to export=",store);
     const s = store.storage;
     const rc = Object.assign(Object.create(null),{
       name: store.jzClass,
@@ -1012,7 +1091,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
                    "Cowardly refusing to create storage with a",
                    "'-journal' suffix.");
       }
-      store = createStorageObj(exp.name);
+      store = newStorageObj(exp.name);
       cache.storagePool[exp.name] =
         cache.storagePool[exp.name+'-journal'] = store;
       //warn("Installing new storage:",store);
index 3176d0a9dd273f6052f3bde8099f9d4924260c51..dddcfbf0ba9d34887ef6d3ffc579e74821c168fa 100644 (file)
@@ -210,8 +210,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
        filter.test(error.message) passes. If it's a function, the test
        passes if filter(error) returns truthy. If it's a string, the
        test passes if the filter matches the exception message
-       precisely. In all other cases the test fails, throwing an
-       Error.
+       precisely. If filter is a number then it is compared against
+       the resultCode property of the exception. In all other cases
+       the test fails, throwing an Error.
 
        If it throws, msg is used as the error report unless it's falsy,
        in which case a default is used.
@@ -225,7 +226,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
       if(filter instanceof RegExp) pass = filter.test(err.message);
       else if(filter instanceof Function) pass = filter(err);
       else if('string' === typeof filter) pass = (err.message === filter);
+      else if('number' === typeof filter) pass = (err.resultCode === filter);
       if(!pass){
+        console.error("Filter",filter,"rejected exception",err);
         throw new Error(msg || ("Filter rejected this exception: <<"+err.message+">>"));
       }
       return this;
@@ -2918,6 +2921,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
       test: function(sqlite3){
         const filename = 'localThread' /* preinstalled instance */;
         const JDb = sqlite3.oo1.JsStorageDb;
+        const DB = sqlite3.oo1.DB;
         JDb.clearStorage(filename);
         let db = new JDb(filename);
         const sqlSetup = [
@@ -2952,16 +2956,19 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
           console.debug("kvvfs to Object:",exp);
           close();
 
-          db = new JDb('new-storage');
+          const dbFileRaw = 'file:new-storage?vfs=kvvfs&transient=1';
+          db = new DB(dbFileRaw);
           db.exec(sqlSetup);
+          const dbFilename = db.dbFilename();
+          console.warn("db.dbFilename() =",dbFilename);
           T.assert(3 === db.selectValue('select count(*) from kvvfs'));
-          console.debug("kvvfs to Object:",exportDb(db.filename));
-          const n = db.storageSize();
+          console.debug("kvvfs to Object:",exportDb(dbFilename));
+          const n = capi.sqlite3_js_kvvfs_size( dbFilename );
           T.assert( n>0, "Db size count failed" );
 
           if( 1 ){
             // Concurrent open of that same name uses the same storage
-            const x = new JDb(db.filename);
+            const x = new JDb(dbFilename);
             T.assert(3 === db.selectValue('select count(*) from kvvfs'));
             x.close();
           }
@@ -2970,14 +2977,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
           // disappears...
           T.mustThrowMatching(function(){
             /* Ensure that 'new-storage' was deleted when its refcount
-               went to 0. TODO is a way to tell these instances to
-               hang around after that, such that 'new-instance' could
-               be semi-persistent (until the page is reloaded).
-            */
-            let ddb = new JDb('new-storage');
+               went to 0, because of its 'transient' flag. By default
+               the objects are retained, like a filesystem would. */
+            let ddb = new JDb(dbFilename);
             try{ddb.selectValue('select a from kvvfs')}
             finally{ddb.close()}
-          }, /.*no such table: kvvfs.*/);
+          }, /no such table: kvvfs/);
         }finally{
           if( db ) db.close();
         }
@@ -2988,6 +2993,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
       //predicate: ()=>false,
       test: function(sqlite3){
         const filename = 'my';
+        const DB = sqlite3.oo1.DB;
         const JDb = sqlite3.oo1.JsStorageDb;
         let db;
         let duo;
@@ -2998,8 +3004,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
         const sqlCount = 'select count(*) from kvvfs';
         try {
           const exportDb = capi.sqlite3_js_kvvfs_export_storage;
-          db = new JDb(filename);
-          db.clearStorage(/*must not throw*/);
+          const dbFileRaw = 'file:'+filename+'?vfs=kvvfs&transient=1';
+          db = new DB(dbFileRaw);
+          capi.sqlite3_js_kvvfs_clear(filename);
           db.exec(sqlSetup);
           T.assert(3 === db.selectValue(sqlCount));
 
@@ -3021,7 +3028,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
           duo = new JDb(filename);
           T.mustThrowMatching(()=>importDb(exp,true), /.*in use.*/);
           duo.close();
-          importDb(exp);
+          importDb(exp, true);
           duo = new JDb(filename);
           T.assert(6 === duo.selectValue(sqlCount));
           duo.close();
index cfded82acdbe4f3a5fa6cb696420fa3a068dff9e..4db57235f25d10c0286564a0226f298c0527c149 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\stypeof\scheck\sso\sthat\sit\sworks\sin\sWorker\sthreads.
-D 2025-11-24T18:17:07.960
+C Add\skvvfs\sURI\sflag\stransient=1\sto\scause\sthe\sstorage\sobject\sto\sbe\sremoved\swhen\sthe\slast\shandle\sto\sthe\sdb\sis\sclosed.\sBy\sdefault\sit\sbehaves\slike\sa\sfilesystem\swould,\sretaining\sthe\sstorage\sobjects.
+D 2025-11-24T20:14:23.332
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -594,13 +594,13 @@ F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8a
 F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd503c41700e03dd1f06
 F ext/wasm/api/pre-js.c-pp.js ad2546290e0c8ce5ca2081bff6e85cc25eeb904a3303921f1184290a7ff1b32f
 F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c
-F ext/wasm/api/sqlite3-api-oo1.c-pp.js 7d8850f754b4a9aecd5a4a92a357e05f720cd7f5cf962909343b40c914237256
+F ext/wasm/api/sqlite3-api-oo1.c-pp.js f3bc80f3d6b75456ea21c9ef8ad565e48376a49e2d15e1226a7a9b22edc2cd0e
 F ext/wasm/api/sqlite3-api-prologue.js 2ac62b41dd8d66859c86a6af126690851e5e557dad61ef59692389762c9bd2ed
 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
 F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
-F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a23002998d4cd2cdd4b6eb8884b399507d7160574bbe5665dfdfcbe53161d2ca
+F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 6a85c98875479f8630bede48c9f5fd1e23e2a073b4d00b968c77ae2b3ac98887
 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 26cb41d5a62f46a106b6371eb00fef02de3cdbfaa51338ba087a45f53028e0d0
 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3
 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86
@@ -647,7 +647,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
 F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
-F ext/wasm/tester1.c-pp.js eaa1ed5ee1e5e8f12b4cbd9462bc8f3841a1deff3232486f72cf7914c02a3c29
+F ext/wasm/tester1.c-pp.js c864070e09a140576ef96ab92117f152e167ea1fdb58da2a561fb2ecd2c5957f
 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
 F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
@@ -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 03cb2a13c7f9081132390b5169cf22ffeced6ebdc5f01654360f951720310916
-R 7358b9115b27e85b1625d74ca82dd891
+P 3f2ed39e40e9c76c7d035b819d06c316ec4fba4e112b8a293822a8648147594b
+R c4273f921b278213e0e850729894dac9
 U stephan
-Z 9ea3ccd4adc9fd767d4ce3fb6cf488b3
+Z 42d0fbf71d4bbf24651067a6368dccc7
 # Remove this line to create a well-formed Fossil manifest.
index 6ecfc9201a3648987f10ce77fefa44eaa0ccd7fd..349ac0e0b34a4ca6beb1a1057527f3270169e0ac 100644 (file)
@@ -1 +1 @@
-3f2ed39e40e9c76c7d035b819d06c316ec4fba4e112b8a293822a8648147594b
+c6183261be77d03451aed563a5e4c19aa69706aa311cfdaf5db5e9b0a167d814