@rankwrangler/http-client 0.13.0 → 0.15.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/README.md +1 -1
- package/dist/app-router.d.ts +50 -44
- package/dist/credential-headers.d.ts +1 -0
- package/dist/credential-headers.js +23 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install @rankwrangler/http-client
|
|
|
13
13
|
import { createRankWranglerClient } from '@rankwrangler/http-client';
|
|
14
14
|
|
|
15
15
|
const client = createRankWranglerClient({
|
|
16
|
-
baseUrl: 'https://rankwrangler.merchbase.co',
|
|
16
|
+
baseUrl: 'https://rankwrangler-api.merchbase.co',
|
|
17
17
|
apiKey: process.env.MERCHBASE_API_KEY,
|
|
18
18
|
});
|
|
19
19
|
|
package/dist/app-router.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
+
export type ServiceAccessErrorCode = "access_denied" | "access_unavailable" | "insufficient_scope" | "unauthenticated" | "unknown_service";
|
|
3
4
|
export type AmazonListingStatus = "active" | "deleted";
|
|
4
5
|
declare const rankwranglerServiceAccounts: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
5
6
|
name: "rankwrangler_service_accounts";
|
|
@@ -184,18 +185,22 @@ declare const rankwranglerServiceAccounts: import("drizzle-orm/pg-core").PgTable
|
|
|
184
185
|
};
|
|
185
186
|
dialect: "pg";
|
|
186
187
|
}>;
|
|
187
|
-
|
|
188
|
+
/** The immutable identity of a user's service account; usage is read fresh where it is metered. */
|
|
189
|
+
export type RankWranglerServicePrincipal = Pick<typeof rankwranglerServiceAccounts.$inferSelect, "id" | "service"> & {
|
|
188
190
|
merchbaseUserId: string;
|
|
189
191
|
};
|
|
190
|
-
export interface
|
|
192
|
+
export interface MerchbaseUser {
|
|
191
193
|
sub: string;
|
|
192
194
|
email?: string;
|
|
193
195
|
}
|
|
194
|
-
export type CredentialKind = "api_key" | "oauth" | "session";
|
|
195
196
|
export interface ContextRequest {
|
|
197
|
+
method?: string;
|
|
198
|
+
url?: string;
|
|
196
199
|
headers: {
|
|
197
200
|
authorization?: string;
|
|
198
201
|
host?: string;
|
|
202
|
+
"cf-access-jwt-assertion"?: string;
|
|
203
|
+
"x-merchbase-user-id"?: string | string[];
|
|
199
204
|
};
|
|
200
205
|
}
|
|
201
206
|
declare const keywordStages: readonly [
|
|
@@ -231,7 +236,7 @@ export interface Product {
|
|
|
231
236
|
} | {
|
|
232
237
|
status: "unavailable";
|
|
233
238
|
};
|
|
234
|
-
isMerchListing: boolean
|
|
239
|
+
isMerchListing: boolean;
|
|
235
240
|
amazonListingStatus: AmazonListingStatus;
|
|
236
241
|
};
|
|
237
242
|
category: {
|
|
@@ -270,7 +275,7 @@ export interface KeywordResultsProduct {
|
|
|
270
275
|
} | {
|
|
271
276
|
status: "unavailable";
|
|
272
277
|
};
|
|
273
|
-
isMerchListing: boolean
|
|
278
|
+
isMerchListing: boolean;
|
|
274
279
|
amazonListingStatus: AmazonListingStatus;
|
|
275
280
|
category: {
|
|
276
281
|
id: number;
|
|
@@ -349,13 +354,13 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
349
354
|
credentialKind: null;
|
|
350
355
|
authExpiresAtMs: null;
|
|
351
356
|
accessPrincipal: null;
|
|
352
|
-
accessError:
|
|
357
|
+
accessError: ServiceAccessErrorCode | null;
|
|
353
358
|
request: ContextRequest;
|
|
354
359
|
} | {
|
|
355
|
-
user:
|
|
360
|
+
user: MerchbaseUser;
|
|
356
361
|
isAdmin: boolean;
|
|
357
362
|
authType: "access";
|
|
358
|
-
credentialKind:
|
|
363
|
+
credentialKind: "session" | "api_key" | "service_delegated" | "oauth";
|
|
359
364
|
authExpiresAtMs: number | null;
|
|
360
365
|
accessPrincipal: RankWranglerServicePrincipal;
|
|
361
366
|
accessError: null;
|
|
@@ -373,13 +378,13 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
373
378
|
credentialKind: null;
|
|
374
379
|
authExpiresAtMs: null;
|
|
375
380
|
accessPrincipal: null;
|
|
376
|
-
accessError:
|
|
381
|
+
accessError: ServiceAccessErrorCode | null;
|
|
377
382
|
request: ContextRequest;
|
|
378
383
|
} | {
|
|
379
|
-
user:
|
|
384
|
+
user: MerchbaseUser;
|
|
380
385
|
isAdmin: boolean;
|
|
381
386
|
authType: "access";
|
|
382
|
-
credentialKind:
|
|
387
|
+
credentialKind: "session" | "api_key" | "service_delegated" | "oauth";
|
|
383
388
|
authExpiresAtMs: number | null;
|
|
384
389
|
accessPrincipal: RankWranglerServicePrincipal;
|
|
385
390
|
accessError: null;
|
|
@@ -397,13 +402,13 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
397
402
|
credentialKind: null;
|
|
398
403
|
authExpiresAtMs: null;
|
|
399
404
|
accessPrincipal: null;
|
|
400
|
-
accessError:
|
|
405
|
+
accessError: ServiceAccessErrorCode | null;
|
|
401
406
|
request: ContextRequest;
|
|
402
407
|
} | {
|
|
403
|
-
user:
|
|
408
|
+
user: MerchbaseUser;
|
|
404
409
|
isAdmin: boolean;
|
|
405
410
|
authType: "access";
|
|
406
|
-
credentialKind:
|
|
411
|
+
credentialKind: "session" | "api_key" | "service_delegated" | "oauth";
|
|
407
412
|
authExpiresAtMs: number | null;
|
|
408
413
|
accessPrincipal: RankWranglerServicePrincipal;
|
|
409
414
|
accessError: null;
|
|
@@ -421,13 +426,13 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
421
426
|
credentialKind: null;
|
|
422
427
|
authExpiresAtMs: null;
|
|
423
428
|
accessPrincipal: null;
|
|
424
|
-
accessError:
|
|
429
|
+
accessError: ServiceAccessErrorCode | null;
|
|
425
430
|
request: ContextRequest;
|
|
426
431
|
} | {
|
|
427
|
-
user:
|
|
432
|
+
user: MerchbaseUser;
|
|
428
433
|
isAdmin: boolean;
|
|
429
434
|
authType: "access";
|
|
430
|
-
credentialKind:
|
|
435
|
+
credentialKind: "session" | "api_key" | "service_delegated" | "oauth";
|
|
431
436
|
authExpiresAtMs: number | null;
|
|
432
437
|
accessPrincipal: RankWranglerServicePrincipal;
|
|
433
438
|
accessError: null;
|
|
@@ -444,22 +449,22 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
444
449
|
output: {
|
|
445
450
|
keyword: string;
|
|
446
451
|
data: {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
nextCheckAt: string | null;
|
|
452
|
+
freshness: (typeof keywordFreshness)[number] | null;
|
|
453
|
+
products: number;
|
|
450
454
|
id: string;
|
|
455
|
+
createdAt: string;
|
|
456
|
+
searchFrequencyRank: number | null;
|
|
457
|
+
intervalDays: number | null;
|
|
451
458
|
queryId: string;
|
|
452
|
-
|
|
459
|
+
nextCheckAt: string | null;
|
|
453
460
|
stage: (typeof keywordStages)[number];
|
|
454
|
-
freshness: (typeof keywordFreshness)[number] | null;
|
|
455
|
-
retryScheduled: boolean;
|
|
456
461
|
heat: string;
|
|
457
462
|
score: number | null;
|
|
458
|
-
searchFrequencyRank: number | null;
|
|
459
|
-
sources: string[];
|
|
460
|
-
products: number;
|
|
461
463
|
merch: number;
|
|
462
|
-
|
|
464
|
+
term: string;
|
|
465
|
+
retryScheduled: boolean;
|
|
466
|
+
sources: string[];
|
|
467
|
+
lastCheckedAt: string | null;
|
|
463
468
|
};
|
|
464
469
|
};
|
|
465
470
|
meta: object;
|
|
@@ -476,9 +481,9 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
476
481
|
input: {
|
|
477
482
|
text: string;
|
|
478
483
|
freshness?: "live" | "needsSync" | "syncing" | "all" | undefined;
|
|
479
|
-
sort?: "work" | "newest" | undefined;
|
|
480
|
-
stage?: "trial" | "graduated" | "dropped" | "untracked" | "all" | undefined;
|
|
481
484
|
limit?: number | undefined;
|
|
485
|
+
sort?: "work" | "newest" | undefined;
|
|
486
|
+
stage?: "trial" | "dropped" | "graduated" | "untracked" | "all" | undefined;
|
|
482
487
|
heat?: "unrated" | "hot" | "warm" | "cold" | "all" | undefined;
|
|
483
488
|
cursor?: {
|
|
484
489
|
key: [
|
|
@@ -496,22 +501,22 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
496
501
|
};
|
|
497
502
|
output: {
|
|
498
503
|
items: {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
nextCheckAt: string | null;
|
|
504
|
+
freshness: (typeof keywordFreshness)[number] | null;
|
|
505
|
+
products: number;
|
|
502
506
|
id: string;
|
|
507
|
+
createdAt: string;
|
|
508
|
+
searchFrequencyRank: number | null;
|
|
509
|
+
intervalDays: number | null;
|
|
503
510
|
queryId: string;
|
|
504
|
-
|
|
511
|
+
nextCheckAt: string | null;
|
|
505
512
|
stage: (typeof keywordStages)[number];
|
|
506
|
-
freshness: (typeof keywordFreshness)[number] | null;
|
|
507
|
-
retryScheduled: boolean;
|
|
508
513
|
heat: string;
|
|
509
514
|
score: number | null;
|
|
510
|
-
searchFrequencyRank: number | null;
|
|
511
|
-
sources: string[];
|
|
512
|
-
products: number;
|
|
513
515
|
merch: number;
|
|
514
|
-
|
|
516
|
+
term: string;
|
|
517
|
+
retryScheduled: boolean;
|
|
518
|
+
sources: string[];
|
|
519
|
+
lastCheckedAt: string | null;
|
|
515
520
|
}[];
|
|
516
521
|
nextCursor: {
|
|
517
522
|
sort: "fresh" | "work" | "newest" | "score" | "medianBsr" | "merch";
|
|
@@ -538,13 +543,13 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
538
543
|
credentialKind: null;
|
|
539
544
|
authExpiresAtMs: null;
|
|
540
545
|
accessPrincipal: null;
|
|
541
|
-
accessError:
|
|
546
|
+
accessError: ServiceAccessErrorCode | null;
|
|
542
547
|
request: ContextRequest;
|
|
543
548
|
} | {
|
|
544
|
-
user:
|
|
549
|
+
user: MerchbaseUser;
|
|
545
550
|
isAdmin: boolean;
|
|
546
551
|
authType: "access";
|
|
547
|
-
credentialKind:
|
|
552
|
+
credentialKind: "session" | "api_key" | "service_delegated" | "oauth";
|
|
548
553
|
authExpiresAtMs: number | null;
|
|
549
554
|
accessPrincipal: RankWranglerServicePrincipal;
|
|
550
555
|
accessError: null;
|
|
@@ -593,7 +598,7 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
593
598
|
textFields?: "title" | "all" | undefined;
|
|
594
599
|
excludeWords?: string[] | undefined;
|
|
595
600
|
marketplaceIds?: string[] | undefined;
|
|
596
|
-
isMerchListing?: boolean | "
|
|
601
|
+
isMerchListing?: boolean | "all" | undefined;
|
|
597
602
|
amazonListingStatus?: "active" | "deleted" | "all" | undefined;
|
|
598
603
|
brands?: string[] | undefined;
|
|
599
604
|
excludeBrands?: string[] | undefined;
|
|
@@ -643,6 +648,7 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
643
648
|
} | null;
|
|
644
649
|
} | null;
|
|
645
650
|
items: {
|
|
651
|
+
extra?: undefined;
|
|
646
652
|
marketplaceId: string;
|
|
647
653
|
asin: string;
|
|
648
654
|
title: string | null;
|
|
@@ -656,7 +662,7 @@ export declare const publicAppRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
656
662
|
status: "unavailable";
|
|
657
663
|
url?: undefined;
|
|
658
664
|
};
|
|
659
|
-
isMerchListing: boolean
|
|
665
|
+
isMerchListing: boolean;
|
|
660
666
|
amazonListingStatus: AmazonListingStatus;
|
|
661
667
|
categoryId: number | null;
|
|
662
668
|
salesRank: number | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const credentialHeaders: (credential: string) => Record<string, string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const credentialHeaders = (credential) => {
|
|
2
|
+
if (!credential.startsWith('mbk_v1.'))
|
|
3
|
+
return { Authorization: `Bearer ${credential}` };
|
|
4
|
+
try {
|
|
5
|
+
if (credential.length > 2048)
|
|
6
|
+
throw new Error();
|
|
7
|
+
const encoded = credential.slice(7);
|
|
8
|
+
if (!/^[A-Za-z0-9_-]+$/.test(encoded))
|
|
9
|
+
throw new Error();
|
|
10
|
+
const decoded = atob(encoded.replace(/-/g, '+').replace(/_/g, '/'));
|
|
11
|
+
if (btoa(decoded).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') !== encoded)
|
|
12
|
+
throw new Error();
|
|
13
|
+
const parsed = JSON.parse(decoded);
|
|
14
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed) || Object.keys(parsed).length !== 2 || !('clientId' in parsed) || !('clientSecret' in parsed) ||
|
|
15
|
+
typeof parsed.clientId !== 'string' || !/^[A-Za-z0-9._-]{1,256}$/.test(parsed.clientId) ||
|
|
16
|
+
typeof parsed.clientSecret !== 'string' || !/^[A-Za-z0-9_-]{32,512}$/.test(parsed.clientSecret))
|
|
17
|
+
throw new Error();
|
|
18
|
+
return { 'CF-Access-Client-Id': parsed.clientId, 'CF-Access-Client-Secret': parsed.clientSecret };
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error('Invalid Merchbase machine credential.');
|
|
22
|
+
}
|
|
23
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createTRPCProxyClient } from '@trpc/client';
|
|
2
2
|
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
|
|
3
3
|
import type { PublicAppRouter } from './app-router';
|
|
4
|
-
export declare const DEFAULT_API_BASE_URL = "https://rankwrangler.merchbase.co";
|
|
4
|
+
export declare const DEFAULT_API_BASE_URL = "https://rankwrangler-api.merchbase.co";
|
|
5
5
|
export type AppRouter = PublicAppRouter;
|
|
6
6
|
export type RouterInputs = inferRouterInputs<PublicAppRouter>;
|
|
7
7
|
export type RouterOutputs = inferRouterOutputs<PublicAppRouter>;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { credentialHeaders } from './credential-headers.js';
|
|
1
2
|
import { createTRPCProxyClient, httpBatchLink, httpLink } from '@trpc/client';
|
|
2
3
|
const TRAILING_SLASHES_REGEX = /\/+$/;
|
|
3
|
-
export const DEFAULT_API_BASE_URL = 'https://rankwrangler.merchbase.co';
|
|
4
|
+
export const DEFAULT_API_BASE_URL = 'https://rankwrangler-api.merchbase.co';
|
|
4
5
|
export const createRankWranglerClient = ({ baseUrl, apiKey, headers, batch = true, }) => {
|
|
5
6
|
const url = `${normalizeBaseUrl(baseUrl)}/api`;
|
|
6
7
|
const resolveHeaders = () => ({
|
|
7
|
-
...(apiKey ?
|
|
8
|
+
...(apiKey ? credentialHeaders(apiKey) : {}),
|
|
8
9
|
...(headers ?? {}),
|
|
9
10
|
});
|
|
10
11
|
if (batch) {
|
|
@@ -12,6 +13,7 @@ export const createRankWranglerClient = ({ baseUrl, apiKey, headers, batch = tru
|
|
|
12
13
|
links: [
|
|
13
14
|
httpBatchLink({
|
|
14
15
|
url,
|
|
16
|
+
fetch: (input, init) => fetch(input, { ...init, redirect: 'manual' }),
|
|
15
17
|
headers: resolveHeaders,
|
|
16
18
|
}),
|
|
17
19
|
],
|
|
@@ -22,6 +24,7 @@ export const createRankWranglerClient = ({ baseUrl, apiKey, headers, batch = tru
|
|
|
22
24
|
links: [
|
|
23
25
|
httpLink({
|
|
24
26
|
url,
|
|
27
|
+
fetch: (input, init) => fetch(input, { ...init, redirect: 'manual' }),
|
|
25
28
|
headers: resolveHeaders,
|
|
26
29
|
}),
|
|
27
30
|
],
|