npm.io
0.2.0 • Published 5d ago

tile-live-layer

Licence
UNLICENSED
Version
0.2.0
Deps
0
Size
33 kB
Vulns
0
Weekly
118

tile-live-layer

Remote config SDK for Tile (Expo / React Native) apps.

Fetches a per-(app, environment) nested JSON config from the CDN, sliced by a generic category, caches it, and reads values on-device with a 4-layer fallback so a read never fails and the app never blocks on the network:

live (network)  →  cached (AsyncStorage)  →  bootstrap (baked at build)  →  code default

Config is arbitrary nested JSON — read any path with useLiveLayer(['home', 'cta', 'label']). It is fully decoupled from OTA bundles.

Install

npm install tile-live-layer
# AsyncStorage enables cross-launch persistence (optional but recommended):
npx expo install @react-native-async-storage/async-storage

Usage

import { LiveLayerProvider, useLiveLayer } from 'tile-live-layer';
import bootstrap from './assets/tile-live-layer.json'; // baked at build time

export default function App() {
  return (
    <LiveLayerProvider
      options={{
        appId: 'YOUR_APP_ID',
        env: 'prod',                 // 'dev' | 'staging' | 'prod' | 'preview'
        baseUrl: 'https://storage.googleapis.com/tile-livelayer-configs',
        // The category this user/session belongs to, computed from on-device
        // signals at boot. The SDK fetches the longest existing prefix of this
        // key (falling back to the base layer []).
        context: ['in', 'mumbai'],
        bootstrap,
        refreshOnForeground: true,
      }}
    >
      <Screen />
    </LiveLayerProvider>
  );
}

function Screen() {
  const label = useLiveLayer<string>(['home', 'cta', 'label'], 'Shop now');
  const timeout = useLiveLayer<number>(['checkout', 'timeoutMs'], 8000);
  // ...
}
Categories

A category is an ordered array of arbitrary strings (['in', 'mumbai']) — region, tier, A/B bucket, anything. The app declares which category it belongs to via the provider's context; the SDK fetches the longest existing prefix of it from the manifest, falling back through the chain to the base layer:

['in','mumbai','pro']  →  in/mumbai/pro → in/mumbai → in → (base)

Each category is one already-resolved flat document — the SDK fetches exactly one file and does no merging on-device.

Hooks
  • useLiveLayer(path, fallback?) — read one nested value, e.g. useLiveLayer(['home','cta','label'], 'Shop now').
  • useLiveLayerAll() — the whole active config document.
  • useLiveLayerStatus(){ config, category, version, status, source, error, refresh }.
Debug panel

Render anywhere inside the provider to see live status + every resolved value:

import { LiveLayerDebugPanel } from 'tile-live-layer';
<LiveLayerDebugPanel />

Build-time snapshot & management — the tile CLI

Management and build-time snapshots are handled by the unified tile CLI (npm i -g @tile/cli).

# bake the current published base config into your assets so first launch
# (no network, no cache) still shows real values:
tile live-layer pull --app YOUR_APP_ID --env prod --out assets/tile-live-layer.json

# manage config headless (CI / agents) — auth via `tile login` or TILE_TOKEN:
tile live-layer get                                            # base config
tile live-layer get home.cta.label --category in/mumbai        # one nested path
tile live-layer set home.cta.label="₹500 off" --category in/mumbai
tile live-layer publish --file config.json --category in/mumbai # replace whole category
tile live-layer layers                                         # list categories
tile live-layer versions --category in/mumbai
tile live-layer rollback --to 3 --category in/mumbai
tile live-layer rm-layer in/mumbai                             # delete a category

Writes are atomic per category (optimistic-locked, auto-retry once on a 409).

How serving works

The backend publishes a no-cache manifest plus one immutable blob per category:

live-layer/{appId}/{env}/manifest.json              no-cache  (which categories exist + current blob)
live-layer/{appId}/{env}/v/{N}.json                 immutable (base layer)
live-layer/{appId}/{env}/{category}/v/{N}.json      immutable (e.g. in/mumbai/v/3.json)

The SDK reads the manifest each launch (cheap, non-blocking via stale-while-revalidate), picks the longest matching category, and fetches that one immutable blob at most once per version per device. Point baseUrl at a CDN domain later with no code change.

Keywords