npm package: @futuredevsolutions/1get-sdk
Description: TypeScript SDK for the 1get link shortening API — core client, React component, and Web Component
Latest version: 0.1.2

# @futuredevsolutions/1get-sdk

TypeScript SDK for the [1get](https://1get.site) link shortening API — core client, React component, and Web Component.

[![npm version](https://img.shields.io/npm/v/@futuredevsolutions/1get-sdk.svg)](https://www.npmjs.com/package/@futuredevsolutions/1get-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@futuredevsolutions/1get-sdk)](https://bundlephobia.com/package/@futuredevsolutions/1get-sdk)

## Features

- **Zero dependencies** — Only React as an optional peer dependency
- **Three integration paths**:
  - `OneGetClient` — Vanilla JS/TS client for any environment (Node 18+, browsers, edge)
  - `<LinkShortener />` — Drop-in React component with theming and QR codes
  - `<one-get-shortener>` — Web Component for Vue, Angular, Svelte, or plain HTML
- **Full TypeScript support** — Strict types and comprehensive JSDoc
- **QR code generation** — Generate and download QR codes for shortened links
- **Theming** — Light, dark, and auto themes with customizable accent colors
- **WCAG 2.1 AA accessible** — Keyboard navigation, ARIA labels, focus management

## Installation

```bash
npm install @futuredevsolutions/1get-sdk
```

## Quick Start

Get your API key at [https://1get.site/settings/api-access](https://1get.site/settings/api-access).

```typescript
import { OneGetClient } from '@futuredevsolutions/1get-sdk';

const client = new OneGetClient({ apiKey: '1gt_live_xxxxx' });

const result = await client.shorten({ url: 'https://example.com/very-long-url' });

console.log(result.shortUrl);  // https://1get.site/abc123
console.log(result.qrCode?.url); // QR code image URL (if requested)
```

## React Component

```tsx
import { LinkShortener } from '@futuredevsolutions/1get-sdk/react';

function App() {
  return (
    <LinkShortener
      apiKey="1gt_live_xxxxx"
      enableQrCode={true}
      theme="auto"
      accentColor="#14b8a6"
      borderRadius="lg"
      onShorten={(result) => console.log('Shortened:', result.shortUrl)}
      onError={(error) => console.error('Error:', error.code)}
      onCopy={(url) => console.log('Copied:', url)}
    />
  );
}
```

Or use the provider pattern to set the API key once:

```tsx
import { OneGetProvider, LinkShortener } from '@futuredevsolutions/1get-sdk/react';

function App() {
  return (
    <OneGetProvider apiKey="1gt_live_xxxxx">
      <LinkShortener theme="dark" />
    </OneGetProvider>
  );
}
```

## Web Component

```html
<script type="module">
  import '@futuredevsolutions/1get-sdk/web-component';
</script>

<one-get-shortener
  api-key="1gt_live_xxxxx"
  enable-qr="true"
  theme="auto"
  accent-color="#14b8a6"
></one-get-shortener>

<script>
  document.querySelector('one-get-shortener')
    .addEventListener('shorten', (e) => {
      console.log('Shortened:', e.detail.shortUrl);
    });
</script>
```

---

## API Reference

### OneGetClient

```typescript
import { OneGetClient } from '@futuredevsolutions/1get-sdk';

const client = new OneGetClient(config);
```

#### Constructor Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiKey` | `string` | — | Your 1get API key. Falls back to environment variables if omitted. |
| `baseUrl` | `string` | `'https://1get.site'` | Base URL for the API. |
| `timeout` | `number` | `30000` | Request timeout in milliseconds. |
| `headers` | `Record<string, string>` | `{}` | Additional headers for every request. |

---

### client.shorten(options)

Shortens a URL and optionally generates a QR code.

```typescript
const result = await client.shorten({
  url: 'https://example.com/product/launch',
  slug: 'launch-2026',           // Optional custom slug
  redirectType: 'TEMPORARY_302', // or 'PERMANENT_301'
  tags: ['marketing', 'email'],
  utmSource: 'newsletter',
  utmMedium: 'email',
  utmCampaign: 'launch',
  qr: {
    include: true,
    format: 'PNG',               // or 'SVG'
    size: 256,
    foregroundColor: '#000000',
    backgroundColor: '#FFFFFF',
  },
  idempotencyKey: 'unique-key',  // For safe retries
});
```

#### ShortenOptions

| Option | Type | Description |
|--------|------|-------------|
| `url` | `string` | **Required.** The URL to shorten. |
| `slug` | `string` | Custom slug (3–50 chars, alphanumeric + hyphens). |
| `redirectType` | `'PERMANENT_301' \| 'TEMPORARY_302'` | HTTP redirect type. Default: `'TEMPORARY_302'`. |
| `tags` | `string[]` | Tags to associate with the link. |
| `utmSource` | `string` | UTM source parameter. |
| `utmMedium` | `string` | UTM medium parameter. |
| `utmCampaign` | `string` | UTM campaign parameter. |
| `utmTerm` | `string` | UTM term parameter. |
| `utmContent` | `string` | UTM content parameter. |
| `qr` | `boolean \| QrOptions` | QR code options. Pass `true` for defaults. |
| `idempotencyKey` | `string` | Idempotency key for safe retries. |

#### ShortenResult

```typescript
interface ShortenResult {
  id: string;
  slug: string;
  shortUrl: string;           // e.g., 'https://1get.site/abc123'
  originalUrl: string;
  status: string;             // 'ACTIVE', 'EXPIRED', etc.
  redirectType: string;
  totalClicks: number;
  tags: string[];
  qrStatus: string;           // 'ready', 'pending', 'failed', 'skipped'
  qrCode?: {
    id: string;
    url: string;              // QR image URL
    format: string;
    size: number;
    foregroundColor: string;
    backgroundColor: string;
  };
  createdAt: string;
  updatedAt: string;
}
```

---

### client.getLink(id)

Retrieves a link by ID.

```typescript
const link = await client.getLink('ecb3ec1f-ae2e-4c30-b7d6-c47b4c671f7b');
console.log(link.totalClicks);
```

---

### client.getLinkQr(id)

Retrieves QR code metadata for a link.

```typescript
const qr = await client.getLinkQr('ecb3ec1f-ae2e-4c30-b7d6-c47b4c671f7b');
console.log(qr.qrCode.url);
```

---

### client.getUsage()

Retrieves API usage, plan details, and key counts.

```typescript
const usage = await client.getUsage();
console.log(`${usage.usage.remaining} API calls remaining`);
console.log(`Plan: ${usage.plan.displayName}`);
```

---

### client.downloadQr(qrUrl, options?)

Downloads a QR code image as a Blob.

```typescript
const blob = await client.downloadQr(result.qrCode.url, { format: 'png' });

// Create download link
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'qr-code.png';
a.click();
URL.revokeObjectURL(url);
```

---

## React API Reference

### `<LinkShortener />`

A drop-in React component for URL shortening with QR codes.

```tsx
import { LinkShortener } from '@futuredevsolutions/1get-sdk/react';
```

#### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `apiKey` | `string` | — | API key. Falls back to provider/env vars. |
| `enableQrCode` | `boolean` | `true` | Show QR code in results. |
| `qrCodeDownloadable` | `boolean` | `true` | Show download button for QR. |
| `qrFormat` | `'PNG' \| 'SVG'` | `'PNG'` | QR image format. |
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color theme. |
| `accentColor` | `string` | `'#14b8a6'` | Primary accent color. |
| `borderRadius` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `'lg'` | Border radius preset. |
| `className` | `string` | — | Additional CSS class. |
| `style` | `CSSProperties` | — | Additional inline styles. |
| `autoFocus` | `boolean` | `false` | Auto-focus input on mount. |
| `showCopyButton` | `boolean` | `true` | Show copy-to-clipboard button. |
| `resetAfterCopy` | `boolean` | `false` | Reset form after copying. |
| `onShorten` | `(result: ShortenResult) => void` | — | Called on success. |
| `onError` | `(error: OneGetError) => void` | — | Called on error. |
| `onCopy` | `(shortUrl: string) => void` | — | Called after copying. |
| `labels` | `Partial<Labels>` | — | Custom labels for i18n. |

#### Labels Object

```typescript
{
  inputPlaceholder: 'Enter URL to shorten',
  buttonText: 'Shorten',
  buttonLoadingText: 'Shortening...',
  copyButtonText: 'Copy',
  copiedText: 'Copied!',
  qrDownloadText: 'Download QR',
  errorPrefix: 'Error:',
}
```

---

### useShorten()

React hook for programmatic URL shortening.

```tsx
import { useShorten } from '@futuredevsolutions/1get-sdk/react';

function MyComponent() {
  const { shorten, isLoading, error, result, reset } = useShorten({
    apiKey: '1gt_live_xxxxx',
    onSuccess: (result) => console.log(result),
    onError: (error) => console.error(error),
  });

  const handleClick = async () => {
    const result = await shorten({ url: 'https://example.com' });
    console.log(result.shortUrl);
  };

  return (
    <button onClick={handleClick} disabled={isLoading}>
      {isLoading ? 'Loading...' : 'Shorten'}
    </button>
  );
}
```

#### Options

| Option | Type | Description |
|--------|------|-------------|
| `apiKey` | `string` | API key. Falls back to provider/env vars. |
| `baseUrl` | `string` | Base URL for the API. |
| `onSuccess` | `(result: ShortenResult) => void` | Success callback. |
| `onError` | `(error: OneGetError) => void` | Error callback. |

#### Return Value

| Property | Type | Description |
|----------|------|-------------|
| `shorten` | `(options: ShortenOptions) => Promise<ShortenResult>` | Shorten function. |
| `isLoading` | `boolean` | Loading state. |
| `error` | `OneGetError \| null` | Last error. |
| `result` | `ShortenResult \| null` | Last result. |
| `reset` | `() => void` | Reset state. |

---

### `<OneGetProvider />`

Provides API configuration to all child components.

```tsx
import { OneGetProvider } from '@futuredevsolutions/1get-sdk/react';

function App() {
  return (
    <OneGetProvider apiKey="1gt_live_xxxxx" baseUrl="https://1get.site">
      <LinkShortener />
      <AnotherComponent />
    </OneGetProvider>
  );
}
```

---

## Web Component API Reference

### Attributes

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `api-key` | `string` | — | **Required.** Your API key. |
| `enable-qr` | `'true' \| 'false'` | `'true'` | Show QR code. |
| `qr-downloadable` | `'true' \| 'false'` | `'true'` | Show QR download button. |
| `qr-format` | `'PNG' \| 'SVG'` | `'PNG'` | QR image format. |
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color theme. |
| `accent-color` | `string` | `'#14b8a6'` | Primary accent color. |
| `border-radius` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `'lg'` | Border radius. |
| `auto-focus` | `'true' \| 'false'` | `'false'` | Auto-focus input. |
| `show-copy-button` | `'true' \| 'false'` | `'true'` | Show copy button. |
| `placeholder` | `string` | `'Enter URL to shorten'` | Input placeholder. |
| `button-text` | `string` | `'Shorten'` | Submit button text. |

### Events

| Event | Detail | Description |
|-------|--------|-------------|
| `shorten` | `ShortenResult` | Fired on successful shortening. |
| `error` | `OneGetError` | Fired on error. |
| `copy` | `{ shortUrl: string }` | Fired after copying. |

```javascript
element.addEventListener('shorten', (e) => {
  console.log(e.detail.shortUrl);
});
```

### Programmatic Usage

```javascript
import { OneGetShortenerElement } from '@futuredevsolutions/1get-sdk/web-component';

const element = new OneGetShortenerElement();
element.setAttribute('api-key', '1gt_live_xxxxx');
document.body.appendChild(element);
```

---

## Framework Integration Examples

### Next.js (App Router)

```tsx
// app/page.tsx
'use client';

import { LinkShortener } from '@futuredevsolutions/1get-sdk/react';

export default function Home() {
  return (
    <LinkShortener
      apiKey={process.env.NEXT_PUBLIC_1GET_API_KEY}
      theme="auto"
    />
  );
}
```

### Next.js (Pages Router)

```tsx
// pages/index.tsx
import { OneGetProvider, LinkShortener } from '@futuredevsolutions/1get-sdk/react';

export default function Home() {
  return (
    <OneGetProvider apiKey={process.env.NEXT_PUBLIC_1GET_API_KEY!}>
      <LinkShortener enableQrCode={true} />
    </OneGetProvider>
  );
}
```

### Vite + React

```tsx
// src/App.tsx
import { LinkShortener } from '@futuredevsolutions/1get-sdk/react';

function App() {
  return (
    <LinkShortener
      apiKey={import.meta.env.VITE_1GET_API_KEY}
      theme="dark"
      accentColor="#6366f1"
    />
  );
}
```

### Vue 3

```vue
<template>
  <one-get-shortener
    api-key="1gt_live_xxxxx"
    theme="auto"
    @shorten="onShorten"
  />
</template>

<script setup>
import '@futuredevsolutions/1get-sdk/web-component';

function onShorten(e) {
  console.log('Shortened:', e.detail.shortUrl);
}
</script>
```

### Svelte

```svelte
<script>
  import '@futuredevsolutions/1get-sdk/web-component';

  function handleShorten(e) {
    console.log('Shortened:', e.detail.shortUrl);
  }
</script>

<one-get-shortener
  api-key="1gt_live_xxxxx"
  theme="dark"
  on:shorten={handleShorten}
/>
```

### Vanilla HTML

```html
<!DOCTYPE html>
<html>
<head>
  <script type="module">
    import '@futuredevsolutions/1get-sdk/web-component';
  </script>
</head>
<body>
  <one-get-shortener
    api-key="1gt_live_xxxxx"
    enable-qr="true"
    theme="auto"
  ></one-get-shortener>

  <script>
    document.querySelector('one-get-shortener')
      .addEventListener('shorten', (e) => {
        alert('Short URL: ' + e.detail.shortUrl);
      });
  </script>
</body>
</html>
```

---

## Environment Variables

When `apiKey` is not explicitly provided, the SDK checks these environment variables in order:

| Variable | Framework |
|----------|-----------|
| `NEXT_PUBLIC_1GET_API_KEY` | Next.js |
| `VITE_1GET_API_KEY` | Vite |
| `ONEGET_API_KEY` | Node.js / general |
| `1GET_API_KEY` | Fallback |

```bash
# .env.local (Next.js)
NEXT_PUBLIC_1GET_API_KEY=1gt_live_xxxxx

# .env (Vite)
VITE_1GET_API_KEY=1gt_live_xxxxx
```

---

## Error Handling

All errors are instances of `OneGetError` with structured properties:

```typescript
import { OneGetClient, OneGetError } from '@futuredevsolutions/1get-sdk';

const client = new OneGetClient({ apiKey: '1gt_live_xxxxx' });

try {
  await client.shorten({ url: 'https://example.com' });
} catch (err) {
  if (err instanceof OneGetError) {
    console.error('Code:', err.code);        // 'RATE_LIMITED', 'VALIDATION_FAILED', etc.
    console.error('Status:', err.status);    // HTTP status code
    console.error('Message:', err.message);  // Human-readable message
    console.error('Details:', err.details);  // Additional context
    console.error('Request ID:', err.requestId); // For support
  }
}
```

### Common Error Codes

| Code | Description |
|------|-------------|
| `MISSING_API_KEY` | No API key provided or found in env vars. |
| `INVALID_API_KEY` | API key is invalid or expired. |
| `VALIDATION_FAILED` | Invalid request parameters. |
| `CONFLICT` | Custom slug is already in use. |
| `RATE_LIMITED` | Too many requests. |
| `PLAN_LIMIT_EXCEEDED` | Monthly API call limit reached. |
| `NETWORK_ERROR` | Network request failed. |

---

## TypeScript

The SDK is fully typed with comprehensive JSDoc documentation.

```typescript
import type {
  OneGetConfig,
  ShortenOptions,
  ShortenResult,
  QrOptions,
  QrCodeResult,
  LinkResult,
  QrReadResult,
  UsageResult,
} from '@futuredevsolutions/1get-sdk';

import type {
  LinkShortenerProps,
  UseShortenOptions,
  UseShortenReturn,
} from '@futuredevsolutions/1get-sdk/react';
```

---

## Contributing

Contributions are welcome! Please open an issue or submit a pull request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

---

## License

MIT License - see [LICENSE](./LICENSE) for details.

---

**Get your API key at [https://1get.site/settings/api-access](https://1get.site/settings/api-access)**