🙀 Uncaught exception TypeError: e._db.sessions[n].hasExpired is not a function
at file:///var/home/aral/.local/share/small-tech.org/kitten/app/kitten-bundle.js:434:9245
at Array.forEach (<anonymous>)
at Timeout._onTimeout (file:///var/home/aral/.local/share/small-tech.org/kitten/app/kitten-bundle.js:434:9215)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7) uncaughtException
Periodic crash due to session garbage collection code #160
🙀 Uncaught exception TypeError: kitten2._db.sessions[sessionId].hasExpired is not a function
at file:///var/home/aral/.local/share/small-tech.org/kitten/app/kitten-bundle.js:206391:45
at Array.forEach (<anonymous>)
at Timeout.garbageCollectSessions [as _onTimeout] (file:///var/home/aral/.local/share/small-tech.org/kitten/app/kitten-bundle.js:206390:21)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7) uncaughtException
Found the cause of this and it was non-trivial. I was encountering it while testing Domain and here’s why it was happening:
I started running this instance of Domain with a non-minified Kitten release. Among other things, this saved instances of the Session class in _db – the internal JSDB database. (JSDB supports persistence of custom data types.)
Then, I experimented with several builds of Kitten where Kitten was minified. While this was great in reducing the size of the bundle from over 8mb to under 5mb, it resulted in the names of identifiers (including classes) to be changed. So, for example, the Session might have been replaced with x1. The first time the database was loaded in with the minified build of Kitten, it could not find the x1 class in memory and so a plain object was created and plain objects, instead of Session instances were subsequently persisted.
As the session cleanup code expects to work with Session instances, it would try to access the hasExpired method, only for it to fail, as seen above.
This has now been fixed in 1af2eed897 where the Kitten bundle is now only built using esbuild’s --minify-whitespace and --minify-syntax flags (so without --minify-identifiers) and with --keep-names so that even if a class name should change due to the bundling, the name property of the class will still be set correctly (and this is what JSDB uses when persisting the entity to its append-only JavaScript log).
(Note that even without --minify-identifiers and with --keep-names, the bundle size currently stands at ~5.9mb, which is not bad at all.)
I’ve also opened a separate issue in JSDB to document this behaviour with a note that minification of identifiers should be avoided in projects that use JSDB.
If your app if affected
If you used any of the minified Kitten builds, you will have to manually clean-up Kitten’s internal database for your app.
To check
From your app’s directory, run:
kitten _db tail sessions --all
If you see entries in the following form, you’re find and don’t need to do anything:
export const _ = {}
_['ezgJlDegjdeQUrie4btAqcqN'] = Object.create(typeof Session === 'function' ? Session.prototype : {}, Object.getOwnPropertyDescriptors({ 'createdAt': 1713546935651, 'authenticated': false, 'id': `ezgJlDegjdeQUrie4btAqcqN` }));
...
If, however, you see plain objects there instead, e.g.,
export const _ = {}
_['ezgJlDegjdeQUrie4btAqcqN'] = { 'createdAt': 1713546935651, 'authenticated': false, 'id': `ezgJlDegjdeQUrie4btAqcqN` };
...
Then you need to nuke the sessions table:
kitten _db delete session
Note that the uploads table will likely also be affected so you might have to remove that also. Or, if you want to maintain your uploads, open the uploads table (remember it’s just a JavaScript file) in your editor of choice and surround the plain objects there with:
Object.create(typeof Upload === 'function' ? Upload.prototype : {}, Object.getOwnPropertyDescriptors({ ... }));
No due date set.
No dependencies set.
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?