npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@abto-app/sdk

v0.0.1

Published

ABTO SDK — broad autocapture of user behavior x LLM cost/latency/quality attribution. Browser (.) and Node server (./server) in one package.

Readme

@abto-app/sdk

ABTO SDK는 브라우저에서 관측 가능한 사용자 행동을 수집하고, Gateway가 반환한 request_id를 통해 서버의 LLM 비용·지연 데이터와 연결한다.

  • @abto-app/sdk: Browser SDK — autocapture, custom events, AI trace
  • @abto-app/sdk/server: Node Server SDK — Gateway 호출과 context 전달

이 문서의 앞부분은 Browser SDK를 다룬다. 브라우저와 서버는 같은 npm 패키지로 배포되지만 API와 책임은 분리되어 있다.

PostHog의 autocapture, ingestion, session, schema/discovery는 ABTO 이벤트 설계의 참고 모델이다. ABTO 이벤트를 PostHog로 보내는 연동이 아니라, 검증된 수집 철학을 ABTO 독립 수집 구조에 적용한다.

설치

pnpm add @abto-app/sdk

이벤트 경계

Browser SDK가 보내는 이벤트는 두 종류다.

| 종류 | 이름 | 정의 주체 | 발생 방식 | |---|---|---|---| | 시스템 이벤트 | $로 시작 | ABTO | SDK 자동 수집 또는 전용 API | | 커스텀 이벤트 | $ 없이 제품 도메인 이름 사용 | 고객 저장소 | client.capture() |

사용자는 $ 이벤트나 $ 속성을 등록할 수 없다. ABTO 시스템 이벤트도 일반 capture()로 보낼 수 없으며 SDK 내부 경로와 AI trace 전용 메서드만 발생시킨다.

Browser SDK 시스템 이벤트

| 이벤트 | 의미 | 발생 조건 | |---|---|---| | $pageview | 페이지/SPA route 진입 | 초기 로드, history 변경, bfcache 복원 | | $pageleave | 페이지/route 이탈 | SPA 이동, pagehide | | $autocapture | DOM 상호작용 원시 사실 | click, change, submit, copy | | $rageclick | 짧은 시간의 반복 클릭 | SDK 휴리스틱 | | $dead_click | 반응이 관측되지 않은 클릭 | SDK 휴리스틱 | | $ai_prompt_submitted | 프롬프트 제출을 앱이 확인 | trace.submitPrompt() | | $ai_response_rendered | 응답이 UI에 렌더됨을 앱이 확인 | trace.markResponseRendered() | | $ai_response_interacted | 응답에 대한 명시적 행동 | trace.captureResponseInteraction() |

$session_start와 $session_end는 보내지 않는다. 모든 이벤트의 $session_id와 timestamp의 최솟값·최댓값을 분석 계층에서 사용해 세션 시작, 종료, duration을 파생한다. 브라우저 종료 신호는 유실될 수 있으므로 $session_end를 확정 사실로 기록하지 않는다.

커스텀 이벤트 정본: abto.events.ts

제품 이벤트는 고객 애플리케이션 저장소의 abto.events.ts에 사전 등록한다. 이 파일을 코드 리뷰와 향후 CLI/CI schema push의 정본으로 사용한다.

// abto.events.ts
import { defineEvents } from '@abto-app/sdk';

export const events = defineEvents({
  checkout_completed: {
    description: '결제가 완료됨',
    properties: {
      order_id: { type: 'string', required: true },
      amount: { type: 'number', required: true },
      currency: {
        type: 'string',
        enum: ['KRW', 'USD'],
        required: true,
      },
    },
  },
});
import { initAbto } from '@abto-app/sdk';
import { events } from './abto.events';

const abto = initAbto({
  projectKey: 'public_project_key',
  environment: 'development',
  events,
});

abto.capture('checkout_completed', {
  order_id: 'order_123',
  amount: 49_000,
  currency: 'KRW',
});

