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

@aoa-ua/sdk

v0.1.1

Published

Official TypeScript SDK for the AOA public API: venues, table availability and bookings, events, tickets, checkout and webhooks in Ukraine.

Readme

AOA SDK for TypeScript

Official client for the AOA (Act of Attraction) public API: venues and table bookings, events and tickets, checkout, orders and webhooks in Ukraine.

  • One typed method per operationId of the OpenAPI spec; the types are generated from the spec.
  • Zero runtime dependencies; uses global fetch and WebCrypto. Node.js 20+, Bun, Deno, edge runtimes. ESM only.
  • Automatic Idempotency-Key for table bookings and checkout, opt-in 429 retries honouring Retry-After, rate-limit state, cursor pagination, webhook signature verification.
npm install @aoa-ua/sdk

Quick start

import { createAoaClient } from '@aoa-ua/sdk';

// Reads need no key. The key (aoa_live_...) is needed for writes and raises
// read limits from 60 to 600 requests per minute. Defaults to AOA_API_KEY.
const aoa = createAoaClient({ apiKey: process.env.AOA_API_KEY });

const { data: venues } = await aoa.searchLocations({ city: 'Київ', limit: 5 });
const { data: day } = await aoa.getTableAvailability({
  locationId: venues[0].id,
  date: '2026-10-03',
});
const free = day.slots?.filter((slot) => slot.available).map((slot) => slot.value);

Book a table (after the person confirmed)

const { data: booking } = await aoa.createTableReservation(
  {
    locationId: venues[0].id,
    date: '2026-10-03',
    time: '19:00',
    partySize: 2,
    guest: { name: guestTypedName, phone: guestTypedPhone }, // typed by the person
    confirmedByUser: true, // only after an explicit yes
  },
  { idempotencyKey: `booking-${cartId}` }, // generated when omitted
);
// booking.status: pending until the venue confirms

Sell tickets

const { data: stock } = await aoa.getEventAvailability({ eventId: 'a1b2c3' });

const { data: checkout } = await aoa.createTicketCheckout(
  {
    eventId: 'a1b2c3',
    tickets: [{ ticketTypeId: 'tt_…', quantity: 2 }],
    buyer: { email: buyerEmail, name: buyerName },
  },
  { idempotencyKey: `order-${orderId}`, timeoutMs: 30_000 },
);
// Send the person to checkout.paymentUrl, then poll:
const { data: order } = await aoa.getOrder({ paymentId: checkout.paymentId });

Errors, limits, retries

import { AoaApiError } from '@aoa-ua/sdk';

const aoa = createAoaClient({ maxRetries: 2 }); // retry 429 after Retry-After

try {
  await aoa.getEvent({ eventId: 'missing' });
} catch (error) {
  if (error instanceof AoaApiError) {
    error.status;    // 404
    error.code;      // 'not_found' (branch on this, not on message)
    error.hint;      // what to do next, when known
    error.retryable; // true for rate_limited and internal_error
  }
}

aoa.rateLimit; // { limit, remaining, resetSeconds, windowSeconds } of the last response

Pagination

for await (const event of aoa.paginate('searchEvents', { city: 'Львів' })) {
  console.log(event.title, event.url);
}

paginate follows meta.nextCursor and stops after one page when the server returns none.

Webhooks

import express from 'express';
import { constructWebhookEvent } from '@aoa-ua/sdk';

app.post('/hooks/aoa', express.raw({ type: 'application/json' }), async (req, res) => {
  try {
    const event = await constructWebhookEvent(
      req.body, // raw bytes: never re-serialized JSON
      req.get('AOA-Signature'),
      process.env.AOA_WEBHOOK_SECRET!,
    );
    res.sendStatus(200);
    void handle(event); // deduplicate by event.id (= AOA-Delivery-Id)
  } catch {
    res.sendStatus(401);
  }
});

Several reads in one request

const { data: results } = await aoa.batchOperations({
  operations: [
    { id: 'first', path: '/events/AB12CD34/availability' },
    { id: 'second', path: '/events/EF56GH78/availability' },
  ],
});
// results[i]: { id, status, body }, in the same order; up to 20 operations

Asynchronous checkout

const result = await aoa.createTicketCheckout(params, {
  headers: { Prefer: 'respond-async' }, // 202 with data.statusUrl
});

Any operation by id

const result = await aoa.request('getEventTicketTypes', { eventId: 'a1b2c3' });

Development

npm install
npm run generate:fetch   # download https://aoa.com.ua/openapi.json, update the snapshot and types
npm test                 # stale-types check, build, type tests, node --test

src/generated/schema.ts is generated by scripts/generate-types.mjs; do not edit it by hand. A new API operation needs no SDK code: regenerate and it appears as a typed method.

Links

  • Docs: https://aoa.com.ua/docs
  • Repository: https://github.com/aoa-ua/aoa-agent-kit
  • License: MIT