Brazen Framework - IndexedDB Storage

IndexedDB storage layer and repositories for Brazen user scripts

Este script não deve ser instalado diretamente. É uma biblioteca destinada a ser incluída por outros scripts através da diretiva de metadados // @require https://update.greasyfork.org/scripts/587030/1884360/Brazen%20Framework%20-%20IndexedDB%20Storage.js

Terá de instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Terá de instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Terá de instalar uma extensão como Tampermonkey para instalar este script.

Terá de instalar uma extensão de gestão de scripts de utilizador para instalar este script.

(Já tenho um gestor de scripts de utilizador, deixe-me instalá-lo!)

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

(Já tenho um gestor de estilos de utilizador, deixe-me instalá-lo!)

Autor
brazenvoid
Versão
1.3.1
Criado
14/07/2026
Atualizado
24/07/2026
Tamanho
90 KB
Licença
GPL-3.0-only

Brazen Framework — IndexedDB Storage (developer guide)

Required for latest-stack apps that use IndexedDB persistence through Configuration Manager. One IndexedDB database per script (scriptPrefix with trailing dash stripped, e.g. brazen-r34xxx). Replaces localStorage/GM aggregate blobs for settings, tags, bookmarks, and download ledger.

Greasy Fork: IndexedDB Storage · Requires: Utilities · Load before: Configuration Manager

Apps do not open the database directly. Use BrazenConfigurationManager.initialize(), getRepos(), and field APIs wired by the configuration manager.


When to use

Scenario This module
New Brazen app with async initialize() + IDB persistence Yes@require before Configuration Manager
Legacy app on driver-only Configuration Manager 3.x No — keep local/GM drivers until migrated
IDB unavailable (private mode, blocked storage) CM sets isIdbBlocked(); persistence disabled, read-only UI

Quick start (script setup hook)

Seed script-specific data during first-time setup via setScriptSetup() on the configuration manager:

this._configurationManager.setScriptSetup(async (repos, cm) => {
  // Seed apis / tagTypes documents (example)
  let apis = await repos.storage.get(IDB_STORE_APIS, 'apis')
  if (!apis?.entries?.length) {
    await repos.storage.put(IDB_STORE_APIS, {
      id: 'apis',
      entries: [{ entryId: 1, name: 'gelbooru', label: 'Gelbooru' }],
    })
  }
})

Legacy local/GM settings and bookmarks are imported automatically during setup by BrazenLegacyImporter when present. Download ledger is IndexedDB-only (no GM ledger import).


Architecture

BrazenConfigurationManager
  └── BrazenStorageRepositories(scriptPrefix, onRepositoryChange?, onRevisionBump?)
        ├── storage   → BrazenIndexedDBStorage (open, close, CRUD, health, zip)
        ├── meta      → MetaRepository (revision, setup lock, entryId counters)
        ├── settings  → SettingsRepository (non-tag field blobs)
        ├── tags      → TagRepository (registry + compile → tagRuleSets)
        ├── tagRules  → TagRuleRepository (row-per-rule by group)
        ├── bookmarks → BookmarkRepository
        ├── ledger    → LedgerRepository
        ├── downloadResolutionQueue → DownloadResolutionQueueRepository
        ├── downloadQueue         → DownloadQueueRepository
        └── downloadManagerState  → DownloadManagerStateRepository

Database stores (schema v2+; IDB_SCHEMA_VERSION is 5)

Store Shape Role
meta singleton revisionId, setup flags, per-store next*EntryId counters, compilePendingGroups
settings singleton document Non-tag config fields (camelCase properties)
apis singleton + entries[] Site/API entities
tagTypes singleton + entries[] Canonical and alias tag types
tags row per tag Append-only registry (name immutable; typeEntryId; isDiscovered discovery gate)
tagRules row per rule Raw lines by group (blacklist, explored, …)
tagRuleSets singleton Compiled rawLines + optimized per tag-domain field
bookmarks row per bookmark Numeric entryId, sortOrder, label/tags/url
ledgerEntries row per post id Download duplicate ledger (postId unique)
downloadResolutionQueue row per itemId Resolution pipeline (status, addedAt indexes)
downloadQueue row per itemId Download pipeline (status, addedAt indexes)
downloadManagerState singleton id: 'state' Shared DM flags, discovery panel, human-interaction, leadership — see createDefaultDownloadManagerState()

