Capability first · transport second

DBOPFS.js

Provides app-scoped OPFS tables, committed-change subscriptions with targeted cache freshness, explicit non-recursive empty-table removal, worker I/O, backup/restore, compression, and CRUD/batch APIs.

SDK 0.97.1Runtime 0.8.12Protocol arcane/1
On this page

Overview

Provides app-scoped OPFS tables, committed-change subscriptions with targeted cache freshness, explicit non-recursive empty-table removal, worker I/O, backup/restore, compression, and CRUD/batch APIs.

  • Artifact
    DBOPFS.js · esm
  • Classification
    public first party
  • Availability
    Browser / native WebView
  • Normalization
    App scope and recognized file parsing are normalized; nonblank unreadable JSONL rows remain complete raw strings, empty-table removal reports removed, absent, or not-empty after a create:false directory lookup and without scanning or recursively clearing a directory, same-named files are preserved, aliases and cached handles are invalidated only when the directory is gone, and unexpected DOM/storage errors are preserved.

Import and lifecycle

JavaScript
import * as module from '/node_modules/arcane-os/runtime/arcane/modules/DBOPFS.js';

Browser import installs window.dbopfs, asynchronously opens or creates only the app OPFS scope, and emits dbopfs-ready. No table directory is created until a caller requests it; clearAllStorage leaves the emptied app scope without recreating product directories. CRUD and backup methods read, write, delete, download, or restore files. Successful mutations publish committed-change metadata through the existing event source and one app-scoped native BroadcastChannel. pagehide closes the channel; pageshow reopens it and clears only memory caches without fabricating a change.

Application-facing behavior: default DBOPFS; installs window.dbopfs, emits dbopfs-ready; subscribeChanges(listener,{signal,once}) observes DBOPFSEVENTTYPES.change (dbopfs-change), returns idempotent unsubscribe/.dispose, and publishes metadata {applicationId,storagePath,tableName,directoryName,fileName,action,originId,sequence,changeId,remote} after successful storage commits only. Actions are write/append/delete/table-delete; batches preserve partial success, remote receipts invalidate targeted aliases before local publication and never rebroadcast, and pagehide/pageshow closes/reopens the native channel and clears memory caches without replay or fabricated changes. Local subscription/storage continue when BroadcastChannel is unavailable. Table/file/backup APIs include getTableHandle(tableName='',{create=true}={}), readFile(tableName='',fileName='',{createTable=true}={}), get(tableName='',fileName='',force=false,{createTable=true}={}), and removeEmptyTable(tableName). Explicit create:false/createTable:false reads existing tables without creation or joining pending create work; default lazy creation remains unchanged. Low-level missing tables/files reject NotFoundError; get retains parsed caching/force semantics and resolves null only for NotFoundError, propagating other failures. Worker fallback reads already use existing app/table/file handles. createCompressedPNG({tableNames,additionalTables,signal}) returns a PNG Blob without download or record writes; omitted names select all, [] none, and supplied tables replace matching saved tables in the export. downloadCompressedPNG(name,options) reuses the same preparation and initiates one download; cancellation prevents it. restoreFromPNG(file,{selectTables}) closes the decoded image after pixel extraction, awaits the optional caller selection/projection before any writes, and rejects DBOPFSRESTOREWRITEFAILED AggregateError after all selected table batches settle when records fail, preserving original errors and failures {tableName,fileName,reason}; successful writes remain. No-options restore and setMany retain their contracts.

Protocol and host implementation

OPFS, DBOPFSWorker, Compression Streams, per-realm globalThis.arcaneEvents authority, and native BroadcastChannel for live same-app/storage-partition committed changes This detail does not widen the application-facing API or grant authority.

Exports, signatures, parameters, and results

