@quikturn/logos 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +498 -0
- package/dist/client/index.cjs +726 -0
- package/dist/client/index.d.cts +399 -0
- package/dist/client/index.d.ts +399 -0
- package/dist/client/index.mjs +721 -0
- package/dist/index.cjs +319 -0
- package/dist/index.d.cts +437 -0
- package/dist/index.d.ts +437 -0
- package/dist/index.mjs +294 -0
- package/dist/server/index.cjs +858 -0
- package/dist/server/index.d.cts +423 -0
- package/dist/server/index.d.ts +423 -0
- package/dist/server/index.mjs +854 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Quikturn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
# @quikturn/logos
|
|
2
|
+
|
|
3
|
+
> TypeScript SDK for the Quikturn Logos API -- fetch company logos with type safety.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Zero-dependency URL builder** -- universal, works in any JavaScript runtime
|
|
8
|
+
- **Browser client** -- blob URL management, retry/backoff, auto-scrape polling, event emission
|
|
9
|
+
- **Server client** -- Buffer output, ReadableStream streaming, concurrent batch operations
|
|
10
|
+
- **Full TypeScript support** -- strict types, discriminated union error codes, generic response shapes
|
|
11
|
+
- **Tree-shakeable** -- ESM and CJS dual builds; import only what you need
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# pnpm (recommended)
|
|
17
|
+
pnpm add @quikturn/logos
|
|
18
|
+
|
|
19
|
+
# npm
|
|
20
|
+
npm install @quikturn/logos
|
|
21
|
+
|
|
22
|
+
# yarn
|
|
23
|
+
yarn add @quikturn/logos
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Requirements:** Node.js >= 18
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### URL Builder (Universal)
|
|
31
|
+
|
|
32
|
+
The URL builder runs everywhere -- browsers, Node.js, edge runtimes -- with zero dependencies and no network calls.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { logoUrl } from "@quikturn/logos";
|
|
36
|
+
|
|
37
|
+
// Simple usage
|
|
38
|
+
const url = logoUrl("github.com");
|
|
39
|
+
// => "https://logos.getquikturn.io/github.com"
|
|
40
|
+
|
|
41
|
+
// With options
|
|
42
|
+
const customUrl = logoUrl("stripe.com", {
|
|
43
|
+
token: "qt_abc123",
|
|
44
|
+
size: 256,
|
|
45
|
+
format: "webp",
|
|
46
|
+
greyscale: true,
|
|
47
|
+
theme: "dark",
|
|
48
|
+
});
|
|
49
|
+
// => "https://logos.getquikturn.io/stripe.com?token=qt_abc123&size=256&greyscale=1&theme=dark&format=webp"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Browser Client
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { QuikturnLogos } from "@quikturn/logos/client";
|
|
56
|
+
|
|
57
|
+
const client = new QuikturnLogos({ token: "qt_your_publishable_key" });
|
|
58
|
+
|
|
59
|
+
// Fetch a logo as a blob URL (ready for <img src>)
|
|
60
|
+
const { url, blob, contentType, metadata } = await client.get("github.com", {
|
|
61
|
+
size: 256,
|
|
62
|
+
format: "webp",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
document.querySelector("img")!.src = url;
|
|
66
|
+
|
|
67
|
+
// Listen for rate limit warnings
|
|
68
|
+
client.on("rateLimitWarning", (remaining, limit) => {
|
|
69
|
+
console.warn(`Rate limit: ${remaining}/${limit} requests remaining`);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Clean up blob URLs when done
|
|
73
|
+
client.destroy();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Server Client
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { QuikturnLogos } from "@quikturn/logos/server";
|
|
80
|
+
|
|
81
|
+
const client = new QuikturnLogos({ secretKey: "sk_your_secret_key" });
|
|
82
|
+
|
|
83
|
+
// Fetch a logo as a Buffer
|
|
84
|
+
const { buffer, contentType, metadata } = await client.get("github.com", {
|
|
85
|
+
size: 512,
|
|
86
|
+
format: "png",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Batch fetch multiple logos
|
|
90
|
+
for await (const result of client.getMany(["github.com", "stripe.com", "vercel.com"])) {
|
|
91
|
+
if (result.success) {
|
|
92
|
+
console.log(`${result.domain}: ${result.buffer!.byteLength} bytes`);
|
|
93
|
+
} else {
|
|
94
|
+
console.error(`${result.domain}: ${result.error!.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Stream a logo to a file
|
|
99
|
+
import { createWriteStream } from "node:fs";
|
|
100
|
+
import { Readable } from "node:stream";
|
|
101
|
+
|
|
102
|
+
const stream = await client.getStream("github.com", { format: "png" });
|
|
103
|
+
Readable.fromWeb(stream).pipe(createWriteStream("logo.png"));
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## API Reference
|
|
107
|
+
|
|
108
|
+
### Universal (`@quikturn/logos`)
|
|
109
|
+
|
|
110
|
+
The universal entry point exports the URL builder, types, constants, error classes, and header parser. No network calls are made from this module.
|
|
111
|
+
|
|
112
|
+
#### `logoUrl(domain, options?)`
|
|
113
|
+
|
|
114
|
+
Constructs a fully-qualified Logos API URL. Pure function with no side effects.
|
|
115
|
+
|
|
116
|
+
| Parameter | Type | Description |
|
|
117
|
+
|-----------|------|-------------|
|
|
118
|
+
| `domain` | `string` | Domain to fetch a logo for (e.g. `"github.com"`) |
|
|
119
|
+
| `options` | `LogoRequestOptions` | Optional request parameters |
|
|
120
|
+
|
|
121
|
+
**Returns:** `string` -- fully-qualified URL
|
|
122
|
+
|
|
123
|
+
**Throws:** `DomainValidationError` if the domain fails RFC 1035/1123 validation
|
|
124
|
+
|
|
125
|
+
##### `LogoRequestOptions`
|
|
126
|
+
|
|
127
|
+
| Property | Type | Default | Description |
|
|
128
|
+
|----------|------|---------|-------------|
|
|
129
|
+
| `token` | `string` | -- | Publishable key (`qt_`/`pk_`) appended as a query parameter |
|
|
130
|
+
| `size` | `number` | `128` | Output width in pixels, clamped to `1..800` (publishable) or `1..1200` (secret) |
|
|
131
|
+
| `width` | `number` | `128` | Alias for `size` |
|
|
132
|
+
| `greyscale` | `boolean` | `false` | When `true`, applies saturation: 0 transformation |
|
|
133
|
+
| `theme` | `"light" \| "dark"` | -- | Gamma curve adjustment (`"light"` = 0.9, `"dark"` = 1.12) |
|
|
134
|
+
| `format` | `SupportedOutputFormat \| FormatShorthand` | `"image/png"` | Output image format |
|
|
135
|
+
| `autoScrape` | `boolean` | `false` | Trigger background scrape if logo is not found |
|
|
136
|
+
| `baseUrl` | `string` | `"https://logos.getquikturn.io"` | Override the API base URL |
|
|
137
|
+
|
|
138
|
+
#### Types
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import type {
|
|
142
|
+
// Key & Auth
|
|
143
|
+
KeyType, // "publishable" | "secret"
|
|
144
|
+
KeyPrefix, // "qt_" | "pk_" | "sk_"
|
|
145
|
+
Tier, // "free" | "launch" | "growth" | "enterprise"
|
|
146
|
+
TokenStatus, // "active" | "suspended" | "revoked"
|
|
147
|
+
|
|
148
|
+
// Request
|
|
149
|
+
ThemeOption, // "light" | "dark"
|
|
150
|
+
SupportedOutputFormat, // "image/png" | "image/jpeg" | "image/webp" | "image/avif"
|
|
151
|
+
FormatShorthand, // "png" | "jpeg" | "webp" | "avif"
|
|
152
|
+
LogoRequestOptions,
|
|
153
|
+
|
|
154
|
+
// Response
|
|
155
|
+
LogoMetadata,
|
|
156
|
+
BrowserLogoResponse,
|
|
157
|
+
ServerLogoResponse,
|
|
158
|
+
|
|
159
|
+
// Auto-scrape
|
|
160
|
+
ScrapeJob,
|
|
161
|
+
ScrapePendingResponse,
|
|
162
|
+
ScrapeJobStatus, // "pending" | "complete" | "failed"
|
|
163
|
+
ScrapeProgressEvent,
|
|
164
|
+
|
|
165
|
+
// Attribution (free tier)
|
|
166
|
+
AttributionStatus,
|
|
167
|
+
AttributionInfo,
|
|
168
|
+
|
|
169
|
+
// Error codes
|
|
170
|
+
LogoErrorCode,
|
|
171
|
+
} from "@quikturn/logos";
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### Constants
|
|
175
|
+
|
|
176
|
+
| Constant | Value | Description |
|
|
177
|
+
|----------|-------|-------------|
|
|
178
|
+
| `BASE_URL` | `"https://logos.getquikturn.io"` | Root API endpoint |
|
|
179
|
+
| `DEFAULT_WIDTH` | `128` | Default logo width (px) |
|
|
180
|
+
| `MAX_WIDTH` | `800` | Max width for publishable keys |
|
|
181
|
+
| `MAX_WIDTH_SERVER` | `1200` | Max width for secret keys |
|
|
182
|
+
| `DEFAULT_FORMAT` | `"image/png"` | Default output MIME type |
|
|
183
|
+
| `SUPPORTED_FORMATS` | `Set<SupportedOutputFormat>` | All supported MIME types |
|
|
184
|
+
| `FORMAT_ALIASES` | `Record<FormatShorthand, SupportedOutputFormat>` | Shorthand-to-MIME mapping |
|
|
185
|
+
| `RATE_LIMITS` | `Record<Tier, { requests, windowSeconds }>` | Per-tier publishable rate limits |
|
|
186
|
+
| `SERVER_RATE_LIMITS` | `Record<Tier, { requests, windowSeconds }>` | Per-tier server rate limits |
|
|
187
|
+
| `MONTHLY_LIMITS` | `Record<Tier, number>` | Monthly request quotas |
|
|
188
|
+
| `TIERS` | `readonly Tier[]` | All tiers as a runtime array |
|
|
189
|
+
| `KEY_TYPES` | `readonly KeyType[]` | All key types as a runtime array |
|
|
190
|
+
|
|
191
|
+
#### `parseLogoHeaders(headers)`
|
|
192
|
+
|
|
193
|
+
Parses a `Headers` object from a fetch `Response` into a structured `LogoMetadata` object.
|
|
194
|
+
|
|
195
|
+
#### `parseRetryAfter(headers)`
|
|
196
|
+
|
|
197
|
+
Extracts the `Retry-After` header value in seconds. Returns `number | null`.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### Browser Client (`@quikturn/logos/client`)
|
|
202
|
+
|
|
203
|
+
#### `new QuikturnLogos(options)`
|
|
204
|
+
|
|
205
|
+
| Option | Type | Default | Description |
|
|
206
|
+
|--------|------|---------|-------------|
|
|
207
|
+
| `token` | `string` | **required** | Publishable key (`qt_`/`pk_` prefix). Server keys (`sk_`) are rejected. |
|
|
208
|
+
| `baseUrl` | `string` | `"https://logos.getquikturn.io"` | Override the API base URL |
|
|
209
|
+
| `maxRetries` | `number` | `2` | Max retry attempts for rate-limited/server-error responses |
|
|
210
|
+
|
|
211
|
+
#### `client.get(domain, options?)`
|
|
212
|
+
|
|
213
|
+
Fetches a logo and returns a `BrowserLogoResponse`.
|
|
214
|
+
|
|
215
|
+
| Option | Type | Default | Description |
|
|
216
|
+
|--------|------|---------|-------------|
|
|
217
|
+
| `size` | `number` | `128` | Output width in pixels |
|
|
218
|
+
| `width` | `number` | `128` | Alias for `size` |
|
|
219
|
+
| `greyscale` | `boolean` | `false` | Greyscale transformation |
|
|
220
|
+
| `theme` | `"light" \| "dark"` | -- | Gamma curve adjustment |
|
|
221
|
+
| `format` | `SupportedOutputFormat \| FormatShorthand` | `"image/png"` | Output format |
|
|
222
|
+
| `autoScrape` | `boolean` | `false` | Enable auto-scrape polling |
|
|
223
|
+
| `scrapeTimeout` | `number` | -- | Max time (ms) to wait for scrape completion |
|
|
224
|
+
| `onScrapeProgress` | `(event: ScrapeProgressEvent) => void` | -- | Callback for scrape progress |
|
|
225
|
+
| `signal` | `AbortSignal` | -- | Cancel the request |
|
|
226
|
+
|
|
227
|
+
**Returns:** `Promise<BrowserLogoResponse>`
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
interface BrowserLogoResponse {
|
|
231
|
+
url: string; // blob: object URL for <img src>
|
|
232
|
+
blob: Blob; // Raw image Blob
|
|
233
|
+
contentType: string; // e.g. "image/webp"
|
|
234
|
+
metadata: LogoMetadata;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### `client.getUrl(domain, options?)`
|
|
239
|
+
|
|
240
|
+
Returns a plain URL string without making a network request. Useful for `<img>` tags, CSS `background-image`, or preloading hints.
|
|
241
|
+
|
|
242
|
+
**Returns:** `string`
|
|
243
|
+
|
|
244
|
+
#### `client.on(event, handler)` / `client.off(event, handler)`
|
|
245
|
+
|
|
246
|
+
Register or remove event listeners.
|
|
247
|
+
|
|
248
|
+
| Event | Handler Signature | Description |
|
|
249
|
+
|-------|-------------------|-------------|
|
|
250
|
+
| `"rateLimitWarning"` | `(remaining: number, limit: number) => void` | Fires when rate limit is approaching |
|
|
251
|
+
| `"quotaWarning"` | `(remaining: number, limit: number) => void` | Fires when monthly quota is approaching |
|
|
252
|
+
|
|
253
|
+
#### `client.destroy()`
|
|
254
|
+
|
|
255
|
+
Revokes all tracked `blob:` object URLs to free memory and removes all event listeners. Call this when the client is no longer needed to prevent memory leaks in long-lived browser sessions.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
### Server Client (`@quikturn/logos/server`)
|
|
260
|
+
|
|
261
|
+
#### `new QuikturnLogos(options)`
|
|
262
|
+
|
|
263
|
+
| Option | Type | Default | Description |
|
|
264
|
+
|--------|------|---------|-------------|
|
|
265
|
+
| `secretKey` | `string` | **required** | Secret key (`sk_` prefix). Publishable keys (`qt_`/`pk_`) are rejected. |
|
|
266
|
+
| `baseUrl` | `string` | `"https://logos.getquikturn.io"` | Override the API base URL |
|
|
267
|
+
| `maxRetries` | `number` | `2` | Max retry attempts for rate-limited/server-error responses |
|
|
268
|
+
|
|
269
|
+
#### `client.get(domain, options?)`
|
|
270
|
+
|
|
271
|
+
Fetches a logo and returns a `ServerLogoResponse`.
|
|
272
|
+
|
|
273
|
+
Accepts the same options as the browser client's `get()` method.
|
|
274
|
+
|
|
275
|
+
**Returns:** `Promise<ServerLogoResponse>`
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
interface ServerLogoResponse {
|
|
279
|
+
buffer: Buffer; // Raw image bytes
|
|
280
|
+
contentType: string; // e.g. "image/png"
|
|
281
|
+
metadata: LogoMetadata;
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### `client.getMany(domains, options?)`
|
|
286
|
+
|
|
287
|
+
Fetches logos for multiple domains with concurrency control. Yields results in the same order as the input array.
|
|
288
|
+
|
|
289
|
+
| Option | Type | Default | Description |
|
|
290
|
+
|--------|------|---------|-------------|
|
|
291
|
+
| `concurrency` | `number` | `5` | Maximum parallel fetches |
|
|
292
|
+
| `size` | `number` | `128` | Output width in pixels |
|
|
293
|
+
| `greyscale` | `boolean` | `false` | Greyscale transformation |
|
|
294
|
+
| `theme` | `"light" \| "dark"` | -- | Gamma curve adjustment |
|
|
295
|
+
| `format` | `SupportedOutputFormat \| FormatShorthand` | `"image/png"` | Output format |
|
|
296
|
+
| `signal` | `AbortSignal` | -- | Cancel remaining batch items |
|
|
297
|
+
| `continueOnError` | `boolean` | `true` | Capture errors per-domain instead of aborting the batch |
|
|
298
|
+
|
|
299
|
+
**Returns:** `AsyncGenerator<BatchResult>`
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
interface BatchResult {
|
|
303
|
+
domain: string;
|
|
304
|
+
success: boolean;
|
|
305
|
+
buffer?: Buffer;
|
|
306
|
+
contentType?: string;
|
|
307
|
+
metadata?: LogoMetadata;
|
|
308
|
+
error?: LogoError;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### `client.getStream(domain, options?)`
|
|
313
|
+
|
|
314
|
+
Returns the raw response body as a `ReadableStream`. Useful for piping to a file or HTTP response without buffering the entire image in memory.
|
|
315
|
+
|
|
316
|
+
Accepts the same options as `get()`.
|
|
317
|
+
|
|
318
|
+
**Returns:** `Promise<ReadableStream>`
|
|
319
|
+
|
|
320
|
+
#### `client.getUrl(domain, options?)`
|
|
321
|
+
|
|
322
|
+
Returns a plain URL string with the secret key included as a token query parameter.
|
|
323
|
+
|
|
324
|
+
**Returns:** `string`
|
|
325
|
+
|
|
326
|
+
#### `client.on(event, handler)` / `client.off(event, handler)`
|
|
327
|
+
|
|
328
|
+
Same event interface as the browser client. Supports `"rateLimitWarning"` and `"quotaWarning"` events.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### Error Classes
|
|
333
|
+
|
|
334
|
+
All SDK errors extend `LogoError`, which extends the native `Error` class with a machine-readable `code` and an optional HTTP `status`.
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import {
|
|
338
|
+
LogoError,
|
|
339
|
+
DomainValidationError,
|
|
340
|
+
RateLimitError,
|
|
341
|
+
QuotaExceededError,
|
|
342
|
+
AuthenticationError,
|
|
343
|
+
ForbiddenError,
|
|
344
|
+
NotFoundError,
|
|
345
|
+
ScrapeTimeoutError,
|
|
346
|
+
BadRequestError,
|
|
347
|
+
} from "@quikturn/logos";
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
| Error Class | Code | HTTP Status | Extra Properties |
|
|
351
|
+
|-------------|------|-------------|------------------|
|
|
352
|
+
| `LogoError` | varies | varies | `code: LogoErrorCode`, `status?: number` |
|
|
353
|
+
| `DomainValidationError` | `DOMAIN_VALIDATION_ERROR` | -- | `domain: string` |
|
|
354
|
+
| `AuthenticationError` | `AUTHENTICATION_ERROR` | 401 | -- |
|
|
355
|
+
| `ForbiddenError` | `FORBIDDEN_ERROR` | 403 | `reason: string` |
|
|
356
|
+
| `NotFoundError` | `NOT_FOUND_ERROR` | 404 | `domain: string` |
|
|
357
|
+
| `BadRequestError` | `BAD_REQUEST_ERROR` | 400 | -- |
|
|
358
|
+
| `RateLimitError` | `RATE_LIMIT_ERROR` | 429 | `retryAfter: number`, `remaining: number`, `resetAt: Date` |
|
|
359
|
+
| `QuotaExceededError` | `QUOTA_EXCEEDED_ERROR` | 429 | `retryAfter: number`, `limit: number`, `used: number` |
|
|
360
|
+
| `ScrapeTimeoutError` | `SCRAPE_TIMEOUT_ERROR` | -- | `jobId: string`, `elapsed: number` |
|
|
361
|
+
|
|
362
|
+
All error codes are typed via the `LogoErrorCode` discriminated union for exhaustive switch handling:
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
import { LogoError } from "@quikturn/logos";
|
|
366
|
+
import type { LogoErrorCode } from "@quikturn/logos";
|
|
367
|
+
|
|
368
|
+
try {
|
|
369
|
+
const { url } = await client.get("example.com");
|
|
370
|
+
} catch (err) {
|
|
371
|
+
if (err instanceof LogoError) {
|
|
372
|
+
switch (err.code) {
|
|
373
|
+
case "RATE_LIMIT_ERROR":
|
|
374
|
+
// err is narrowed, handle backoff
|
|
375
|
+
break;
|
|
376
|
+
case "NOT_FOUND_ERROR":
|
|
377
|
+
// show placeholder
|
|
378
|
+
break;
|
|
379
|
+
// ... handle other cases
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Authentication
|
|
386
|
+
|
|
387
|
+
The Quikturn Logos API uses token-based authentication with two key types:
|
|
388
|
+
|
|
389
|
+
| Key Type | Prefix | Environment | Auth Method |
|
|
390
|
+
|----------|--------|-------------|-------------|
|
|
391
|
+
| **Publishable** | `qt_` or `pk_` | Browser | Query parameter (`?token=...`) |
|
|
392
|
+
| **Secret** | `sk_` | Server only | `Authorization: Bearer` header |
|
|
393
|
+
|
|
394
|
+
- **Publishable keys** are safe to expose in client-side code. They are passed as query parameters and support a max image width of 800px.
|
|
395
|
+
- **Secret keys** must never be exposed to the browser. They are sent via the `Authorization` header and support a max image width of 1200px.
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
// Browser -- publishable key
|
|
399
|
+
import { QuikturnLogos } from "@quikturn/logos/client";
|
|
400
|
+
const client = new QuikturnLogos({ token: "qt_your_publishable_key" });
|
|
401
|
+
|
|
402
|
+
// Server -- secret key
|
|
403
|
+
import { QuikturnLogos } from "@quikturn/logos/server";
|
|
404
|
+
const client = new QuikturnLogos({ secretKey: "sk_your_secret_key" });
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Configuration
|
|
408
|
+
|
|
409
|
+
### Custom Base URL
|
|
410
|
+
|
|
411
|
+
Override the API endpoint for testing, proxied environments, or self-hosted deployments:
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
const client = new QuikturnLogos({
|
|
415
|
+
token: "qt_your_key",
|
|
416
|
+
baseUrl: "https://logos-proxy.your-company.com",
|
|
417
|
+
});
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Format Options
|
|
421
|
+
|
|
422
|
+
Four output formats are supported:
|
|
423
|
+
|
|
424
|
+
| Format | MIME Type | Shorthand |
|
|
425
|
+
|--------|-----------|-----------|
|
|
426
|
+
| PNG | `image/png` | `"png"` |
|
|
427
|
+
| JPEG | `image/jpeg` | `"jpeg"` |
|
|
428
|
+
| WebP | `image/webp` | `"webp"` |
|
|
429
|
+
| AVIF | `image/avif` | `"avif"` |
|
|
430
|
+
|
|
431
|
+
Both the full MIME type and the shorthand alias are accepted:
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
// These are equivalent
|
|
435
|
+
client.get("github.com", { format: "image/webp" });
|
|
436
|
+
client.get("github.com", { format: "webp" });
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Theme Options
|
|
440
|
+
|
|
441
|
+
| Theme | Gamma | Use Case |
|
|
442
|
+
|-------|-------|----------|
|
|
443
|
+
| `"light"` | 0.9 | Light backgrounds |
|
|
444
|
+
| `"dark"` | 1.12 | Dark backgrounds |
|
|
445
|
+
|
|
446
|
+
## Auto-Scrape
|
|
447
|
+
|
|
448
|
+
When a logo is not found in the database, the SDK can automatically trigger a background scrape and poll for completion.
|
|
449
|
+
|
|
450
|
+
**Flow:** Request with `autoScrape: true` --> API returns `202 Accepted` with a scrape job --> SDK polls the job URL --> Logo becomes available --> SDK returns the final image.
|
|
451
|
+
|
|
452
|
+
```ts
|
|
453
|
+
const { url } = await client.get("brand-new-startup.com", {
|
|
454
|
+
autoScrape: true,
|
|
455
|
+
scrapeTimeout: 30_000, // wait up to 30 seconds
|
|
456
|
+
onScrapeProgress: (event) => {
|
|
457
|
+
console.log(`Scrape status: ${event.status}, progress: ${event.progress}%`);
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
If the scrape does not complete within `scrapeTimeout`, a `ScrapeTimeoutError` is thrown.
|
|
463
|
+
|
|
464
|
+
## Rate Limits & Quotas
|
|
465
|
+
|
|
466
|
+
### Per-Minute Rate Limits (Publishable Keys)
|
|
467
|
+
|
|
468
|
+
| Tier | Requests/min | Window |
|
|
469
|
+
|------|-------------|--------|
|
|
470
|
+
| Free | 100 | 60s |
|
|
471
|
+
| Launch | 500 | 60s |
|
|
472
|
+
| Growth | 5,000 | 60s |
|
|
473
|
+
| Enterprise | 50,000 | 60s |
|
|
474
|
+
|
|
475
|
+
### Per-Minute Rate Limits (Secret Keys)
|
|
476
|
+
|
|
477
|
+
| Tier | Requests/min | Window |
|
|
478
|
+
|------|-------------|--------|
|
|
479
|
+
| Launch | 1,000 | 60s |
|
|
480
|
+
| Growth | 10,000 | 60s |
|
|
481
|
+
| Enterprise | 100,000 | 60s |
|
|
482
|
+
|
|
483
|
+
> The free tier does not have server-side (secret key) access.
|
|
484
|
+
|
|
485
|
+
### Monthly Quotas
|
|
486
|
+
|
|
487
|
+
| Tier | Monthly Limit |
|
|
488
|
+
|------|--------------|
|
|
489
|
+
| Free | 500,000 |
|
|
490
|
+
| Launch | 1,000,000 |
|
|
491
|
+
| Growth | 5,000,000 |
|
|
492
|
+
| Enterprise | 10,000,000 |
|
|
493
|
+
|
|
494
|
+
Rate limits are enforced by the API server. The SDK reads `X-RateLimit-Remaining`, `X-Quota-Remaining`, and `Retry-After` headers to provide warnings via the event system and automatic retry with backoff.
|
|
495
|
+
|
|
496
|
+
## License
|
|
497
|
+
|
|
498
|
+
MIT
|