Download manager state (createDefaultDownloadManagerState)

Singleton document id: 'state' in downloadManagerState:

Field Role
paused Download queue paused (default true)
resolutionBlocked / resolutionBlockedItemId Tag discovery gate
humanInteractionBlocked / humanInteractionContext / humanInteractionItemId / humanInteractionPromptTabId Rate-limit block
humanInteractionOpenUrl Verification URL for Reopen
processingTabId / processingHeartbeatAt Processor leadership + heartbeat
lastResolutionInitiationAt / lastDownloadInitiationAt Initiation gap clocks
tagDiscoveryEnabled / tagDiscoveryPanelTabId Discovery toggle + panel owner tab
discoveryPanelTags / discoveryPanelKnownTags Tag discovery panel payloads
discoveryReviewMode 'unknown' \
pendingImmediateDownload Gated immediate-download payload
completedResolutionCount / completedDownloadCount Dock progress totals

Download queue stores do not bump meta.revisionId (avoids wiping unsaved settings edits on every processor step).

For large pending queues, prefer repository hot paths over listAll():

Method Role
countActive() Non-terminal count via status index (no fat row bodies)
listActiveItemIds() Primary keys for active statuses only
peekNextQueued() Oldest queued row by addedAt (processor claim)

Public surface (via Configuration Manager)

CM method Role
async initialize() Open DB, setup or normal phase, hydrate fields
getRepos() BrazenStorageRepositories instance
isStorageReady() / isIdbBlocked() / canPersist() Runtime gates
toggleTagRule(fieldKey, tagName) Sidebar-style sole-tag toggle (writes tagRules, compiles)
clearTagRules(fieldKey) Clear all rules in a tag group
scheduleTagRuleCompile(groups) / ensureTagRuleSetsCompiled() Two-phase compile pipeline
async save() / async backup() / async restore() Persistence + v3 zip bundle

Direct repository use (advanced, e.g. bookmark widget per-op):

let repos = this._configurationManager.getRepos()
await repos.bookmarks.add({ label: '…', tags: '…', url: '…', sortOrder: 0 })
let rows = await repos.bookmarks.listAll()

Tag rules pipeline

  1. WritetagRules rows (sidebar toggle, settings Apply, or legacy import).
  2. Mark pending — affected groups added to meta.compilePendingGroups.
  3. Compile — async/microtask: rules → tagRuleSets.*.optimized (compliance hot path reads compiled data only).
  4. OR in new rules — not stored; legacy | lines are expanded on import via expandOrRuleLine().

Backup / restore (v3)

  • Export: zip bundle — one JSON file per store + manifest.json (backup version 3, defined in Configuration Manager as CONFIG_BACKUP_VERSION). STORE method with IEEE CRC-32 per entry.
  • Import: v3 zip or JSON; v2/v1 flat backups still handled by Configuration Manager adapters.
  • Ledger restore: merge by postId (newer claimedAt wins).

Cross-tab sync

meta.revisionId bumps on writes. Configuration Manager listens to visibilitychange only (no BroadcastChannel) and reloads changed fields when revision differs from the cursor it advances on every local bump (onRevisionBump). Same-tab focus after the script’s own writes is a no-op.

Download Manager may call repos.storage.close() on unload so a bfcache'd page cannot pin the database; the next CRUD path calls open() again (concurrent opens are coalesced).


Related modules

  • Configuration Manager — field schema, initialize/save, backup UI
  • UtilitiescoerceBookmarkArray, reviveGmStoredValue, objectFromJSON (legacy GM clone revival)
  • Framework coreasync init(), IDB-blocked banner, compliance after compile

Workspace technical reference: BrazenIndexedDBStorage.spec.md