npm package: @orbit-dev/sdk
Description: Project Orbit browser SDK — config types, HTTP helpers, and selector utilities
Latest version: 0.5.11

## `@orbit-dev/sdk`

Project Orbit browser SDK.

### Install

```bash
npm i @orbit-dev/sdk
```

### What it includes

- **Selector engine**: safe CSS matching + optional open-shadow traversal
- **Runtime**: `bootOrbitRuntime` — published guides, triggers, spotlight + tooltip, completions
- **Step graph**: parsing, trigger evaluator, state machine, minimal renderer
- **Help launcher**: floating “Help” button listing eligible guides
- **Beacons**: pulsing rings anchored to selectors
- **Analytics client**: batched POST to `/analytics/events`
- **Editor**: visual picker, draft panel (WYSIWYG, branching, triggers), autosave, preview; `bootOrbitEditorFromUrl` with **sessionStorage** so the editor survives SPA / Next.js route changes after `?orbit_token=…` is stripped from the URL

---

### Next.js (App Router)

The SDK uses `window` / `document`. Use a **Client Component** (`"use client"`) and start from **`useEffect`** (or dynamic import with `ssr: false`).

If the SDK is in the same monorepo (`file:` / workspace), add **`transpilePackages`** in `next.config.ts`:

```ts
const nextConfig = {
  transpilePackages: ["@orbit-dev/sdk"],
};
export default nextConfig;
```

#### Runtime (end users): `bootOrbitRuntime`

`components/OrbitRuntime.tsx`:

```tsx
"use client";

import { useEffect, useRef } from "react";
import { usePathname } from "next/navigation";
import { bootOrbitRuntime, type OrbitRuntime } from "@orbit-dev/sdk";

const API_BASE = process.env.NEXT_PUBLIC_ORBIT_API_BASE!;
const APP_ID = process.env.NEXT_PUBLIC_ORBIT_APP_ID!;

export function OrbitRuntimeProvider() {
  const pathname = usePathname();
  const handleRef = useRef<OrbitRuntime | null>(null);

  useEffect(() => {
    if (!API_BASE || !APP_ID) return;

    const endUserId =
      /* stable per visitor, e.g. from auth/session */
      "anonymous";

    void bootOrbitRuntime({
      apiBase: API_BASE,
      appId: APP_ID,
      endUserId,
    }).then((h) => {
      handleRef.current = h;
    });

    return () => {
      handleRef.current?.destroy();
      handleRef.current = null;
    };
  }, []);

  // Re-evaluate triggers after client navigations
  useEffect(() => {
    void handleRef.current?.refresh();
  }, [pathname]);

  return null;
}
```

`.env.local`:

```env
NEXT_PUBLIC_ORBIT_API_BASE=https://your-api.example.com
NEXT_PUBLIC_ORBIT_APP_ID=your-app-uuid-from-dashboard
```

Mount once in `app/layout.tsx` (inside `<body>`):

```tsx
import { OrbitRuntimeProvider } from "@/components/OrbitRuntime";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <OrbitRuntimeProvider />
      </body>
    </html>
  );
}
```

Use a real stable `endUserId` when the user is logged in (same id used for completion tracking).

#### Editor (dashboard “open in app”): `bootOrbitEditorFromUrl`

When the user lands with `?orbit_token=...`, bootstrap the editor from a client component:

```tsx
"use client";

import { useEffect } from "react";
import { bootOrbitEditorFromUrl } from "@orbit-dev/sdk";

const API_BASE = process.env.NEXT_PUBLIC_ORBIT_API_BASE!;

export function OrbitEditorBootstrap() {
  useEffect(() => {
    if (!API_BASE) return;
    void bootOrbitEditorFromUrl({ apiBase: API_BASE });
  }, []);
  return null;
}
```

Place `<OrbitEditorBootstrap />` in the same root layout (or page) as your app. The token is stored in **sessionStorage** for the tab so the floating editor stays available after Next.js changes the URL; it is cleared when the user exits the editor.

#### Optional: lazy load (smaller first paint)

```tsx
import dynamic from "next/dynamic";

const OrbitRuntimeProvider = dynamic(
  () => import("@/components/OrbitRuntime").then((m) => m.OrbitRuntimeProvider),
  { ssr: false }
);
```

---

### Editor bootstrap (any host app)

```ts
import { bootOrbitEditorFromUrl } from "@orbit-dev/sdk";

void bootOrbitEditorFromUrl({
  apiBase: "https://your-api.example.com",
});
```

---

### Runtime bootstrap (end users)

```ts
import { bootOrbitRuntime } from "@orbit-dev/sdk";

void bootOrbitRuntime({
  apiBase: "https://your-api.example.com",
  appId: "your-app-uuid",
  endUserId: "stable-user-id",
});
```

---

### Script-tag / CDN usage (no bundler)

```html
<script type="module">
  import { bootOrbitEditorFromUrl } from "https://unpkg.com/@orbit-dev/sdk@0.5.2/dist/index.js";
  void bootOrbitEditorFromUrl({ apiBase: "https://your-api.example.com" });
</script>
```

Update the version in the URL when you publish. For a local API, use `apiBase: "http://localhost:3001"`.

---

### Publishing notes

- The npm package includes `dist/` and this `README.md`.
- To publish keywords/README changes, bump the version and republish:

```bash
cd sdk
npm version patch
npm publish --access public
```