An Experiment writting tiddlywiki filteroperators and JS Widgets for local storage

I understand the concern about us presenting LLM generated content. However this was supprising to me, perhaps because it knows more about tiddlywiki from my past conversations.

  • I have done rudimentary testing so its not halucinating

I first asked it to read in the code from the sort filter operator as an example then asked it to provide a filter operator to read and set local storage.

It came back with a filter operator localstorage[] and widget $action-localstorage. After setting the type and module-type, a save and reload and they worked out of the box.

The are internaly self documented and a number of tests to add/clear/read/list all worked, confirmed in the local storage part of the browser console. Seriously impressive.

I attach them here is you want to experiment or review the quality of the coding if you know how.
local-storage-plugin.json (9.6 KB)

I did skim the code and it seems to look OK. There is only one thing, which caught my eye. It does check if localstorage is available and still uses a try/catch construction for every local storage access. That may be possible to optimise. … But there would be some experiments needed.

Which LLM did you use?

What’s your usecase?

We do have the local-storage core plugin, which saves all tiddlers. So you can write to a data-tiddler and be sure, it will have values.

Thanks for taking the time to look @pmario I used my paid chatgpt

perhaps tell me what to ask to optimise it?

my use case was a simplified way to save and get values to support a range of explorations from saving passwords, detecting wikis in tabs, saving incidental data, session focused data.

  • saving a global value without needing to modify the tiddler store and more.
  • storing json and other possible enablers.

Thanks for reminding me of the local storage plugin, there may be some interesting tricks to be had making virtual or persistent tiddlers.

all very speculative :nerd_face:

more…
storing various clipboards, cumulative values, list cache, bookmarklet integrations. most recently used, entered, selected tools.

I would love to give the save as dialogue a default fieldname that includes a full path but still with user confirmation. Perhaps it won’t help, but I am always trying to find new hacks.

Oh, that one may be interesting. IMO we do not have a functionality like that. At least I don’t know it. (Which means nothing, since I can’t remember my own blog posts here :wink: )

OK. It seems the quality of paid models seems to be much better than the free stuff.


IMO storing passwords in plain text in the local-storage is not the best idea. Even if “only” the 1 user has access to the PC.

The other problem is, that eg: file:// URL is treated as one domain. The local storage keeps values on a “per domain” basis. So different single file wikis may see all the storage.

That’s why we did need some special handling for the local-storage plugin. So wikis can only see their values.

Unfortunately, this may add a lot of extra complexity to the code.

it’s also the recent chatgpt 5 and it is primed by knowledge of my tiddlywiki interactions with it.

I am aware of the security concerns you raise. recent discussions on encryption keys came to mind but yes to trust it needs more work, and may differ for http vs file. While file:// has its problems it also has opportunities.

personally I mostly use file based wikis, lots of them in fact, being able to get bespoke filter operators and action widgets along with possible interwiki communications, window management etc… gives me room to experiment.

I note that local storage seems to be restricted to the current path of a wiki, needs more research.

I did have a closer look at the try/catch constructions, using Gemini-2.5-pro command line app.

I did ask:

The file @tw-filter.js contains a function lsAvailable() which checks if browser local storage is available. within the other function definitions there still is a try / catch construct. Is this really needed, or can it be avoided?

The answer was: TLDR; Yes, for best practice, it is needed

Is try/catch needed if local-storage is accessed?

✦ That’s an excellent question. It shows you’re thinking about code redundancy and efficiency.

Even with the lsAvailable() check at the beginning, the try/catch blocks inside the other functions are still necessary for robust, error-free execution in all scenarios. Here’s why:

  1. The lsAvailable() check is not exhaustive: Your lsAvailable() function checks if the localStorage object itself exists. This is a great first step. However, some browsers or browser
    settings (especially in private/incognito modes or with strict security settings) allow the localStorage object to exist, but will then throw an error if you actually try to use it (e.g.,
    by calling getItem()). The initial check would pass, but the subsequent call would fail.

  2. Handling QuotaExceededError: While this code only reads data with getItem(), localStorage has a finite size (usually 2-5MB). If other scripts were aggressively writing to localStorage,
    it’s theoretically possible for even a read operation to be affected in some browser implementations, although this is rare. For setItem(), this is a very common error to handle. The
    pattern of wrapping all storage interactions in try/catch is a defensive best practice.

  3. Guarding Against Invalid JSON: The try/catch block around JSON.parse() is absolutely critical and unrelated to localStorage’s availability. It handles cases where a value is retrieved from
    storage that is not valid JSON. Without it, calling JSON.parse() on a malformed string would throw a SyntaxError and crash the entire filter operation.

In summary, the lsAvailable() function guards against the environment not supporting localStorage at all (like on a server with Node.js). The subsequent try/catch blocks provide a more
granular, essential level of safety against runtime errors that can occur even when localStorage is theoretically available.

The code is well-written and defensively programmed to be resilient in the unpredictable environment of various user browsers and settings. You can safely keep the try/catch blocks as they
are.

I did fact check it on stackoverflow and some Chrom blog posts and MDN. – And it seems to be true.

Second question:

Does try/catch cause a performance hit? Filter operations are performance critical, sice they can have 1000th of input elements that may be executed.

Answer: TLDR; With modern browser engines it is negligible. (remark: Which seems to be true. In reality it should be optimised, iff there is a performance problem)

Does try/catch have a performance impact?

✦ You’re right to be performance-conscious. In high-frequency operations, every instruction can matter.

Here’s the breakdown of the performance impact of try/catch in modern JavaScript engines:

  1. The “Fast Path”: In modern JavaScript engines (like V8 in Chrome/Edge, SpiderMonkey in Firefox), the try block itself has a negligible, and often zero, performance cost as long as no
    exception is thrown. The JIT (Just-in-Time) compiler is smart enough to optimize the code within the try block assuming the happy path.

  2. The “Slow Path”: The performance cost is only paid when an exception is actually thrown and caught. The process of creating the error object, unwinding the call stack, and executing the
    catch block is where the real work happens.

Applying this to your code:

The try/catch blocks are only entered in exceptional circumstances:

  • A browser’s security settings prevent storage access.
  • A value that is supposed to be JSON is malformed.

For the thousands of successful, normal operations, the code will stay on the “fast path,” and the performance impact of the try statement will be virtually undetectable.

Conclusion: The Trade-off is Worth It

The cost of not having the try/catch is an uncaught exception, which would crash the filter and likely disrupt the user’s interaction with TiddlyWiki.

  • Cost of try/catch: Near-zero in 99.9% of cases.
  • Cost of no try/catch: A brittle filter that can crash the UI.

You are making a wise trade-off. The immense gain in robustness and stability far outweighs the minimal performance overhead. For performance-critical code like this, preventing crashes from
edge cases is paramount. Keep the try/catch blocks.

1 Like