Shipeasy
ReferenceTypeScript / JavaScript

Snippets

Minimal copy-paste blocks for flags, configs, kill switches, experiments and i18n.

Minimal copy-paste blocks, grouped by the registry taxonomy. These are the same leaves the docs get op returns.

release

release / flags

Read a feature flag per user with a bound Client. Assumes configure() ran at startup — see Installation.

import { Client } from "@shipeasy/sdk/server"; // or "@shipeasy/sdk/client"

// construct once per callsite (cheap; binds the user + runs the attributes transform)
const flags = new Client(currentUser);

// getFlag(name, defaultValue?)
//   name         — the flag/gate name
//   defaultValue — returned ONLY when the flag can't be evaluated
//                  (client not ready / flag not found); defaults to false
if (flags.getFlag("{{FLAG_KEY}}", false)) {
  // ship it
}

release / configs

Read a typed dynamic config (with a default when the key is absent). Assumes configure() ran at startup — see Installation.

import { Client } from "@shipeasy/sdk/server"; // or "@shipeasy/sdk/client"

// construct once per callsite (cheap; binds the user)
const flags = new Client(currentUser);

// getConfig<T>(name, opts?)
//   name             — the config name
//   opts.defaultValue — returned when the config key is absent
//   opts.decode       — optional (raw) => T to validate/shape the stored value
const cfg = flags.getConfig<{ max: number }>("{{CONFIG_KEY}}", {
  defaultValue: { max: 50 }, // used when the key isn't published
  decode: (raw) => raw as { max: number }, // optional — typed decode / zod parse
});

release / killswitches

Read a kill switch (not user-bound — global on/off, optionally per-switch). Assumes configure() ran at startup — see Installation.

Whole kill switch

import { Client } from "@shipeasy/sdk/server"; // or "@shipeasy/sdk/client"

// construct once per callsite (cheap; binds the user)
const flags = new Client(currentUser);

// getKillswitch(name, switchKey?)
//   name      — the kill switch name
//   switchKey — optional; reads a single named override switch instead of
//               the whole-killswitch "killed" flag
if (flags.getKillswitch("{{KILLSWITCH_KEY}}")) {
  // killed — short-circuit the feature
}

Named switch (with fallback)

const flags = new Client(currentUser); // construct once per callsite

// Pass the variable to gate as the switchKey. A CONFIGURED switch returns its
// own value; an UNCONFIGURED switch falls back to the whole-killswitch "killed"
// value — so this is always safe to call before any per-key override exists.
if (flags.getKillswitch("{{KILLSWITCH_KEY}}", "apple_pay")) {
  // the "apple_pay" switch is on (or the whole kill switch is killed)
}

release / experiments

Read an experiment's params, then record the conversion event on the same bound Client. Assumes configure() ran at startup — see Installation.

import { Client } from "@shipeasy/sdk/server"; // or "@shipeasy/sdk/client"

// construct once per callsite (cheap; binds the user + runs the attributes transform)
const flags = new Client(currentUser);

// getExperiment<P>(name, defaultParams, decode?)
//   name          — the experiment name
//   defaultParams — params returned when NOT enrolled (control / holdout); also
//                   defines the param shape P
//   decode        — optional (raw) => P to validate/shape the group's params
const { inExperiment, group, params } = flags.getExperiment(
  "{{EXPERIMENT_KEY}}",
  { primary_label: "Sign up" }, // defaultParams (used when not enrolled)
);

render(params.primary_label);

// On conversion — Client-only track (NOT the Engine); the unit is inferred
// from the bound user (user_id, else anonymous_id):
//   track(eventName, props?)
//     eventName — the success event name
//     props     — optional metric properties (private attrs are stripped)
flags.track("{{SUCCESS_EVENT}}", { group }); // props optional

metrics

metrics / track

Track a metric/conversion event from the bound Client. Metrics in the dashboard are computed from these events. Assumes configure() ran at startup — see Installation.

