npm.io
0.2.8 • Published 6h ago

@flexstore/core

Licence
MIT
Version
0.2.8
Deps
1
Size
197 kB
Vulns
0
Weekly
0

@flexstore/core

Framework-agnostic FlexStore sync engine for browsers.

Repository: github.com/flexstoresync/flexstore-core

Data flow

flowchart TB
  subgraph App["Your UI"]
    UI[React / Vue / Angular / vanilla]
  end

  subgraph Core["@flexstore/core"]
    CLIENT[SyncClient]
    SCHED[Scheduler]
    TRANS[Transport]
    CLIENT --> SCHED
    SCHED --> TRANS
  end

  subgraph Local["Browser local store default"]
    SQL[SQLite WASM]
    IDB[(IndexedDB\ndatabase file)]
    SQL --> IDB
  end

  subgraph Remote["flexstoresync server"]
    API[Sync API]
    LEDGER[(Ledger)]
    API <--> LEDGER
  end

  UI <-->|create / query / subscribe| CLIENT
  CLIENT <-->|upsert / pending / cursors| SQL
  TRANS <-->|push / pull / check-deltas| API

Write path (offline-first):

sequenceDiagram
  participant UI as App UI
  participant SC as SyncClient
  participant DB as SqliteStore
  participant IDB as IndexedDB
  participant API as Sync API

  UI->>SC: create / update / remove
  SC->>DB: upsert row + sync_status
  DB->>IDB: persist SQLite pages
  SC-->>UI: immediate local read

  Note over SC,API: background when online
  SC->>API: check-deltas → push → pull
  API-->>SC: remote changes
  SC->>DB: apply pulled rows
  SC-->>UI: subscribe callback

npm install @flexstore/core @journeyapps/wa-sqlite

@journeyapps/wa-sqlite is a direct dependency of core but must be resolvable by your bundler (Vite/Webpack) for the WASM module.

Vite

// vite.config.ts — allow WASM + wa-sqlite subpaths
export default defineConfig({
  optimizeDeps: {
    exclude: ['@journeyapps/wa-sqlite', '@flexstore/core'],
  },
});

Quick start

import { createSyncClient, defineResource, resourceRegistry } from '@flexstore/core';

const todos = defineResource({
  name: 'todos',
  attributes: { title: 'string', done: 'boolean' },
});

const client = createSyncClient({
  baseUrl: 'http://localhost:8088',
  apiKey: 'my-key',
  tenantId: 'my-tenant',
  resources: resourceRegistry(todos),
  // store: default SqliteStore (SQLite WASM → IndexedDB)
});

await client.start();
await client.create('todos', { title: 'Buy milk', done: false });
const open = await client.query('todos', { done: false });

Store adapters

Adapter Export When
SQLite WASM (default) SqliteStore Production — SQL surface, IDB-backed file
Legacy document store IndexedDbStore Migration / debugging only
import { createSyncClient, IndexedDbStore } from '@flexstore/core';

createSyncClient({
  ...config,
  store: new IndexedDbStore(['todos'], 'flexstore-legacy'),
});

Implement FlexStoreAdapter (see index.d.ts) for React Native, Node, etc.

Pub/sub + fallback polling

When pubsubUrl is set, the client subscribes to SSE sync hints for near-real-time pulls. A background check-deltas timer still runs as a safety net:

Mode Config Default
Pub/sub connected pubsubFallbackPollMs / pollIntervalConnectedMs 60s
Pub/sub down / off pollIntervalDisconnectedMs 4s
createSyncClient({
  baseUrl: 'http://localhost:8088',
  pubsubUrl: 'http://localhost:8090',
  pubsubFallbackPollMs: 60_000, // or 0 for hints-only while connected
  pollIntervalDisconnectedMs: 4_000,
  // ...
});

useSyncStatus() / client.status expose pollIntervalMs (active timer) and pubsubFallbackPollMs (configured fallback).

Framework wrappers

Package Repo
@flexstore/react flexstore-react
@flexstore/vue flexstore-vue (composables)
Angular Use createSyncClient + inject a singleton service (see packages/angular in monorepo)
Repo Role
flexstore-self-host Docker sync server
flexstore Monorepo + design docs

License

MIT — see LICENSE.

Keywords