One concept per filesystem level
Storage mapping
apps/<application-id>OPFS root/
└── apps/
└── my-app/
├── users/
│ └── alex.json
├── notes/
│ └── welcome.txt
└── settings/
└── appearance.json
The tree is private to the origin and normally invisible to the user's ordinary filesystem. DBOPFS backup is an explicit way to create a downloadable representation.
Import to ready
Initialization lifecycle
- Request persistence.The module asks
navigator.storage.persist()when available. The browser decides whether to grant it. - Create the singleton.If
window.dbopfsdoes not already exposeget(), the module constructs one instance. - Resolve identity.
AppDataScopereconciles explicit, document-declared, and native-bound identities. - Open the app directory.The module opens
apps/<id>beneath the OPFS root. - Create default tables.Known table directories are opened with
{create:true}. - Publish readiness.
readybecomes true anddbopfs-readyis dispatched with the resolved scope.
readyPromise represents that same lifecycle and remains available after the event has already fired.
Fail-closed ownership
Application identity
Canonical IDs match ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$ and are limited to 64 characters.
| Identity source | Role |
|---|---|
Native Arcane.app.current().id | Authoritative when the bridge exists. |
| Explicit constructor option | Useful for controlled adapters and synthetic tests. |
meta[name="arcane-app-id"] | Normal browser-page declaration. |
documentElement.dataset.arcaneAppId | Equivalent document-level declaration. |
Conflicting declarations fail before the OPFS directory is opened. Imported module paths and page URLs are never guessed as ownership.
Browser fallback
Worker fallback
Ordinary main-thread operations use asynchronous FileSystemFileHandle.createWritable() and getFile(). If one is unavailable, DBOPFS creates a dedicated worker from:
new URL('./DBOPFSWorker.js',import.meta.url)
The worker revalidates the application ID, opens the same apps/<id> subtree, and uses a synchronous OPFS access handle. Each request travels through its own MessageChannel; transferable buffers avoid cloning file bytes.
Deployment invariant: renaming or separating the worker breaks fallback loading. Preserve the runtime module directory exactly.
Within one page
Page-local cache and concurrency
Page-local means the cache exists only in JavaScript memory for the current loaded page. It is not another database, it is not saved when the page closes, and a different tab, worker, window, or same-origin script has its own memory and cannot update this cache automatically.
The singleton maintains three private maps:
- table handles, keyed by alias or discovered physical name;
- parsed record values, keyed by table and filename;
- write-lock promises, keyed by
tableName:fileName.
An ordinary get() can return a cached truthy parsed value without reopening the file. Falsey values are read again. Use get(table,key,true) to force a fresh filesystem read when another context—or writeFile()—may have changed that file. See the cache guide for copyable examples and edge cases.
Writes to the same table/key are chained in call order within this page. Writes to different keys may proceed concurrently. Another tab or same-origin script does not share these in-memory locks.
Cache and locks are not transactions. A batch can partially succeed, and await only waits for and sequences promises. It does not make several files one atomic operation. See Async patterns.
What scoping does—and does not—mean
Application folders and same-origin apps
An application ID stores records under apps/<application-id>. This helps prevent accidental reads, restores, or clears between trusted apps that share one browser origin—the same protocol, host, and port. Examples include test apps at example.com/app-a and example.com/app-b, or several apps served from one intranet or extranet host without subdomains.
Protected against accidental helper misuse: backup, restore, enumeration, and clear-all begin at the current apps/<id> directory rather than the origin root.
Organization is not security isolation. A hostile or compromised script already running on the same origin can bypass DBOPFS and request the browser's raw storage APIs. If applications do not trust one another or require isolated databases, place them on separate origins—normally separate domains or subdomains—or use separate browser profiles.
Trusted sharing, preloading, and synchronization
Trusted apps on the same origin can deliberately share a browser-local database by using the same application ID and agreeing on the same tables and data formats. Sharing an ID means sharing access; it should be an explicit design choice.
A browser app can download validated seed files from a server and write them into DBOPFS on first run. It can synchronize files across browsers, devices, or machines through a service you build. DBOPFS 1.0.0 does not provide the server, authentication, authorization, encryption, transport, conflict handling, or synchronization protocol, so those parts must follow the application's own security model.
Built-in preload or synchronization support may be considered in a future release if there is enough interest. Arcane OS already supports DBOPFS database export/import and packaged database prepopulation.
- DBOPFS does not encrypt record contents.
- It does not validate application schemas or sanitize record values.
- It does not prevent browser eviction or user-driven site-data deletion.
- It does not authenticate users or authorize business operations.
- Backup files may contain every record in the current application scope and should be handled accordingly.
Project-site behavior
GitHub Pages
The documentation uses relative links and no root <base>, so it remains valid beneath the project path /DBOPFS/. GitHub Pages supplies HTTPS, which satisfies the secure-context requirement.
All project sites under thewizardnexus.github.io share an origin. The playground therefore uses a distinct dbopfs-playground application directory and warns visitors to store only disposable example data.
The playground imports ../arcane/modules/DBOPFS.js from its page. The release publication step must mirror the installed runtime into the corresponding static site path without modifying its source.
Externalized runtime
Arcane integration
The packaged 1.0.0 artifact from npm or the GitHub Release preserves the existing arcane/modules layout. Arcane OS can replace its in-tree copy with either package source by changing only the directory pointer that serves those modules. See the npm and GitHub Release installation paths.
The 1.0.0 release gate passed a clean tarball install and a Chrome pointer-only import with a real OPFS set/get round trip. See Release status.