defineEvents()에서 타입을 추론하므로 잘못된 이벤트 이름, required 누락, enum 위반을 개발 시점에 확인할 수 있다. 런타임 정책은 환경별로 다르다.

| 환경 | 미등록 이벤트 | 등록 schema drift | |---|---|---| | development | 전송하고 Discovered 경고 | 전송하고 drift 경고 | | production | drop | required/type/enum 위반 drop |

알 수 없는 추가 속성은 막지 않는다. schema가 선언한 required/type/enum만 검사해 점진적 확장을 허용한다.

초기화와 autocapture

앱 루트에서 한 번 초기화하면 autocapture가 시작된다.

const abto = initAbto({
  projectKey: 'public_project_key',
  apiHost: 'https://api.abto.app',
  environment: 'production',
  events,
});

기본 endpoint는 ${apiHost}/v1/browser/events다. 전송 envelope는 다음 모양이다.

{
  "sent_at": "2026-07-15T04:10:03.000Z",
  "batch": [
    {
      "uuid": "019b...",
      "event": "$autocapture",
      "timestamp": "2026-07-15T04:10:00.000Z",
      "distinct_id": "user_123",
      "properties": {
        "$event_type": "click",
        "$elements_chain": "button.cta:nth-child(1)",
        "$session_id": "019b...",
        "$window_id": "019b...",
        "$pageview_id": "019b..."
      }
    }
  ]
}

서버의 이벤트별 응답은 event UUID를 key로 사용한다.

{
  "results": {
    "019b5b74-11d0-7000-8000-000000000001": {
      "result": "drop",
      "code": "schema_type_mismatch"
    }
  }
}

일반 fetch는 public project key를 Bearer header에 싣고, sendBeacon은 custom header를 지원하지 않으므로 ?api_key= query를 사용한다. 서버가 이 key에서 project_id와 account_id를 결정한다. $tenant_id를 포함한 client property는 분석 문맥이며 인증·project 귀속 값이 아니다.

수신 계약의 상한은 요청당 100 events다. SDK 기본값은 20이며 keepalive/beacon payload는 약 60 KiB 아래에서 전송한다. malformed request와 인증 실패는 요청 단위 4xx, 개별 validation/storage 실패는 2xx 응답의 UUID별 warning, drop, retry로 처리한다.

향후 PostgreSQL ingestion은 uuid/event/timestamp/distinct_id/properties/set/set_once를 각각 event_id/event_name/occurred_at/distinct_id/properties/person_set/person_set_once로 저장하고 서버 수신 시각을 received_at에 기록한다. (project_id, event_id)는 재전송 dedup key다.

annotation은 원시 $autocapture를 다른 이벤트로 바꾸지 않는다. 원시 상호작용을 보존하면서 분석 차원만 보강한다.

<button
  data-abto-action="accept"
  data-abto-surface="generator"
  data-abto-node-key="resume.make"
  data-abto-response-id="resp_123"
  data-abto-request-id="req_123">
  적용
</button>

위 클릭은 $autocapture로 수집되며 $ai_action, $surface, $node_key, $response_id, $request_id가 함께 실린다. 업무 의미가 확정된 행동은 앱 코드에서 커스텀 이벤트 또는 AI 전용 메서드로 별도 기록한다.

개인정보 기본값

prompt, response, DOM text/value는 기본적으로 원문을 수집하지 않는다.

initAbto({
  projectKey: 'public_project_key',
  events,
  capture: {
    prompt: 'metadata_only',
    response: 'metadata_only',
    mask: 'all',
  },
});

위 값들이 생략됐을 때도 같은 안전한 기본값이 적용된다.

| annotation | 동작 | |---|---| | data-abto-no-capture | 자신과 하위 트리를 수집하지 않음 | | data-abto-sensitive | 자신과 하위 text/value를 항상 전체 마스킹 | | data-abto-include | 해당 요소의 text/value 수집을 명시적으로 허용 |