Track an event

import { Client } from "@shipeasy/sdk/server"; // or "@shipeasy/sdk/client"

// construct once per callsite (cheap; binds the user)
const flags = new Client(currentUser);

// track(eventName, props?)
//   eventName — the event your metric is built on (required)
//   props     — optional payload; numeric/string fields you can sum/filter on
//               in a metric (private attributes are stripped before egress)
flags.track("{{EVENT_NAME}}", { amount: 49, currency: "usd" });

Fire-and-forget (never blocks your response) and a no-op under configureForTesting() / configureForOffline(). The unit is the bound user (user_id, else anonymous_id); with no unit the call is a no-op.

Track without properties

const flags = new Client(currentUser); // construct once per callsite

flags.track("{{EVENT_NAME}}"); // props are optional

i18n

i18n / setup

Wire the i18n loader via the SSR bootstrap (it rides the server shipeasy() handle — no separate i18n init). The loader serves the {{PROFILE}} profile and hydrates window.i18n. Full root-layout wiring is on the Installation page.

// app/layout.tsx — Next.js root layout (React Server Component)
import { shipeasy } from "@shipeasy/sdk/server";

// construct once per request (the SSR bootstrap handle; binds this request)
const se = await shipeasy({ serverKey: process.env.SHIPEASY_SERVER_KEY ?? "" });

// getBootstrapData(emit?)
//   emit.clientKey — public client key embedded in the i18n loader tag (NOT
//                    the flags bootstrap tag); selects the {{PROFILE}} profile
const boot = se.getBootstrapData({
  clientKey: process.env.NEXT_PUBLIC_SHIPEASY_CLIENT_KEY, // profile: {{PROFILE}}
});

// Render REAL <script> elements (dangerouslySetInnerHTML scripts do NOT run):
<script src={boot.bootstrap.src} {...boot.bootstrap.attrs} />;
{
  boot.i18nLoader && <script src={boot.i18nLoader.src} {...boot.i18nLoader.attrs} />;
}

i18n / render

Render a translated label with the i18n facade. The fallback is the source string; it shows until the loader resolves. Assumes the i18n loader is wired at startup — see Installation.

import { i18n } from "@shipeasy/sdk/client";

// t(key, fallback, variables?)
//   key       — the translation key
//   fallback  — source string shown until the loader resolves (and the
//               extractable default)
//   variables — optional {{var}} interpolation values
i18n.t("checkout.cta", "Place order");
i18n.t("cart.count", "{{count}} items", { count: cart.length }); // variables

ops

ops / see

Report a caught, handled error (or a non-exception "violation") to Shipeasy with see() — fire-and-forget, never re-throws. Package-level, so it reports against the configuration from configure(). Assumes configure() ran at startup — see Installation.

Report a handled exception

import { see } from "@shipeasy/sdk/server"; // or "@shipeasy/sdk/client"

try {
  await charge(order);
} catch (e) {
  // .causes_the(subject)   what the error affects (e.g. "checkout")
  // .to(outcome)           the terminal — what you do about it; builds + fires once
  see(e).causes_the("checkout").to("use the backup processor");
  await fallbackCharge(order);
}

Attach context with .extras(...)

try {
  await charge(order);
} catch (e) {
  // .extras(obj)           structured fields attached to the report
  see(e).causes_the("checkout").extras({ order_id: order.id }).to("use cached prices");
}

Report a non-exception violation

// A bad state that isn't an exception — the name is a STABLE fingerprint; put
// variable data in .extras, never the name. .to() is the terminal.
see.Violation("missing_invoice").causes_the("billing").to("skip the dunning email");

Mark an expected exception — report NOTHING

try {
  parse(token);
} catch (e) {
  // transmits nothing; .because(...) / .extras() are local-debug only
  see.ControlFlowException(e).because("because end of stream is expected");
}
Was this page helpful?
✎ Edit this page

On this page