@quikturn/logos 0.2.0 → 0.2.1
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/README.md +11 -87
- package/dist/client/index.cjs +7 -59
- package/dist/client/index.d.cts +2 -187
- package/dist/client/index.d.ts +2 -187
- package/dist/client/index.mjs +8 -57
- package/dist/index.cjs +1 -91
- package/dist/index.d.cts +1 -167
- package/dist/index.d.ts +1 -167
- package/dist/index.mjs +2 -83
- package/dist/server/index.cjs +15 -24
- package/dist/server/index.d.cts +2 -94
- package/dist/server/index.d.ts +2 -94
- package/dist/server/index.mjs +16 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Zero-dependency URL builder** -- universal, works in any JavaScript runtime
|
|
8
|
-
- **Browser client** -- blob URL management, retry/backoff,
|
|
8
|
+
- **Browser client** -- blob URL management, retry/backoff, scrape polling, event emission
|
|
9
9
|
- **Server client** -- Buffer output, ReadableStream streaming, concurrent batch operations
|
|
10
10
|
- **Full TypeScript support** -- strict types, discriminated union error codes, generic response shapes
|
|
11
11
|
- **Tree-shakeable** -- ESM and CJS dual builds; import only what you need
|
|
@@ -107,7 +107,7 @@ Readable.fromWeb(stream).pipe(createWriteStream("logo.png"));
|
|
|
107
107
|
|
|
108
108
|
### Universal (`@quikturn/logos`)
|
|
109
109
|
|
|
110
|
-
The universal entry point exports the URL builder, types, constants, error classes
|
|
110
|
+
The universal entry point exports the URL builder, types, constants, and error classes. No network calls are made from this module.
|
|
111
111
|
|
|
112
112
|
#### `logoUrl(domain, options?)`
|
|
113
113
|
|
|
@@ -127,24 +127,17 @@ Constructs a fully-qualified Logos API URL. Pure function with no side effects.
|
|
|
127
127
|
| Property | Type | Default | Description |
|
|
128
128
|
|----------|------|---------|-------------|
|
|
129
129
|
| `token` | `string` | -- | Publishable key (`qt_`/`pk_`) appended as a query parameter |
|
|
130
|
-
| `size` | `number` | `128` | Output width in pixels
|
|
130
|
+
| `size` | `number` | `128` | Output width in pixels |
|
|
131
131
|
| `width` | `number` | `128` | Alias for `size` |
|
|
132
132
|
| `greyscale` | `boolean` | `false` | When `true`, applies saturation: 0 transformation |
|
|
133
|
-
| `theme` | `"light" \| "dark"` | -- |
|
|
133
|
+
| `theme` | `"light" \| "dark"` | -- | Optimize logo for light or dark backgrounds |
|
|
134
134
|
| `format` | `SupportedOutputFormat \| FormatShorthand` | `"image/png"` | Output image format |
|
|
135
|
-
| `autoScrape` | `boolean` | `false` | Trigger background scrape if logo is not found |
|
|
136
135
|
| `baseUrl` | `string` | `"https://logos.getquikturn.io"` | Override the API base URL |
|
|
137
136
|
|
|
138
137
|
#### Types
|
|
139
138
|
|
|
140
139
|
```ts
|
|
141
140
|
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
141
|
// Request
|
|
149
142
|
ThemeOption, // "light" | "dark"
|
|
150
143
|
SupportedOutputFormat, // "image/png" | "image/jpeg" | "image/webp" | "image/avif"
|
|
@@ -156,16 +149,9 @@ import type {
|
|
|
156
149
|
BrowserLogoResponse,
|
|
157
150
|
ServerLogoResponse,
|
|
158
151
|
|
|
159
|
-
//
|
|
160
|
-
ScrapeJob,
|
|
161
|
-
ScrapePendingResponse,
|
|
162
|
-
ScrapeJobStatus, // "pending" | "complete" | "failed"
|
|
152
|
+
// Scrape polling
|
|
163
153
|
ScrapeProgressEvent,
|
|
164
154
|
|
|
165
|
-
// Attribution (free tier)
|
|
166
|
-
AttributionStatus,
|
|
167
|
-
AttributionInfo,
|
|
168
|
-
|
|
169
155
|
// Error codes
|
|
170
156
|
LogoErrorCode,
|
|
171
157
|
} from "@quikturn/logos";
|
|
@@ -177,24 +163,9 @@ import type {
|
|
|
177
163
|
|----------|-------|-------------|
|
|
178
164
|
| `BASE_URL` | `"https://logos.getquikturn.io"` | Root API endpoint |
|
|
179
165
|
| `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
166
|
| `DEFAULT_FORMAT` | `"image/png"` | Default output MIME type |
|
|
183
167
|
| `SUPPORTED_FORMATS` | `Set<SupportedOutputFormat>` | All supported MIME types |
|
|
184
168
|
| `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
169
|
|
|
199
170
|
---
|
|
200
171
|
|
|
@@ -219,7 +190,6 @@ Fetches a logo and returns a `BrowserLogoResponse`.
|
|
|
219
190
|
| `greyscale` | `boolean` | `false` | Greyscale transformation |
|
|
220
191
|
| `theme` | `"light" \| "dark"` | -- | Gamma curve adjustment |
|
|
221
192
|
| `format` | `SupportedOutputFormat \| FormatShorthand` | `"image/png"` | Output format |
|
|
222
|
-
| `autoScrape` | `boolean` | `false` | Enable auto-scrape polling |
|
|
223
193
|
| `scrapeTimeout` | `number` | -- | Max time (ms) to wait for scrape completion |
|
|
224
194
|
| `onScrapeProgress` | `(event: ScrapeProgressEvent) => void` | -- | Callback for scrape progress |
|
|
225
195
|
| `signal` | `AbortSignal` | -- | Cancel the request |
|
|
@@ -319,7 +289,7 @@ Accepts the same options as `get()`.
|
|
|
319
289
|
|
|
320
290
|
#### `client.getUrl(domain, options?)`
|
|
321
291
|
|
|
322
|
-
Returns a plain URL string
|
|
292
|
+
Returns a plain URL string without making a network request. Does **not** include the secret key -- use the `Authorization: Bearer` header when fetching.
|
|
323
293
|
|
|
324
294
|
**Returns:** `string`
|
|
325
295
|
|
|
@@ -438,60 +408,14 @@ client.get("github.com", { format: "webp" });
|
|
|
438
408
|
|
|
439
409
|
### Theme Options
|
|
440
410
|
|
|
441
|
-
| Theme |
|
|
442
|
-
|
|
443
|
-
| `"light"` |
|
|
444
|
-
| `"dark"` |
|
|
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.
|
|
411
|
+
| Theme | Use Case |
|
|
412
|
+
|-------|----------|
|
|
413
|
+
| `"light"` | Optimized for light backgrounds |
|
|
414
|
+
| `"dark"` | Optimized for dark backgrounds |
|
|
463
415
|
|
|
464
416
|
## Rate Limits & Quotas
|
|
465
417
|
|
|
466
|
-
|
|
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.
|
|
418
|
+
Rate limits and monthly quotas are enforced by the API server and vary by plan. The SDK automatically reads rate-limit headers to provide warnings via the event system and retries with backoff when limits are hit. See [Quikturn pricing](https://getquikturn.io/pricing) for details on your plan's limits.
|
|
495
419
|
|
|
496
420
|
## License
|
|
497
421
|
|
package/dist/client/index.cjs
CHANGED
|
@@ -183,7 +183,6 @@ function logoUrl(domain, options) {
|
|
|
183
183
|
greyscale,
|
|
184
184
|
theme,
|
|
185
185
|
format,
|
|
186
|
-
autoScrape,
|
|
187
186
|
baseUrl
|
|
188
187
|
} = options ?? {};
|
|
189
188
|
const maxWidth = token?.startsWith("sk_") ? MAX_WIDTH_SERVER : MAX_WIDTH;
|
|
@@ -210,9 +209,7 @@ function logoUrl(domain, options) {
|
|
|
210
209
|
if (resolvedFormat !== void 0) {
|
|
211
210
|
url.searchParams.set("format", resolvedFormat);
|
|
212
211
|
}
|
|
213
|
-
|
|
214
|
-
url.searchParams.set("autoScrape", "true");
|
|
215
|
-
}
|
|
212
|
+
url.searchParams.set("autoScrape", "true");
|
|
216
213
|
return url.toString();
|
|
217
214
|
}
|
|
218
215
|
|
|
@@ -520,49 +517,6 @@ async function handleScrapeResponse(response, originalUrl, fetchFn, options) {
|
|
|
520
517
|
}
|
|
521
518
|
}
|
|
522
519
|
|
|
523
|
-
// src/client/attribution.ts
|
|
524
|
-
var VALID_ATTRIBUTION_STATUSES = /* @__PURE__ */ new Set([
|
|
525
|
-
"verified",
|
|
526
|
-
"pending",
|
|
527
|
-
"unverified",
|
|
528
|
-
"failed",
|
|
529
|
-
"grace-period",
|
|
530
|
-
"error"
|
|
531
|
-
]);
|
|
532
|
-
var ALWAYS_VALID_STATUSES = /* @__PURE__ */ new Set([
|
|
533
|
-
"verified",
|
|
534
|
-
"pending"
|
|
535
|
-
]);
|
|
536
|
-
function safeParseDate(value) {
|
|
537
|
-
if (value === null) return void 0;
|
|
538
|
-
const date = new Date(value);
|
|
539
|
-
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
540
|
-
}
|
|
541
|
-
function computeIsValid(status, graceDeadline) {
|
|
542
|
-
if (ALWAYS_VALID_STATUSES.has(status)) return true;
|
|
543
|
-
if (status === "grace-period") {
|
|
544
|
-
return graceDeadline !== void 0 && graceDeadline.getTime() > Date.now();
|
|
545
|
-
}
|
|
546
|
-
return false;
|
|
547
|
-
}
|
|
548
|
-
function parseAttributionStatus(headers) {
|
|
549
|
-
const rawStatus = headers.get("X-Attribution-Status");
|
|
550
|
-
if (rawStatus === null) return null;
|
|
551
|
-
if (!VALID_ATTRIBUTION_STATUSES.has(rawStatus)) {
|
|
552
|
-
return { status: "error", isValid: false };
|
|
553
|
-
}
|
|
554
|
-
const status = rawStatus;
|
|
555
|
-
const graceDeadline = safeParseDate(headers.get("X-Attribution-Grace-Deadline"));
|
|
556
|
-
const verifiedAt = safeParseDate(headers.get("X-Attribution-Verified-At"));
|
|
557
|
-
const isValid = computeIsValid(status, graceDeadline);
|
|
558
|
-
return {
|
|
559
|
-
status,
|
|
560
|
-
isValid,
|
|
561
|
-
...graceDeadline !== void 0 ? { graceDeadline } : {},
|
|
562
|
-
...verifiedAt !== void 0 ? { verifiedAt } : {}
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
|
|
566
520
|
// src/client/index.ts
|
|
567
521
|
var QuikturnLogos = class {
|
|
568
522
|
constructor(options) {
|
|
@@ -606,7 +560,6 @@ var QuikturnLogos = class {
|
|
|
606
560
|
greyscale: options?.greyscale,
|
|
607
561
|
theme: options?.theme,
|
|
608
562
|
format: options?.format,
|
|
609
|
-
autoScrape: options?.autoScrape,
|
|
610
563
|
baseUrl: this.baseUrl
|
|
611
564
|
});
|
|
612
565
|
const format = options?.format;
|
|
@@ -618,14 +571,12 @@ var QuikturnLogos = class {
|
|
|
618
571
|
onRateLimitWarning: (remaining, limit) => this.emit("rateLimitWarning", remaining, limit),
|
|
619
572
|
onQuotaWarning: (remaining, limit) => this.emit("quotaWarning", remaining, limit)
|
|
620
573
|
});
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
});
|
|
628
|
-
}
|
|
574
|
+
response = await handleScrapeResponse(response, url, browserFetch, {
|
|
575
|
+
scrapeTimeout: options?.scrapeTimeout,
|
|
576
|
+
onScrapeProgress: options?.onScrapeProgress,
|
|
577
|
+
signal: options?.signal,
|
|
578
|
+
token: this.token
|
|
579
|
+
});
|
|
629
580
|
const contentLength = response.headers.get("Content-Length");
|
|
630
581
|
if (contentLength) {
|
|
631
582
|
const size = parseInt(contentLength, 10);
|
|
@@ -721,6 +672,3 @@ var QuikturnLogos = class {
|
|
|
721
672
|
};
|
|
722
673
|
|
|
723
674
|
exports.QuikturnLogos = QuikturnLogos;
|
|
724
|
-
exports.browserFetch = browserFetch;
|
|
725
|
-
exports.handleScrapeResponse = handleScrapeResponse;
|
|
726
|
-
exports.parseAttributionStatus = parseAttributionStatus;
|
package/dist/client/index.d.cts
CHANGED
|
@@ -67,189 +67,6 @@ interface ScrapeProgressEvent {
|
|
|
67
67
|
};
|
|
68
68
|
error?: string;
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Possible attribution verification states for free-tier consumers.
|
|
72
|
-
*
|
|
73
|
-
* - "verified" — Attribution confirmed and valid.
|
|
74
|
-
* - "pending" — Verification in progress; treated as valid.
|
|
75
|
-
* - "unverified" — Attribution not yet set up.
|
|
76
|
-
* - "failed" — Verification attempted but failed.
|
|
77
|
-
* - "grace-period" — Temporary grace; validity depends on graceDeadline.
|
|
78
|
-
* - "error" — An error occurred during verification.
|
|
79
|
-
*/
|
|
80
|
-
type AttributionStatus = "verified" | "pending" | "unverified" | "failed" | "grace-period" | "error";
|
|
81
|
-
/**
|
|
82
|
-
* Structured attribution information parsed from response headers.
|
|
83
|
-
*
|
|
84
|
-
* - `status` — Current attribution verification state.
|
|
85
|
-
* - `graceDeadline` — If in grace period, the deadline by which attribution must be verified.
|
|
86
|
-
* - `verifiedAt` — Timestamp of when attribution was last verified.
|
|
87
|
-
* - `isValid` — Derived boolean: true when status is "verified", "pending",
|
|
88
|
-
* or "grace-period" with a future graceDeadline.
|
|
89
|
-
*/
|
|
90
|
-
interface AttributionInfo {
|
|
91
|
-
status: AttributionStatus;
|
|
92
|
-
graceDeadline?: Date;
|
|
93
|
-
verifiedAt?: Date;
|
|
94
|
-
isValid: boolean;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* @quikturn/logos SDK — Browser Fetch Wrapper
|
|
99
|
-
*
|
|
100
|
-
* Low-level fetch wrapper for the browser client entry point. Handles HTTP
|
|
101
|
-
* error mapping, retry logic for rate-limited and server-error responses,
|
|
102
|
-
* AbortSignal propagation, and proactive warning callbacks when rate-limit
|
|
103
|
-
* or quota headroom drops below 10%.
|
|
104
|
-
*
|
|
105
|
-
* This module NEVER sets an Authorization header. Publishable keys are
|
|
106
|
-
* passed as query parameters by the URL builder, not as bearer tokens.
|
|
107
|
-
*/
|
|
108
|
-
/**
|
|
109
|
-
* Options accepted by {@link browserFetch}.
|
|
110
|
-
*
|
|
111
|
-
* - `maxRetries` — Maximum number of retry attempts for 429/500 responses. Default: 2.
|
|
112
|
-
* - `signal` — An `AbortSignal` to cancel the in-flight request.
|
|
113
|
-
* - `format` — MIME type string used as the `Accept` request header.
|
|
114
|
-
* - `onRateLimitWarning` — Called when `X-RateLimit-Remaining` drops below 10% of the limit.
|
|
115
|
-
* - `onQuotaWarning` — Called when `X-Quota-Remaining` drops below 10% of the limit.
|
|
116
|
-
*/
|
|
117
|
-
interface FetcherOptions {
|
|
118
|
-
maxRetries?: number;
|
|
119
|
-
signal?: AbortSignal;
|
|
120
|
-
format?: string;
|
|
121
|
-
onRateLimitWarning?: (remaining: number, limit: number) => void;
|
|
122
|
-
onQuotaWarning?: (remaining: number, limit: number) => void;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Performs a fetch request to the Logos API with error mapping and retry logic.
|
|
126
|
-
*
|
|
127
|
-
* **Error mapping:**
|
|
128
|
-
* | Status | Error Class | Notes |
|
|
129
|
-
* |--------|-----------------------|--------------------------------------------|
|
|
130
|
-
* | 401 | AuthenticationError | Invalid or missing API token |
|
|
131
|
-
* | 403 | ForbiddenError | Body text used as `reason` |
|
|
132
|
-
* | 404 | NotFoundError | Domain extracted from URL path |
|
|
133
|
-
* | 429 | QuotaExceededError | When `X-Quota-Limit` header is present |
|
|
134
|
-
* | 429 | RateLimitError | After retries are exhausted |
|
|
135
|
-
* | 500 | LogoError | After a single retry attempt |
|
|
136
|
-
*
|
|
137
|
-
* **Retry behavior:**
|
|
138
|
-
* - 429: Waits `Retry-After` seconds (default 60s), retries up to `maxRetries`.
|
|
139
|
-
* If `X-Quota-Limit` is present, throws `QuotaExceededError` immediately.
|
|
140
|
-
* - 500: Retries once after a 1-second delay, then throws.
|
|
141
|
-
* - AbortError: Never retried; throws immediately.
|
|
142
|
-
* - Network errors: Never retried; throws immediately.
|
|
143
|
-
*
|
|
144
|
-
* @param url - Fully-qualified Logos API URL (built by `logoUrl`).
|
|
145
|
-
* @param options - Optional fetch configuration.
|
|
146
|
-
* @returns The raw `Response` object on success (2xx).
|
|
147
|
-
*
|
|
148
|
-
* @throws {AuthenticationError} On 401.
|
|
149
|
-
* @throws {ForbiddenError} On 403.
|
|
150
|
-
* @throws {NotFoundError} On 404.
|
|
151
|
-
* @throws {RateLimitError} On 429 after retries exhausted (no quota header).
|
|
152
|
-
* @throws {QuotaExceededError} On 429 with `X-Quota-Limit` header.
|
|
153
|
-
* @throws {LogoError} On 500, network error, or abort.
|
|
154
|
-
*/
|
|
155
|
-
declare function browserFetch(url: string, options?: FetcherOptions): Promise<Response>;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* @quikturn/logos SDK -- Scrape Poller
|
|
159
|
-
*
|
|
160
|
-
* Handles 202 (scrape_pending) responses from the Logos API. When the API
|
|
161
|
-
* returns a 202 with a {@link ScrapePendingResponse} body, this module polls
|
|
162
|
-
* the scrape job status URL with exponential backoff until the job completes,
|
|
163
|
-
* fails, or the configured timeout elapses.
|
|
164
|
-
*
|
|
165
|
-
* On completion, re-fetches the original logo URL (with optional token) and
|
|
166
|
-
* returns the final Response to the caller.
|
|
167
|
-
*/
|
|
168
|
-
|
|
169
|
-
/** A fetch function that takes a URL and returns a Response promise. */
|
|
170
|
-
type FetchFn = (url: string) => Promise<Response>;
|
|
171
|
-
/**
|
|
172
|
-
* Options accepted by {@link handleScrapeResponse}.
|
|
173
|
-
*
|
|
174
|
-
* - `scrapeTimeout` -- Maximum time (ms) to wait for the scrape to complete. Default: 30_000.
|
|
175
|
-
* - `onScrapeProgress` -- Called after each poll with the latest progress event.
|
|
176
|
-
* - `signal` -- An `AbortSignal` to cancel the polling loop.
|
|
177
|
-
* - `token` -- API token appended to the final logo re-fetch URL.
|
|
178
|
-
*/
|
|
179
|
-
interface ScrapePollerOptions {
|
|
180
|
-
scrapeTimeout?: number;
|
|
181
|
-
onScrapeProgress?: (event: ScrapeProgressEvent) => void;
|
|
182
|
-
signal?: AbortSignal;
|
|
183
|
-
token?: string;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Inspects a response from the Logos API and, if it is a 202 (scrape pending),
|
|
187
|
-
* polls the scrape job until completion and re-fetches the logo.
|
|
188
|
-
*
|
|
189
|
-
* **Non-202 responses** are returned immediately as a passthrough.
|
|
190
|
-
*
|
|
191
|
-
* **202 responses** trigger the following lifecycle:
|
|
192
|
-
* 1. Parse the {@link ScrapePendingResponse} JSON body to extract `scrapeJob`.
|
|
193
|
-
* 2. Wait `estimatedWaitMs` (the initial backoff interval).
|
|
194
|
-
* 3. Poll `scrapeJob.pollUrl` via `fetchFn`, parse the {@link ScrapeProgressEvent}.
|
|
195
|
-
* 4. Call `onScrapeProgress` with the event.
|
|
196
|
-
* 5. If `status === "complete"`, re-fetch `originalUrl` (with token if provided).
|
|
197
|
-
* 6. If `status === "failed"`, throw `LogoError` with code `SCRAPE_FAILED`.
|
|
198
|
-
* 7. If `status === "pending"`, double the backoff (capped at 5 s) and repeat.
|
|
199
|
-
* 8. If `scrapeTimeout` elapses, throw {@link ScrapeTimeoutError}.
|
|
200
|
-
* 9. If `signal` is aborted, throw `LogoError` with code `ABORT_ERROR`.
|
|
201
|
-
*
|
|
202
|
-
* @param response -- The raw Response from the initial logo fetch.
|
|
203
|
-
* @param originalUrl -- The original logo URL (re-fetched after scrape completes).
|
|
204
|
-
* @param fetchFn -- The fetch function (typically `browserFetch`).
|
|
205
|
-
* @param options -- Optional polling configuration.
|
|
206
|
-
* @returns The final logo Response on success.
|
|
207
|
-
*
|
|
208
|
-
* @throws {ScrapeTimeoutError} When polling exceeds `scrapeTimeout`.
|
|
209
|
-
* @throws {LogoError} When the scrape job fails, is aborted, or encounters a network error.
|
|
210
|
-
*/
|
|
211
|
-
declare function handleScrapeResponse(response: Response, originalUrl: string, fetchFn: FetchFn, options?: ScrapePollerOptions): Promise<Response>;
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* @quikturn/logos SDK — Attribution Header Parser
|
|
215
|
-
*
|
|
216
|
-
* Parses attribution-related response headers returned by the Cloudflare Worker
|
|
217
|
-
* for free-tier consumers. The worker attaches these headers to indicate whether
|
|
218
|
-
* the consumer has properly attributed Quikturn on their site.
|
|
219
|
-
*
|
|
220
|
-
* | Header | Field |
|
|
221
|
-
* |----------------------------------|-----------------|
|
|
222
|
-
* | `X-Attribution-Status` | `status` |
|
|
223
|
-
* | `X-Attribution-Grace-Deadline` | `graceDeadline` |
|
|
224
|
-
* | `X-Attribution-Verified-At` | `verifiedAt` |
|
|
225
|
-
*
|
|
226
|
-
* The derived `isValid` field is computed from the status:
|
|
227
|
-
* - "verified" -> true
|
|
228
|
-
* - "pending" -> true
|
|
229
|
-
* - "grace-period" -> true only if graceDeadline exists and is in the future
|
|
230
|
-
* - "unverified" -> false
|
|
231
|
-
* - "failed" -> false
|
|
232
|
-
* - "error" -> false
|
|
233
|
-
*/
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Parses attribution response headers into a typed `AttributionInfo` object.
|
|
237
|
-
*
|
|
238
|
-
* Returns `null` when the `X-Attribution-Status` header is absent, indicating
|
|
239
|
-
* that the response is not from a free-tier request (attribution does not apply).
|
|
240
|
-
*
|
|
241
|
-
* @param headers - The `Headers` object from a fetch `Response`.
|
|
242
|
-
* @returns An `AttributionInfo` object, or `null` if no attribution header is present.
|
|
243
|
-
*
|
|
244
|
-
* @example
|
|
245
|
-
* ```ts
|
|
246
|
-
* const attribution = parseAttributionStatus(response.headers);
|
|
247
|
-
* if (attribution && !attribution.isValid) {
|
|
248
|
-
* console.warn("Attribution required for free-tier usage");
|
|
249
|
-
* }
|
|
250
|
-
* ```
|
|
251
|
-
*/
|
|
252
|
-
declare function parseAttributionStatus(headers: Headers): AttributionInfo | null;
|
|
253
70
|
|
|
254
71
|
/**
|
|
255
72
|
* @quikturn/logos SDK — Browser Client Class
|
|
@@ -291,7 +108,6 @@ interface BrowserClientOptions {
|
|
|
291
108
|
* - `greyscale` — When true, returns a greyscale image.
|
|
292
109
|
* - `theme` — "light" or "dark" gamma adjustment.
|
|
293
110
|
* - `format` — Output image format (MIME type or shorthand).
|
|
294
|
-
* - `autoScrape` — When true, triggers background scrape if logo is not found.
|
|
295
111
|
* - `scrapeTimeout` — Maximum time (ms) to wait for a scrape to complete.
|
|
296
112
|
* - `onScrapeProgress`— Callback fired on each scrape poll.
|
|
297
113
|
* - `signal` — AbortSignal to cancel the request.
|
|
@@ -302,7 +118,6 @@ interface GetOptions {
|
|
|
302
118
|
greyscale?: boolean;
|
|
303
119
|
theme?: ThemeOption;
|
|
304
120
|
format?: SupportedOutputFormat | FormatShorthand;
|
|
305
|
-
autoScrape?: boolean;
|
|
306
121
|
scrapeTimeout?: number;
|
|
307
122
|
onScrapeProgress?: (event: ScrapeProgressEvent) => void;
|
|
308
123
|
signal?: AbortSignal;
|
|
@@ -363,7 +178,7 @@ declare class QuikturnLogos {
|
|
|
363
178
|
* // => "https://logos.getquikturn.io/github.com?token=qt_abc123&format=webp"
|
|
364
179
|
* ```
|
|
365
180
|
*/
|
|
366
|
-
getUrl(domain: string, options?: Omit<GetOptions, "
|
|
181
|
+
getUrl(domain: string, options?: Omit<GetOptions, "scrapeTimeout" | "onScrapeProgress" | "signal">): string;
|
|
367
182
|
/**
|
|
368
183
|
* Registers an event listener for a client event.
|
|
369
184
|
*
|
|
@@ -396,4 +211,4 @@ declare class QuikturnLogos {
|
|
|
396
211
|
private emit;
|
|
397
212
|
}
|
|
398
213
|
|
|
399
|
-
export { type BrowserClientOptions, type ClientEvent, type EventHandler, type
|
|
214
|
+
export { type BrowserClientOptions, type ClientEvent, type EventHandler, type GetOptions, QuikturnLogos };
|