@mika/blackcurrant (1.1.0)
Installation
@mika:registry=npm install @mika/blackcurrant@1.1.0"@mika/blackcurrant": "1.1.0"About this package
@mika/blackcurrant
Blackcurrant is a client-side data runtime for request-driven stores, journal-backed sync, durable persistence, public and private data lanes, and optimistic/offline mutations.
Install
npm install @mika/blackcurrant @mika/signals uuid
@mika/signals is a peer dependency.
Exports
import {
createCommunication,
createIndexedDbStorage,
createPersistence,
createStore,
} from "@mika/blackcurrant"
Typical Setup
import {
createCommunication,
createIndexedDbStorage,
createPersistence,
createStore,
} from "@mika/blackcurrant"
const persistence = createPersistence({
storage: createIndexedDbStorage(),
})
const communication = createCommunication({
baseUrl: window.location.origin,
})
const users = createStore({
name: "user",
communication,
persistence,
})
const bulletin = createStore({
name: "bulletin",
public: true,
communication,
persistence,
})
Concepts
Blackcurrant is built around three cooperating parts:
CommunicationPersistenceStore
Together they provide:
- single-stream public/private sync
- journal-backed SSE sync
- durable client data
- request-driven stores
- public and private store visibility
- optimistic mutations
- offline mutation replay
Visibility
Stores are private by default.
const inbox = createStore({
name: "inbox",
communication,
persistence,
})
Public stores opt in with public: true.
const bulletin = createStore({
name: "bulletin",
public: true,
communication,
persistence,
})
Key rules:
public: trueuses anonymous transport semantics- omitted
publicmeans authenticated transport semantics - store names must be globally unique across public and private resources
- public stores continue working across login/logout
- private stores clear on logout
Sync Model
Blackcurrant now uses one SSE connection at a time with separate public and private frontiers.
Typical sync URLs look like:
/sync?public=3:120&private=7:45
The stream keeps the existing { type, ... } envelope and may emit:
helloentryresetRequirederror
Private sync startup requires either:
hellowithuserId- or
errorfollowed by stream close
Every entry must include its lane in entry.scope.
Logout And Reset
logout() now rejects with machine-readable codes in two cases:
ERR_LOGOUT_OFFLINEERR_LOGOUT_PENDING_MUTATIONS
Any sync reset clears the full mutation queue, even if only one lane was invalidated.
Migration
See CHANGELOG.md for the step-by-step migration guide for 1.0.0.
Further Reading
Notes
- The package is plain ESM.
- There is no build step.
- Application-specific views, filtering, sorting, and UI belong to the consuming app.
Dependencies
Dependencies
| ID | Version |
|---|---|
| uuid | ^13.0.0 |
Peer dependencies
| ID | Version |
|---|---|
| @mika/signals | ^0.1.0 |