BindingFormDeclaration or signatureParameter syntax
DBOPFS_EVENT_TYPESvariable · valuevariable DBOPFS_EVENT_TYPES—
DBOPFS_REASONSvariable · valuevariable DBOPFS_REASONS—
defaultdefault · classclass DBOPFS—
MemberKindExact public declarationParameter syntax
DBOPFS.constructorconstructorconstructor(options={})options={}
DBOPFS.readyfieldready=false;—
DBOPFS.readyPromisefieldreadyPromise=Promise.resolve();—
DBOPFS.applicationIdgetget applicationId()—
DBOPFS.storagePathgetget storagePath()—
DBOPFS.subscribeChangesmethodsubscribeChanges(listener,options={})listener,options={}
DBOPFS.tablesgetget tables()—
DBOPFS.tablessetset tables(update={tableName:'',fileName:'',value:''})update={tableName:'',fileName:'',value:''}
DBOPFS.getTableHandleasync methodasync getTableHandle(tableName='',{create=true}={})tableName='',{create=true}={}
DBOPFS.setasync methodasync set(tableName='',fileName='',value={}, append=false)tableName='',fileName='',value={}, append=false
DBOPFS.writeFileasync methodasync writeFile(tableName='',fileName='',fileData='',append=false)tableName='',fileName='',fileData='',append=false
DBOPFS.readFileasync methodasync readFile(tableName='',fileName='',{createTable=true}={})tableName='',fileName='',{createTable=true}={}
DBOPFS.getFileMetadataasync methodasync getFileMetadata(tableName='',fileName='')tableName='',fileName=''
DBOPFS.setManyasync methodasync setMany(tableName,items)tableName,items
DBOPFS.getasync methodasync get(tableName='',fileName='',force=false,{createTable=true}={})tableName='',fileName='',force=false,{createTable=true}={}
DBOPFS.getManyasync methodasync getMany(tableName,items)tableName,items
DBOPFS.getAllasync methodasync getAll(tableName='',force=false)tableName='',force=false
DBOPFS.deleteasync methodasync delete(tableName='',fileName='')tableName='',fileName=''
DBOPFS.deleteManyasync methodasync deleteMany(tableName,fileNames)tableName,fileNames
DBOPFS.deleteTableasync methodasync deleteTable(tableName)tableName
DBOPFS.removeEmptyTableasync methodasync removeEmptyTable(tableName)tableName
DBOPFS.clearAllStorageasync methodasync clearAllStorage()—
DBOPFS.clearasync methodasync clear(tableName)tableName
DBOPFS.getAllKeysasync methodasync getAllKeys(tableName)tableName
DBOPFS.getTableNamesasync methodasync getTableNames(discover=false)discover=false
DBOPFS.filterKeyIncludesasync methodasync filterKeyIncludes(tableName,subString='')tableName,subString=''
DBOPFS.hasKeyasync methodasync hasKey(tableName,key)tableName,key
DBOPFS.countasync methodasync count(tableName)tableName
DBOPFS.createCompressedPNGasync methodasync createCompressedPNG({tableNames, additionalTables = {}, signal} = {}){tableNames, additionalTables = {}, signal} = {}
DBOPFS.downloadCompressedPNGasync methodasync downloadCompressedPNG(name = 'DBOPFS-backup', options = {})name = 'DBOPFS-backup', options = {}
DBOPFS.restoreFromPNGasync methodasync restoreFromPNG(file, {selectTables} = {})file, {selectTables} = {}

Parameter meanings and results