password, hidden input과 카드·비밀번호·SSN 계열 필드는 annotation과 무관하게 보호한다. full 원문 수집은 명시적 opt-in이며 고객의 동의·보존·삭제 정책과 함께 사용해야 한다.

브라우저에서 관측 가능한 AI 이벤트

브라우저가 확실히 아는 세 가지 사실만 전용 API로 제공한다.

const trace = abto.startLlmTrace({
  nodeId: 'resume.make',
  taskType: 'draft_generation',
  surface: 'editor',
});

await trace.submitPrompt({
  prompt: promptText,
  language: 'ko',
});

const response = await fetch('/api/generate', {
  method: 'POST',
  headers: { 'content-type': 'application/json', ...trace.getHeaders() },
  body: JSON.stringify({ prompt: promptText }),
});
trace.attachRequestId(response);

await trace.markResponseRendered({
  responseId: 'resp_123',
  timeToRenderMs: 1_380,
});

await trace.captureResponseInteraction('copied', {
  responseId: 'resp_123',
  source: 'copy_button',
});

provider/model/token/cost/retry/fallback, 실제 첫 토큰 시점과 request 성공·실패는 Server SDK/Gateway가 소유한다. AI task 완료·이탈은 제품마다 의미가 다르므로 커스텀 이벤트 또는 분석 파생 지표로 둔다.

식별자와 세션

| 속성 | 수명과 역할 | |---|---| | $device_id | 프로젝트별 브라우저 설치, localStorage 유지 | | $anonymous_id | 로그인 전 distinct identity | | $user_id | identify()로 연결한 제품 사용자 | | $session_id | 탭 사이에서 공유하는 논리 세션, 30분 idle 또는 24시간 max age에 회전 | | $window_id | 탭/window별 ID, sessionStorage 유지 | | $pageview_id | 페이지/SPA route 구간, pageview마다 회전 | | $trace_id | 한 사용자 행동에서 서버 호출까지 연결 | | $request_id | Gateway의 실제 provider 호출 PK |

abto.identify('user_123', 'tenant_123');
abto.reset();        // user/tenant 제거, device 유지
abto.forgetDevice(); // outbox와 device identity 제거

전송과 재시도

  • 이벤트는 localStorage outbox에 먼저 저장한다.
  • 기본적으로 최대 20개씩 POST /v1/browser/events로 보낸다.
  • 일반 flush는 fetch, 페이지 이탈은 안전 크기에서 sendBeacon을 우선 사용한다.
  • keepalive/beacon payload는 약 60 KiB 이내로 제한한다.
  • 408, 429, 5xx와 이벤트별 retry만 지수 backoff로 재시도한다.
  • 영구 4xx와 이벤트별 drop은 outbox에서 제거한다.
  • 이벤트별 ok, warning, drop, retry 응답을 UUID 기준으로 처리한다.

Public API (browser)

initAbto · defineEvents · identify · getIdentity · reset · forgetDevice · startLlmTrace · setNode · getTraceHeaders · client.capture · trace.submitPrompt · trace.markResponseRendered · trace.captureResponseInteraction · flush.

Node Server SDK

Node 서버에서는 별도 subpath를 사용한다. Browser SDK와 섞어 import하지 않는다.

import { createAbto } from '@abto-app/sdk/server';

const abto = createAbto({
  abtoApiKey: process.env.ABTO_API_KEY,
  providerKeys: {
    openai: process.env.OPENAI_API_KEY,
  },
  gatewayBaseURL: 'https://gateway.abto.app/v1',
  userId: process.env.ABTO_USER_ID,
});

Server SDK의 Gateway/provider 계약은 서버 SDK 문서와 해당 PR에서 관리한다.

개발 검증

pnpm test
pnpm typecheck
pnpm build
node ../../examples/browser-smoke/collector.mjs

실브라우저 검증 절차는 examples/browser-smoke/README.md를 따른다.