@dbrij/ship
v0.1.0
Published
Dbrij Ship SDK: over-the-air updates, feature flags and remote config for mobile apps. Zero dependencies.
Readme
@dbrij/ship
The Dbrij Ship SDK: over-the-air updates, feature flags and remote config for mobile apps. Zero dependencies; works anywhere fetch exists (React Native, Capacitor webviews, Node).
The core speaks the device protocol: check-in (flags + config + kill switch + the update decision) and outcome beacons. Code push itself, downloading and swapping bundles, lives in the per-stack plugins (@dbrij/ship-react-native, @dbrij/ship-capacitor), which drive this core and add the native verify/apply/rollback steps.
Quick start (flags and config, any stack)
import { createShip } from '@dbrij/ship';
import AsyncStorage from '@react-native-async-storage/async-storage'; // or any getItem/setItem pair
const ship = createShip({
appKey: 'shp_...', // from your Ship dashboard
channel: 'production',
binaryVersion: '1.2.0', // the store build version
platform: 'android',
storage: AsyncStorage, // persists the device id + last answer for offline starts
});
const { killSwitch, flags, config } = await ship.checkIn();
if (!killSwitch && ship.getFlag('new_checkout')) {
// ...
}
const apiUrl = ship.getConfig('api_url', 'https://fallback.example.com');Call checkIn() on app launch (and on foreground if you like). The last good answer is cached in storage, so getFlag/getConfig answer instantly and work offline; the kill-switch answer is never cached.
Raw REST (no SDK)
Any stack can integrate with two endpoints:
POST /api/v1/public/ship/checkwith{ appKey, deviceId, channel?, binaryVersion?, currentRelease?, platform? }returns{ killSwitch, flags, config, update, revert }.POST /api/v1/public/ship/reportwith{ appKey, deviceId, releaseId, event }where event isapplied | failed | crashed | reverted.
Generate a stable random deviceId once and persist it; it is an opaque bucketing handle, never personal data.
Code push and signatures
Update descriptors carry sha256 and an ed25519 signature over the ascii hex of that hash, signed with your app's private key (server-held). The plugins verify against the signPublicKey you pin from the dashboard before a byte is applied. If you integrate by REST, do the same: hash the downloaded bundle, verify the signature, only then swap.
Privacy
Pass disabled: true (or call setDisabled(true)) to honour an app-level opt-out: nothing is sent at all. Ship stores only a hash of the device id server-side.
