From 3734401a95dc92f7cb7c3a86875370f1598213aa Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 24 Aug 2022 18:39:46 +0000 Subject: [PATCH] Expand the worker1 'exec' op handling for per-row callbacks for API-level consistency and smooth some edges between worker1 core and worker1-promiser. Add worker1 'config-get' message to fetch the serializable parts of the sqlite3.config state. Improve the 'open' op's handling of the 'persistent' option (noting that we cannot yet test that case from a worker). FossilOrigin-Name: 509f8839201ec1ea4863bd31493e6c29a0721ca6340755bb96656b828758fea7 --- ext/wasm/api/sqlite3-api-oo1.js | 15 ++ ext/wasm/api/sqlite3-api-worker1.js | 244 +++++++++++++++++---------- ext/wasm/sqlite3-worker1-promiser.js | 63 ++++--- ext/wasm/testing-worker1-promiser.js | 50 ++++-- ext/wasm/testing2.js | 12 +- manifest | 20 +-- manifest.uuid | 2 +- 7 files changed, 264 insertions(+), 142 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js index be9d8af5a8..e16b45bb5e 100644 --- a/ext/wasm/api/sqlite3-api-oo1.js +++ b/ext/wasm/api/sqlite3-api-oo1.js @@ -252,6 +252,21 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ out.cbArg = (stmt)=>stmt.get(out.opt.rowMode); break; } + /* + TODO?: how can we define rowMode such that it uses + rowMode of 'object' and returns a given named field from + the object. Something like: + + if(?what goes here?){ + out.cbArg = function f(stmt){return stmt.get(this.obj)[this.colName]} + .bind({obj:{}, colName: ???what goes here???}}); + break; + } + + Maybe rowMode:['colName1',... 'colNameN']? That could be + ambiguous: might mean "return an object with just these + columns". + */ toss3("Invalid rowMode:",out.opt.rowMode); } } diff --git a/ext/wasm/api/sqlite3-api-worker1.js b/ext/wasm/api/sqlite3-api-worker1.js index c63ab1117e..afb2e78124 100644 --- a/ext/wasm/api/sqlite3-api-worker1.js +++ b/ext/wasm/api/sqlite3-api-worker1.js @@ -42,25 +42,21 @@ initialization is complete, as the initialization is synchronous. In some contexts, however, listening for the above message is a better fit. + + Note that the worker-based interface can be slightly quirky because + of its async nature. In particular, any number of messages may be posted + to the worker before it starts handling any of them. If, e.g., an + "open" operation fails, any subsequent messages will fail. The + Promise-based wrapper for this API (`sqlite3-worker1-promiser.js`) + is more comfortable to use in that regard. + + + TODO: hoist the message API docs from deep in this code to here. + */ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3.initWorker1API = function(){ 'use strict'; - /** - UNDER CONSTRUCTION - - We need an API which can proxy the DB API via a Worker message - interface. The primary quirky factor in such an API is that we - cannot pass callback functions between the window thread and a - worker thread, so we have to receive all db results via - asynchronous message-passing. That requires an asychronous API - with a distinctly different shape than OO API #1. - - TODOs include, but are not necessarily limited to: - - - Support for handling multiple DBs via this interface is under - development. - */ const toss = (...args)=>{throw new Error(args.join(' '))}; if('function' !== typeof importScripts){ toss("Cannot initalize the sqlite3 worker API in the main thread."); @@ -86,12 +82,13 @@ sqlite3.initWorker1API = function(){ }; /** - Helper for managing Worker-level state. + Internal helper for managing Worker-level state. */ const wState = { defaultDb: undefined, idSeq: 0, idMap: new WeakMap, + xfer: [/*Temp holder for "transferable" postMessage() state.*/], open: function(opt){ const db = new DB(opt.filename); this.dbs[getDbId(db)] = db; @@ -109,9 +106,15 @@ sqlite3.initWorker1API = function(){ } } }, + /** + Posts the given worker message value. If xferList is provided, + it must be an array, in which case a copy of it passed as + postMessage()'s second argument and xferList.length is set to + 0. + */ post: function(msg,xferList){ - if(xferList){ - self.postMessage( msg, xferList ); + if(xferList && xferList.length){ + self.postMessage( msg, Array.from(xferList) ); xferList.length = 0; }else{ self.postMessage(msg); @@ -146,32 +149,40 @@ sqlite3.initWorker1API = function(){ message type key. The onmessage() dispatcher attempts to dispatch all inbound messages to a method of this object, passing it the event.data part of the inbound event object. All - methods must return a plain Object containing any response + methods must return a plain Object containing any result state, which the dispatcher may amend. All methods must throw on error. */ const wMsgHandler = { - xfer: [/*Temp holder for "transferable" postMessage() state.*/], /** Proxy for the DB constructor. Expects to be passed a single - object or a falsy value to use defaults. The object may have a - filename property to name the db file (see the DB constructor - for peculiarities and transformations). The response is an - object: + object or a falsy value to use defaults: { - filename: db filename (possibly differing from the input), + filename [=":memory:" or "" (unspecified)]: the db filename. + See the sqlite3.oo1.DB constructor for peculiarities and transformations, + + persistent [=false]: if true and filename is not one of ("", + ":memory:"), prepend + sqlite3.capi.sqlite3_web_persistent_dir() to the given + filename so that it is stored in persistent storage _if_ the + environment supports it. If persistent storage is not + supported, the filename is used as-is. + } + + The response object looks like: + + { + filename: db filename, possibly differing from the input. dbId: an opaque ID value which must be passed in the message - envelope to other calls in this API to tell them which - db to use. If it is not provided to future calls, they - will default to operating on the first-opened db. + envelope to other calls in this API to tell them which db to + use. If it is not provided to future calls, they will default + to operating on the first-opened db. - persistent: prepend sqlite3.capi.sqlite3_web_persistent_dir() - to the given filename so that it is stored - in persistent storage _if_ the environment supports it. - If persistent storage is not supported, the filename - is used as-is. + persistent: true if the given filename resides in the + known-persistent storage, else false. This determination is + independent of the `persistent` input argument. } */ open: function(ev){ @@ -179,28 +190,32 @@ sqlite3.initWorker1API = function(){ if(args.simulateError){ // undocumented internal testing option toss("Throwing because of simulateError flag."); } - if(args.persistent && args.filename){ - oargs.filename = sqlite3.capi.sqlite3_web_persistent_dir() + args.filename; - }else if('' === args.filename){ - oargs.filename = args.filename; + const rc = Object.create(null); + const pDir = sqlite3.capi.sqlite3_web_persistent_dir(); + if(!args.filename || ':memory:'===args.filename){ + oargs.filename = args.filename || ''; + }else if(pDir){ + oargs.filename = pDir + ('/'===args.filename[0] ? args.filename : ('/'+args.filename)); }else{ - oargs.filename = args.filename || ':memory:'; - } + oargs.filename = args.filename; + } const db = wState.open(oargs); - return { - filename: db.filename, - dbId: getDbId(db) - }; + rc.filename = db.filename; + rc.persistent = !!pDir && db.filename.startsWith(pDir); + rc.dbId = getDbId(db); + return rc; }, /** Proxy for DB.close(). ev.args may be elided or an object with an `unlink` property. If that value is truthy then the db file (if the db is currently open) will be unlinked from the virtual - filesystem, else it will be kept intact. The result object is: + filesystem, else it will be kept intact, noting that unlink + failure is ignored. The result object is: { filename: db filename _if_ the db is opened when this - is called, else the undefined value + is called, else the undefined value + dbId: the ID of the closed b, or undefined if none is closed } @@ -211,7 +226,7 @@ sqlite3.initWorker1API = function(){ const db = getMsgDb(ev,false); const response = { filename: db && db.filename, - dbId: db ? getDbId(db) : undefined + dbId: db && getDbId(db) }; if(db){ wState.close(db, ((ev.args && 'object'===typeof ev.args) @@ -220,7 +235,7 @@ sqlite3.initWorker1API = function(){ return response; }, /** - Proxy for DB.exec() which expects a single argument of type + Proxy for oo1.DB.exec() which expects a single argument of type string (SQL to execute) or an options object in the form expected by exec(). The notable differences from exec() include: @@ -234,12 +249,21 @@ sqlite3.initWorker1API = function(){ message type key, in which case a callback function will be applied which posts each row result via: - postMessage({type: thatKeyType, row: theRow}) + postMessage({type: thatKeyType, rowNumber: 1-based-#, row: theRow}) - And, at the end of the result set (whether or not any - result rows were produced), it will post an identical - message with row:null to alert the caller than the result - set is completed. + And, at the end of the result set (whether or not any result + rows were produced), it will post an identical message with + (row=undefined, rowNumber=null) to alert the caller than the + result set is completed. Note that a row value of `null` is + a legal row result for certain `rowMode` values. + + (Design note: we don't use (row=undefined, rowNumber=undefined) + to indicate end-of-results because fetching those would be + indistinguishable from fetching from an empty object unless the + client used hasOwnProperty() (or similar) to distinguish + "missing property" from "property with the undefined value". + Similarly, `null` is a legal value for `row` in some case , + whereas the db layer won't emit a result value of `undefined`.) The callback proxy must not recurse into this interface, or results are undefined. (It hypothetically cannot recurse @@ -250,52 +274,73 @@ sqlite3.initWorker1API = function(){ The response is the input options object (or a synthesized one if passed only a string), noting that options.resultRows and options.columnNames may be populated - by the call to exec(). - - This opens/creates the Worker's db if needed. + by the call to db.exec(). */ exec: function(ev){ - const opt = ( + const rc = ( 'string'===typeof ev.args ) ? {sql: ev.args} : (ev.args || Object.create(null)); - if(undefined===opt.rowMode){ + if(undefined===rc.rowMode){ /* Since the default rowMode of 'stmt' is not useful for the Worker interface, we'll default to something else. */ - opt.rowMode = 'array'; - }else if('stmt'===opt.rowMode){ - toss("Invalid rowMode for exec(): stmt mode", + rc.rowMode = 'array'; + }else if('stmt'===rc.rowMode){ + toss("Invalid rowMode for 'exec': stmt mode", "does not work in the Worker API."); } const db = getMsgDb(ev); - if(opt.callback || Array.isArray(opt.resultRows)){ + if(rc.callback || Array.isArray(rc.resultRows)){ // Part of a copy-avoidance optimization for blobs - db._blobXfer = this.xfer; + db._blobXfer = wState.xfer; } - const callbackMsgType = opt.callback; + const callbackMsgType = rc.callback; + let rowNumber = 0; if('string' === typeof callbackMsgType){ /* Treat this as a worker message type and post each row as a message of that type. */ - const that = this; - opt.callback = - (row)=>wState.post({type: callbackMsgType, row:row}, this.xfer); + rc.callback = + (row)=>wState.post({type: callbackMsgType, rowNumber:++rowNumber, row:row}, wState.xfer); } try { - db.exec(opt); - if(opt.callback instanceof Function){ - opt.callback = callbackMsgType; - wState.post({type: callbackMsgType, row: null}); + db.exec(rc); + if(rc.callback instanceof Function){ + rc.callback = callbackMsgType; + wState.post({type: callbackMsgType, rowNumber: null, row: undefined}); } - }/*catch(e){ - console.warn("Worker is propagating:",e);throw e; - }*/finally{ - delete db._blobXfer; - if(opt.callback){ - opt.callback = callbackMsgType; - } - } - return opt; + }finally{ + delete db._blobXfer; + if(rc.callback){ + rc.callback = callbackMsgType; + } + } + return rc; }/*exec()*/, + /** + Returns a JSON-friendly form of a _subset_ of sqlite3.config, + sans any parts which cannot be serialized. Because we cannot, + from here, distingush whether or not certain objects can be + serialized, this routine selectively copies certain properties + rather than trying JSON.stringify() and seeing what happens + (the results are horrid if the config object contains an + Emscripten module object). + + In addition to the "real" config properties, it sythesizes + the following: + + - persistenceEnabled: true if persistent dir support is available, + else false. + */ + 'config-get': function(){ + const rc = Object.create(null), src = sqlite3.config; + [ + 'persistentDirName', 'bigIntEnabled' + ].forEach(function(k){ + if(Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k]; + }); + rc.persistenceEnabled = !!sqlite3.capi.sqlite3_web_persistent_dir(); + return rc; + }, /** TO(RE)DO, once we can abstract away access to the JS environment's virtual filesystem. Currently this @@ -329,7 +374,7 @@ sqlite3.initWorker1API = function(){ filename: db.filename, mimetype: 'application/x-sqlite3' }; - this.xfer.push(response.buffer.buffer); + wState.xfer.push(response.buffer.buffer); return response;**/ }/*export()*/, toss: function(ev){ @@ -344,22 +389,32 @@ sqlite3.initWorker1API = function(){ form: { type: apiCommand, - dbId: optional DB ID value (else uses a default db handle), args: apiArguments, + dbId: optional DB ID value (else uses a default db handle), messageId: optional client-specific value } As a rule, these commands respond with a postMessage() of their - own in the form: - - TODO: refactoring is underway. - - The responses always have an object-format `result` part. If the - inbound object has a `messageId` property, that property is + own. The responses always have a `type` property equal to the + input message's type and an object-format `result` part. If + the inbound object has a `messageId` property, that property is always mirrored in the result object, for use in client-side - dispatching of these asynchronous results. Exceptions thrown - during processing result in an `error`-type event with a payload - in the form: + dispatching of these asynchronous results. For example: + + { + type: 'open', + messageId: ...copied from inbound message..., + dbId: ID of db which was opened, + result: { + dbId: repeat of ^^^, for API consistency's sake, + filename: ..., + persistent: false + }, + ...possibly other framework-internal/testing/debugging info... + } + + Exceptions thrown during processing result in an `error`-type + event with a payload in the form: { type: 'error', dbId: DB handle ID, @@ -413,10 +468,15 @@ sqlite3.initWorker1API = function(){ workerReceivedTime: arrivalTime, workerRespondTime: performance.now(), departureTime: ev.departureTime, + // TODO: move the timing bits into... + //timing:{ + // departure: ev.departureTime, + // workerReceived: arrivalTime, + // workerResponse: performance.now(); + //}, result: result - }, wMsgHandler.xfer); + }, wState.xfer); }; self.postMessage({type:'sqlite3-api',result:'worker1-ready'}); }.bind({self, sqlite3}); }); - diff --git a/ext/wasm/sqlite3-worker1-promiser.js b/ext/wasm/sqlite3-worker1-promiser.js index d023f86366..7327e14c70 100644 --- a/ext/wasm/sqlite3-worker1-promiser.js +++ b/ext/wasm/sqlite3-worker1-promiser.js @@ -27,7 +27,7 @@ manipulated via a Promise-based interface and returns a factory function which returns Promises for communicating with the worker. This proxy has an _almost_ identical interface to the normal - worker API, with any exceptions noted below. + worker API, with any exceptions documented below. It requires a configuration object with the following properties: @@ -127,26 +127,34 @@ - exec's {callback: STRING} option does not work via this interface (it triggers an exception), but {callback: function} does and works exactly like the STRING form does in the Worker: - the callback is called one time for each row of the result set - and once more, at the end, passed only `null`, to indicate that + the callback is called one time for each row of the result set, + passed the same worker message format as the worker API emits: + + {type:typeString, row:VALUE, rowNumber:1-based-#} + + Where `typeString` is an internally-synthesized message type string + used temporarily for worker message dispatching. It can be ignored + by all client code except that which tests this API. The `row` + property contains the row result in the form implied by the + `rowMode` option (defaulting to `'array'`). The `rowNumber` is a + 1-based integer value incremented by 1 on each call into th + callback. + + At the end of the result set, the same event is fired with + (row=undefined, rowNumber=null) to indicate that the end of the result set has been reached. Note that the rows arrive via worker-posted messages, with all the implications of that. - - - TODO?: a config option which causes it to queue up events to fire - one at a time and flush the event queue on the first error. The - main use for this is test runs which must fail at the first error. */ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){ // Inspired by: https://stackoverflow.com/a/52439530 - let idNumber = 0; const handlerMap = Object.create(null); const noop = function(){}; const err = config.onerror || noop; const debug = config.debug || noop; + const idTypeMap = config.generateMessageId ? undefined : Object.create(null); const genMsgId = config.generateMessageId || function(msg){ - return msg.type+'#'+(++idNumber); + return msg.type+'#'+(idTypeMap[msg.type] = (idTypeMap[msg.type]||0) + 1); }; const toss = (...args)=>{throw new Error(args.join(' '))}; if('function'===typeof config.worker) config.worker = config.worker(); @@ -162,7 +170,7 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){ } msgHandler = handlerMap[ev.type] /* check for exec per-row callback */; if(msgHandler && msgHandler.onrow){ - msgHandler.onrow(ev.row); + msgHandler.onrow(ev); return; } if(config.onunhandled) config.onunhandled(arguments[0]); @@ -183,13 +191,10 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){ default: break; } - try { - msgHandler.resolve(ev); - }catch(e){ - msgHandler.reject(e); - } + try {msgHandler.resolve(ev)} + catch(e){msgHandler.reject(e)} }/*worker.onmessage()*/; - return function(/*(msgType, msgArgs) || (msg)*/){ + return function(/*(msgType, msgArgs) || (msgEnvelope)*/){ let msg; if(1===arguments.length){ msg = arguments[0]; @@ -206,15 +211,29 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){ msg.departureTime = performance.now(); const proxy = Object.create(null); proxy.message = msg; - let cbId /* message handler ID for exec on-row callback proxy */; + let rowCallbackId /* message handler ID for exec on-row callback proxy */; if('exec'===msg.type && msg.args){ if('function'===typeof msg.args.callback){ - cbId = genMsgId(msg)+':row'; + rowCallbackId = msg.messageId+':row'; proxy.onrow = msg.args.callback; - msg.args.callback = cbId; - handlerMap[cbId] = proxy; + msg.args.callback = rowCallbackId; + handlerMap[rowCallbackId] = proxy; }else if('string' === typeof msg.args.callback){ toss("exec callback may not be a string when using the Promise interface."); + /** + Design note: the reason for this limitation is that this + API takes over worker.onmessage() and the client has no way + of adding their own message-type handlers to it. Per-row + callbacks are implemented as short-lived message.type + mappings for worker.onmessage(). + + We "could" work around this by providing a new + config.fallbackMessageHandler (or some such) which contains + a map of event type names to callbacks. Seems like overkill + for now, seeing as the client can pass callback functions + to this interface (whereas the string-form "callback" is + needed for the over-the-Worker interface). + */ } } //debug("requestWork", msg); @@ -225,7 +244,7 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){ debug("Posting",msg.type,"message to Worker dbId="+(config.dbId||'default')+':',msg); config.worker.postMessage(msg); }); - if(cbId) p = p.finally(()=>delete handlerMap[cbId]); + if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]); return p; }; }/*sqlite3Worker1Promiser()*/; diff --git a/ext/wasm/testing-worker1-promiser.js b/ext/wasm/testing-worker1-promiser.js index cfae443d06..a2f3a2523d 100644 --- a/ext/wasm/testing-worker1-promiser.js +++ b/ext/wasm/testing-worker1-promiser.js @@ -60,24 +60,41 @@ delete self.sqlite3Worker1Promiser; const wtest = async function(msgType, msgArgs, callback){ + if(2===arguments.length && 'function'===typeof msgArgs){ + callback = msgArgs; + msgArgs = undefined; + } const p = workerPromise({type: msgType, args:msgArgs}); return callback ? p.then(callback).finally(testCount) : p; }; const runTests = async function(){ const dbFilename = '/testing2.sqlite3'; - logHtml('', - "Sending 'open' message and waiting for its response before continuing."); startTime = performance.now(); + + let sqConfig; + await wtest('config-get', (ev)=>{ + const r = ev.result; + log('sqlite3.config subset:', r); + T.assert('boolean' === typeof r.bigIntEnabled) + .assert('string'===typeof r.persistentDirName) + .assert('boolean' === typeof r.persistenceEnabled); + sqConfig = r; + }); + logHtml('', + "Sending 'open' message and waiting for its response before continuing..."); + await wtest('open', { filename: dbFilename, - persistent: true, + persistent: sqConfig.persistenceEnabled, simulateError: 0 /* if true, fail the 'open' */, }, function(ev){ - log("then open result",ev); - T.assert(1 && (dbFilename===ev.result.filename - || (sqlite3TestModule.sqlite3ApiConfig.persistentDirName - + dbFilename)==ev.result.filename)) + const r = ev.result; + log("then open result",r); + T.assert(r.persistent === sqConfig.persistenceEnabled) + .assert(r.persistent + ? (dbFilename!==r.filename) + : (dbFilename==r.filename)) .assert(ev.dbId) .assert(ev.messageId) .assert(promiserConfig.dbId === ev.dbId); @@ -145,11 +162,17 @@ .assert(3 === ev.resultRows[1][0]); }); - const resultRowTest1 = function f(row){ + const resultRowTest1 = function f(ev){ if(undefined === f.counter) f.counter = 0; - if(row) ++f.counter; - //log("exec() result row:",row); - T.assert(null===row || 'number' === typeof row.b); + if(null === ev.rowNumber){ + /* End of result set. */ + T.assert(undefined === ev.row); + }else{ + T.assert(ev.rowNumber > 0); + ++f.counter; + } + log("exec() result row:",ev); + T.assert(null === ev.rowNumber || 'number' === typeof ev.row.b); }; await wtest('exec',{ sql: 'select a a, b b from t order by a', @@ -195,10 +218,9 @@ T.assert('string' === typeof ev.result.filename); }); - await wtest('close').then((ev)=>{ + await wtest('close', (ev)=>{ T.assert(undefined === ev.result.filename); - log("That's all, folks!"); - }); + }).finally(()=>log("That's all, folks!")); }/*runTests2()*/; diff --git a/ext/wasm/testing2.js b/ext/wasm/testing2.js index b051cc04cc..d64fd6e89a 100644 --- a/ext/wasm/testing2.js +++ b/ext/wasm/testing2.js @@ -115,9 +115,15 @@ }, resultRowTest1: function f(ev){ if(undefined === f.counter) f.counter = 0; - if(ev.row) ++f.counter; - //log("exec() result row:",ev.row); - T.assert(null===ev.row || 'number' === typeof ev.row.b); + if(null === ev.rowNumber){ + /* End of result set. */ + T.assert(undefined === ev.row); + }else{ + T.assert(ev.rowNumber > 0); + ++f.counter; + } + //log("exec() result row:",ev); + T.assert(null === ev.rowNumber || 'number' === typeof ev.row.b); } }; diff --git a/manifest b/manifest index ca5ed7147e..2b3fc24b37 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C js:\sresolve\sthe\smysterious\s"extra"\sunhandled\sexception\snotification,\scaused\sby\sinadvertently\sforking\sone\spromise\sinto\stwo\sseparate\sones\s(failing\sto\sproperly\sreassign\sa\sthen()\sresult).\sFix\sa\stypo\sin\snew\sWorker\s1\scode\swhich\scaused\sthe\sDB(filename)\sname\sto\sbe\sincorrect. -D 2022-08-24T14:50:10.920 +C Expand\sthe\sworker1\s'exec'\sop\shandling\sfor\sper-row\scallbacks\sfor\sAPI-level\sconsistency\sand\ssmooth\ssome\sedges\sbetween\sworker1\score\sand\sworker1-promiser.\sAdd\sworker1\s'config-get'\smessage\sto\sfetch\sthe\sserializable\sparts\sof\sthe\ssqlite3.config\sstate.\sImprove\sthe\s'open'\sop's\shandling\sof\sthe\s'persistent'\soption\s(noting\sthat\swe\scannot\syet\stest\sthat\scase\sfrom\sa\sworker). +D 2022-08-24T18:39:46.246 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -483,10 +483,10 @@ F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba814 F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b F ext/wasm/api/sqlite3-api-cleanup.js 1a12e64060c2cb0defd34656a76a9b1d7ed58459c290249bb31567c806fd44de F ext/wasm/api/sqlite3-api-glue.js 67ca83974410961953eeaa1dfed3518530d68381729ed1d27f95122f5baeabd3 -F ext/wasm/api/sqlite3-api-oo1.js f6dcaac3270182471f97efcfda25bd4a4ac1777b8ec52ebd1c6846721160e54c +F ext/wasm/api/sqlite3-api-oo1.js 5ce93b89165e1eb6ef26ba67ae9d3c25379df74eea82edb7b46255f86db21cfc F ext/wasm/api/sqlite3-api-opfs.js 011799db398157cbd254264b6ebae00d7234b93d0e9e810345f213a5774993c0 F ext/wasm/api/sqlite3-api-prologue.js 2d5c5d3355f55eefe51922cec5bfedbec0f8300db98a17685ab7a34a03953c7a -F ext/wasm/api/sqlite3-api-worker1.js b23f66ef5afd350a17fbadb795007098e518a40e5c7c439cd83ef34aa55a45af +F ext/wasm/api/sqlite3-api-worker1.js f7372b84b6d71ebdc0d2a9e7944ce571b4f18e0dd4c1be78282c68b4582558ca F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 0d81282eaeff2a6e9fc5c28a388c5c5b45cf25a9393992fa511ac009b27df982 F ext/wasm/common/SqliteTestUtil.js eb96275bed43fdb364b7d65bcded0ca5e22aaacff120d593d1385f852f486247 @@ -508,14 +508,14 @@ F ext/wasm/scratchpad-opfs-main.js 69e960e9161f6412fd0c30f355d4112f1894d6609eb43 F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5 F ext/wasm/scratchpad-opfs-worker.js 3ec2868c669713145c76eb5877c64a1b20741f741817b87c907a154b676283a9 F ext/wasm/scratchpad-opfs-worker2.js 5f2237427ac537b8580b1c659ff14ad2621d1694043eaaf41ae18dbfef2e48c0 -F ext/wasm/sqlite3-worker1-promiser.js 9638b0ced7f02806c3220b616f08729dde9eb13fb56e125cd4759f40bfa81210 +F ext/wasm/sqlite3-worker1-promiser.js 92b8da5f38439ffec459a8215775d30fa498bc0f1ab929ff341fc3dd479660b9 F ext/wasm/sqlite3-worker1.js 0c1e7626304543969c3846573e080c082bf43bcaa47e87d416458af84f340a9e F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893 -F ext/wasm/testing-worker1-promiser.js 931d909c769c57292f1cafdf10c7dab402d17cd16a6d0ec32089f67b559b058f +F ext/wasm/testing-worker1-promiser.js 81d81eda77c9d4a3e43cfeee91df6c3b039782cc998020d72fe1fdf91790242d F ext/wasm/testing1.html 528001c7e32ee567abc195aa071fd9820cc3c8ffc9c8a39a75e680db05f0c409 F ext/wasm/testing1.js 2def7a86c52ff28b145cb86188d5c7a49d5993f9b78c50d140e1c31551220955 F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3 -F ext/wasm/testing2.js f01e8d7b32f6d4790f8352bf8dc17d2b860afa58f6c8ea1f824ef1c0d2068138 +F ext/wasm/testing2.js 04a4194188d54856027eb4cad7239223a8f7a60e64b0aac81fc1a5a70363b98e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 @@ -2009,8 +2009,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b030f321bd5a38cdd5d6f6735f201afa62d30d2b0ba02e67f055b4895553a878 -R a11ec2b23afafa9cff8838dfde907f0c +P 7467ac88801224089b51c6ba7924f93283dd87beca602a186c83632df26cfc85 +R 4d53a1266e528a954f73a792c3648256 U stephan -Z 64f88270da37ddd3ce54e6e07b8ab1af +Z cffa6daad399e2d401f0fd69f4f04b4f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 521621a6a1..7400cbe177 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7467ac88801224089b51c6ba7924f93283dd87beca602a186c83632df26cfc85 \ No newline at end of file +509f8839201ec1ea4863bd31493e6c29a0721ca6340755bb96656b828758fea7 \ No newline at end of file