subscribeChanges(listener,{signal,once}) observes DBOPFS_EVENT_TYPES.change (dbopfs-change), returns idempotent unsubscribe/.dispose, and receives event.detail {applicationId,storagePath,tableName,directoryName,fileName,action,originId,sequence,changeId,remote}. Actions are write, append, delete and table-delete; fileName is null for table removal. Successful close/flush/removal precedes notification, and targeted caches and aliases are invalidated before listeners run. Partial batches publish each successful mutation without claiming a transaction; reads, missing targets and failed writes emit no change. Cross-document receivers invalidate before local publication and never rebroadcast. Subscriptions are live-only: subscribe before the initial read; application-owned refresh handles missed events after suspension. No bodies are included or reread, and outside-DBOPFS writes are not observed. Storage remains functional without BroadcastChannel; notification failures remain separate from committed storage outcomes. After readyPromise, getTableHandle(tableName='',{create=true}={}) lazily opens or creates one requested table and coalesces concurrent create requests for the same physical directory. Explicit create:false only opens an existing table and does not join a pending create; missing tables reject with NotFoundError. readFile(tableName='',fileName='',{createTable=true}={}) forwards the table selection and returns the complete raw file, rejecting missing tables/files with NotFoundError. get(tableName='',fileName='',force=false,{createTable=true}={}) retains parsed-value caching and force semantics, forwards createTable on actual reads, resolves null only for NotFoundError, and propagates other errors. force:true with createTable:false reads existing storage without earlier cached values or table creation. Defaults, app-scope initialization, and write behavior remain unchanged. Worker fallback reads already open app/table/file handles with create:false. removeEmptyTable(tableName) resolves the target through getDirectoryHandle(name,{create:false}), then asks OPFS to remove that directory non-recursively and resolves {status:'removed'|'absent'|'not-empty',removed,tableName,directoryName}. It never creates, scans, clears, or recursively removes the target; a same-named file and unexpected platform errors reject without removal. The logical memories table retains its physical memory directory and cache aliases are invalidated when that directory is removed or absent. Existing directories remain discoverable. createCompressedPNG({tableNames,additionalTables,signal}) returns a PNG Blob without download or record writes; omitted tableNames selects all saved tables, [] selects none, absent selected tables stay empty without directory creation, and each caller-owned additionalTables table replaces the same saved table in this export only. downloadCompressedPNG(name,options) reuses that method and downloads once. Cancellation stops further preparation and prevents a later download; in-flight browser file/canvas work cannot be interrupted. restoreFromPNG(file,{selectTables}) decodes once, awaits the optional application callback on the complete table/file map, then writes only its returned map; callback errors precede writes, and omitted callback retains all-table restoration. setMany and same-key write serialization remain unchanged. Storage is rooted at apps/<authoritative-app-id>, and worker fallback handles synchronous OPFS access.

Events, side effects, and errors

Source-literal CustomEvent dispatches

No source-literal CustomEvent dispatch is part of this artifact.

Lifecycle and event flow

  • dbopfs-ready
  • dbopfs-change through DBOPFS_EVENT_TYPES.change; committed local and remote storage metadata

Direct coded failures

  • DBOPFS_RESTORE_WRITE_FAILED

Exported Error subclasses

This artifact exports no Error subclass.

Documented failure behavior

  • APP_DATA_SCOPE_INVALID
  • APP_DATA_SCOPE_MISMATCH
  • APP_DATA_SCOPE_REQUIRED
  • APP_DATA_STORAGE_UNAVAILABLE
  • DBOPFS_RESTORE_WRITE_FAILED: AggregateError.errors preserves original rejected writes; failures contains tableName, fileName, and reason after every table batch settles; successful writes remain saved
  • DOM, OPFS, worker, serialization, compression, and backup validation failures

Availability and capabilities

Browser / native WebView. App scope and recognized file parsing are normalized; nonblank unreadable JSONL rows remain complete raw strings, empty-table removal reports removed, absent, or not-empty after a create:false directory lookup and without scanning or recursively clearing a directory, same-named files are preserved, aliases and cached handles are invalidated only when the directory is gone, and unexpected DOM/storage errors are preserved.

Normalized app-scoped browser and native-WebView persistence; Arcane.app.current supplies authoritative identity when native, but Core is not a database service.

Contract example

JavaScript
import '/node_modules/arcane-os/runtime/arcane/modules/DBOPFS.js';

await window.dbopfs.readyPromise;
await window.dbopfs.set('notes','welcome',{text:'Hello'});
console.log(await window.dbopfs.get('notes','welcome',true));

No direct Core call is claimed for this artifact. Any injected provider or consuming module retains its own documented authority.