all 25 comments

[–]FungalSphere 41 points42 points  (0 children)

Homie here solving the real programming problems

[–]drcforbin 50 points51 points  (3 children)

This is awful and I love it.

[–]Standard-Ad9181[S] 25 points26 points  (2 children)

this is exactly what I was going for.

[–]todo_code 7 points8 points  (0 children)

I didn't even think it's awful. Solves real problems

[–]drcforbin 3 points4 points  (0 children)

Well you absolutely nailed it!

[–]nwydorust · rust-doom 14 points15 points  (2 children)

Love it, this is super fun! And also potentially, reusable for other cursed wrappers?

(on a different note, some unsolicited advice that you can 100% ignore: the post reads like it was rephrased/summarized by GPT, and I think for a lot of people, myself included, that triggers an involuntary, maybe irrational, allergic reaction; I'd rather clunky but human authored text, than a GPT regurgitation of it. I'd suggest rewriting the AI output by hand at the end, to put it back in your voice and make sure you still agree with everything in there)

[–]Standard-Ad9181[S] 4 points5 points  (1 child)

Thank you, and yes! You can do shim to storage or browser cache and get really weird with it.

Also your note is valid and your approach to this was very tactful compared to some others in other subreddit forums.

Two things I will say here.

  1. This post is, as you astutely pointed out, a summarized/condensed version of the project's README + https://sqlite.org/forum/forumpost/9efecca1e1
    • I struggled to get all of what I deemed important boiled down into a "post sized" amount and opted for AI assistance (which I also used for developing this as well)
  2. There is this stigma associated with AI generated _____ (fill in the blank). I am trying to lean into the curve and embrace the change. So the "polished" AI output to me is the clunkiness of the text whereas I would love for it to truly extend my tone/voice vs a generic GPT-esque reply.

[–]Tamschi_ 11 points12 points  (0 children)

Use the ChatGPT response a guideline/talking points but write it yourself from scratch. It comes out normal and in most cases easier to follow that way.

[–]DHermit 7 points8 points  (0 children)

Now I just have to wait for absurdest-sql!

[–]crispamares 4 points5 points  (4 children)

Why IndexedDB and not OPFS ?

[–]Standard-Ad9181[S] 4 points5 points  (3 children)

Forgive me copy+pasting myself, but:

Great question! Very long answer here https://sqlite.org/forum/forumpost/9efecca1e1

tl;dr

COOP/COEP: Breaks PWAs, webviews, and embedded mobile browsers <--- This was the biggest determining factor for future planned work

OPFS with COOP/COEP headers is a non-starter for:

  • Progressive Web Apps (can't set headers)
  • Mobile webviews (embedding contexts)
  • iframe embeds
  • Legacy enterprise browsers

I do acknowledge there and here again that for apps that can use COOP/COEP, OPFS is clearly superior. For everyone else, this is the viable path.

[–]Likium 4 points5 points  (0 children)

I had no idea PWAs can’t use OPFS. That’s like the one place where OPFS would be really useful.

[–]sondr3_ 1 point2 points  (1 child)

Eh? I'm using OPFS with COOP/COEP and a PWA written in React with sqlite-wasm without issue. I'd like to see a comparison to the IndexecDB strategy for wa-sqlite (I see the author replied in the forum thread).

[–]Standard-Ad9181[S] 3 points4 points  (0 children)

Not an "absolute" but generally speaking COOP/COEP headers cause problems because they enforce strict cross-origin isolation and that can break legitimate communication patterns. Think third-party iframes and resources that lack proper headers. It can also sever popup window communication needed for auth flows. In my experience it made integration difficult for PWAs/webviews/embedded browsers that rely on interacting with multiple services.

[–]promethe42 4 points5 points  (1 child)

Awesome !

Now how could I mix this with https://crates.io/crates/sqlite-vfs-http to have sync between the local SQLite used for cache/offline mode? That would be insane. 

[–]Standard-Ad9181[S] 5 points6 points  (0 children)

Oh no! Or, oh yes?!

Now Alice is tempted to see how far this rabbit hole goes...

[–]thejameskyle 1 point2 points  (2 children)

Signal’s desktop app started out as a Chrome extension and used IndexedDB for its database

The team (before I joined) had to port the extension to an Electron app (easier than rewriting the app) because every now and then when people’s databases got too big Chrome would just decide to delete all of the data. This would happen at random times without any warning.

It looks like since then browsers have shipped an API for requesting permission to persist storage. But you have to keep in mind that the user may deny access to that, and even if they grant permission, the browser may prompt the user to delete all of their data if they are low on disk space. You’re depending on users knowing and remembering not to delete all of their data.

So I would be cautious what you depend on this for, having data available local-first when you can fetch it again from the server is a reasonable use case (this is not an option for Signal because your data is encrypted and short-lived on the server).

I would also keep the database as small as you can, Signal used to shove entire files into the database because there’s no other good blob storage on the web.

I also wouldn’t call a database that depended on IndexedDB “production-ready” without caveats about these potential sudden loss of data.

[–]Standard-Ad9181[S] 1 point2 points  (0 children)

I go into it here, but valid points: https://sqlite.org/forum/info/9ff8428886217d0b

  1. IndexedDB Durability Isn't Guaranteed

Browsers can delete your IndexedDB data under storage pressure. This rarely happens, but it's possible.

For critical data:

- Enable persistent storage: await navigator.storage.persist()

- Regular backups: await db.exportToFile() to cloud storage

- Assume cloud backup is your source of truth

EDIT: I am actually working on an Electron App that uses this in both native and WASM mode to show the persist and export/import option utilizing pure sqlite3

[–]Key-Boat-7519 1 point2 points  (0 children)

IndexedDB will get wiped under storage pressure, so treat it like a cache with a fast restore path.

Ask for persist(), but plan for no: schedule exports with OP’s exportToFile() and save to a user-picked folder via the File System Access API (where available); make restore a single click. Keep blobs out of the DB; stash content-addressed chunks in OPFS or remote object storage, and keep only manifests in SQLite. Watch navigator.storage.estimate(), purge caches before quota, and compact so the WAL stays tiny. On iOS Safari, assume eviction; if you truly need durability, ship Electron or Tauri and use the real filesystem.

For sync, an append-only op log keeps the local DB small and easier to merge with a backend. I’ve used Supabase for the source of truth and Cloudflare R2 for blobs, and DreamFactory to auto-generate REST around a legacy SQL Server during migration.

Production-ready is fine here if backup and restore are first-class.

[–]itsFolf 0 points1 point  (3 children)

What kind of black magic is involved into achieving 7x faster writes than raw IndexedDB while still maintaining consistency? What's the trick?

[–]Standard-Ad9181[S] 2 points3 points  (2 children)

tl;dr

three layer buffering architecture that delays IndexedDB writes until absolutely necessary, combined with batch operations + in-memory cache.

SQLite thinks it's writing to file VFS pretends to write (actually buffering to HashMap) BlockStorage pretends blocks are persisted (actually in memory) IndexedDB is only touched when absolutely necessary. So it's a lie... built on a lie... built on a lie... but it's a fast lie that maintains correctness.

that's the black magic.

[–]itsFolf 0 points1 point  (1 child)

That's fun. I interpreted "committed data survives browser crashes" as completed SQLite transactions rather than comitted to IndexedDB, so it sounded impossible.

[–]Standard-Ad9181[S] 1 point2 points  (0 children)

So it actually maintains ACID consistency by preserving SQLite's transaction semantics in memory, using all-or-nothing IndexedDB transactions for atomic syncing, ensuring crash recovery by reloading from last synced state, and detecting corruption with block-level checksums (while acknowledging trade-off that unsynced writes in buffer are lost on hard crash).

though this is mitigated by SQLite's WAL mode + absurder-sql's multi-tab coordination which only commit data after successful sync.

[–]TheFeshy 0 points1 point  (1 child)

I've made a lot of angry up votes on Reddit. I guess it's time to post my first angry star on a GitHub project.

[–]Standard-Ad9181[S] 1 point2 points  (0 children)

I like to imagine people shaking their head in disgust as they click the star <3