recker 1.0.26 → 1.0.27
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/dist/browser/browser/cache.d.ts +40 -0
- package/dist/browser/browser/cache.js +199 -0
- package/dist/browser/browser/crypto.d.ts +24 -0
- package/dist/browser/browser/crypto.js +80 -0
- package/dist/browser/browser/index.d.ts +31 -0
- package/dist/browser/browser/index.js +31 -0
- package/dist/browser/browser/recker.d.ts +26 -0
- package/dist/browser/browser/recker.js +61 -0
- package/dist/browser/cache/basic-file-storage.d.ts +12 -0
- package/dist/browser/cache/basic-file-storage.js +50 -0
- package/dist/browser/cache/memory-limits.d.ts +20 -0
- package/dist/browser/cache/memory-limits.js +96 -0
- package/dist/browser/cache/memory-storage.d.ts +132 -0
- package/dist/browser/cache/memory-storage.js +454 -0
- package/dist/browser/cache.d.ts +40 -0
- package/dist/browser/cache.js +199 -0
- package/dist/browser/constants/http-status.d.ts +73 -0
- package/dist/browser/constants/http-status.js +156 -0
- package/dist/browser/cookies/memory-cookie-jar.d.ts +30 -0
- package/dist/browser/cookies/memory-cookie-jar.js +210 -0
- package/dist/browser/core/client.d.ts +118 -0
- package/dist/browser/core/client.js +667 -0
- package/dist/browser/core/errors.d.ts +142 -0
- package/dist/browser/core/errors.js +308 -0
- package/dist/browser/core/index.d.ts +5 -0
- package/dist/browser/core/index.js +5 -0
- package/dist/browser/core/request-promise.d.ts +23 -0
- package/dist/browser/core/request-promise.js +82 -0
- package/dist/browser/core/request.d.ts +20 -0
- package/dist/browser/core/request.js +76 -0
- package/dist/browser/core/response.d.ts +34 -0
- package/dist/browser/core/response.js +178 -0
- package/dist/browser/crypto.d.ts +24 -0
- package/dist/browser/crypto.js +80 -0
- package/dist/browser/index.d.ts +31 -0
- package/dist/browser/index.js +31 -0
- package/dist/browser/plugins/auth/api-key.d.ts +8 -0
- package/dist/browser/plugins/auth/api-key.js +27 -0
- package/dist/browser/plugins/auth/auth0.d.ts +33 -0
- package/dist/browser/plugins/auth/auth0.js +94 -0
- package/dist/browser/plugins/auth/aws-sigv4.d.ts +10 -0
- package/dist/browser/plugins/auth/aws-sigv4.js +88 -0
- package/dist/browser/plugins/auth/azure-ad.d.ts +48 -0
- package/dist/browser/plugins/auth/azure-ad.js +152 -0
- package/dist/browser/plugins/auth/basic.d.ts +7 -0
- package/dist/browser/plugins/auth/basic.js +13 -0
- package/dist/browser/plugins/auth/bearer.d.ts +8 -0
- package/dist/browser/plugins/auth/bearer.js +17 -0
- package/dist/browser/plugins/auth/cognito.d.ts +45 -0
- package/dist/browser/plugins/auth/cognito.js +208 -0
- package/dist/browser/plugins/auth/digest.d.ts +8 -0
- package/dist/browser/plugins/auth/digest.js +100 -0
- package/dist/browser/plugins/auth/firebase.d.ts +32 -0
- package/dist/browser/plugins/auth/firebase.js +195 -0
- package/dist/browser/plugins/auth/github-app.d.ts +36 -0
- package/dist/browser/plugins/auth/github-app.js +170 -0
- package/dist/browser/plugins/auth/google-service-account.d.ts +49 -0
- package/dist/browser/plugins/auth/google-service-account.js +172 -0
- package/dist/browser/plugins/auth/index.d.ts +15 -0
- package/dist/browser/plugins/auth/index.js +15 -0
- package/dist/browser/plugins/auth/mtls.d.ts +37 -0
- package/dist/browser/plugins/auth/mtls.js +140 -0
- package/dist/browser/plugins/auth/oauth2.d.ts +8 -0
- package/dist/browser/plugins/auth/oauth2.js +26 -0
- package/dist/browser/plugins/auth/oidc.d.ts +55 -0
- package/dist/browser/plugins/auth/oidc.js +222 -0
- package/dist/browser/plugins/auth/okta.d.ts +47 -0
- package/dist/browser/plugins/auth/okta.js +157 -0
- package/dist/browser/plugins/auth.d.ts +1 -0
- package/dist/browser/plugins/auth.js +1 -0
- package/dist/browser/plugins/cache.d.ts +15 -0
- package/dist/browser/plugins/cache.js +486 -0
- package/dist/browser/plugins/circuit-breaker.d.ts +13 -0
- package/dist/browser/plugins/circuit-breaker.js +100 -0
- package/dist/browser/plugins/compression.d.ts +4 -0
- package/dist/browser/plugins/compression.js +130 -0
- package/dist/browser/plugins/cookie-jar.d.ts +5 -0
- package/dist/browser/plugins/cookie-jar.js +72 -0
- package/dist/browser/plugins/dedup.d.ts +5 -0
- package/dist/browser/plugins/dedup.js +35 -0
- package/dist/browser/plugins/graphql.d.ts +13 -0
- package/dist/browser/plugins/graphql.js +58 -0
- package/dist/browser/plugins/grpc-web.d.ts +79 -0
- package/dist/browser/plugins/grpc-web.js +261 -0
- package/dist/browser/plugins/hls.d.ts +105 -0
- package/dist/browser/plugins/hls.js +395 -0
- package/dist/browser/plugins/jsonrpc.d.ts +75 -0
- package/dist/browser/plugins/jsonrpc.js +143 -0
- package/dist/browser/plugins/logger.d.ts +13 -0
- package/dist/browser/plugins/logger.js +108 -0
- package/dist/browser/plugins/odata.d.ts +181 -0
- package/dist/browser/plugins/odata.js +564 -0
- package/dist/browser/plugins/pagination.d.ts +16 -0
- package/dist/browser/plugins/pagination.js +105 -0
- package/dist/browser/plugins/rate-limit.d.ts +15 -0
- package/dist/browser/plugins/rate-limit.js +162 -0
- package/dist/browser/plugins/retry.d.ts +14 -0
- package/dist/browser/plugins/retry.js +116 -0
- package/dist/browser/plugins/scrape.d.ts +21 -0
- package/dist/browser/plugins/scrape.js +82 -0
- package/dist/browser/plugins/server-timing.d.ts +7 -0
- package/dist/browser/plugins/server-timing.js +24 -0
- package/dist/browser/plugins/soap.d.ts +72 -0
- package/dist/browser/plugins/soap.js +347 -0
- package/dist/browser/plugins/xml.d.ts +9 -0
- package/dist/browser/plugins/xml.js +194 -0
- package/dist/browser/plugins/xsrf.d.ts +9 -0
- package/dist/browser/plugins/xsrf.js +48 -0
- package/dist/browser/recker.d.ts +26 -0
- package/dist/browser/recker.js +61 -0
- package/dist/browser/runner/request-runner.d.ts +46 -0
- package/dist/browser/runner/request-runner.js +89 -0
- package/dist/browser/scrape/document.d.ts +44 -0
- package/dist/browser/scrape/document.js +210 -0
- package/dist/browser/scrape/element.d.ts +49 -0
- package/dist/browser/scrape/element.js +176 -0
- package/dist/browser/scrape/extractors.d.ts +16 -0
- package/dist/browser/scrape/extractors.js +356 -0
- package/dist/browser/scrape/types.d.ts +107 -0
- package/dist/browser/scrape/types.js +1 -0
- package/dist/browser/transport/fetch.d.ts +11 -0
- package/dist/browser/transport/fetch.js +143 -0
- package/dist/browser/transport/undici.d.ts +38 -0
- package/dist/browser/transport/undici.js +897 -0
- package/dist/browser/types/ai.d.ts +267 -0
- package/dist/browser/types/ai.js +1 -0
- package/dist/browser/types/index.d.ts +351 -0
- package/dist/browser/types/index.js +1 -0
- package/dist/browser/types/logger.d.ts +16 -0
- package/dist/browser/types/logger.js +66 -0
- package/dist/browser/types/udp.d.ts +138 -0
- package/dist/browser/types/udp.js +1 -0
- package/dist/browser/utils/agent-manager.d.ts +29 -0
- package/dist/browser/utils/agent-manager.js +160 -0
- package/dist/browser/utils/body.d.ts +10 -0
- package/dist/browser/utils/body.js +148 -0
- package/dist/browser/utils/charset.d.ts +15 -0
- package/dist/browser/utils/charset.js +169 -0
- package/dist/browser/utils/concurrency.d.ts +20 -0
- package/dist/browser/utils/concurrency.js +120 -0
- package/dist/browser/utils/dns.d.ts +6 -0
- package/dist/browser/utils/dns.js +26 -0
- package/dist/browser/utils/header-parser.d.ts +94 -0
- package/dist/browser/utils/header-parser.js +617 -0
- package/dist/browser/utils/html-cleaner.d.ts +1 -0
- package/dist/browser/utils/html-cleaner.js +21 -0
- package/dist/browser/utils/link-header.d.ts +69 -0
- package/dist/browser/utils/link-header.js +190 -0
- package/dist/browser/utils/optional-require.d.ts +19 -0
- package/dist/browser/utils/optional-require.js +105 -0
- package/dist/browser/utils/progress.d.ts +8 -0
- package/dist/browser/utils/progress.js +82 -0
- package/dist/browser/utils/request-pool.d.ts +22 -0
- package/dist/browser/utils/request-pool.js +101 -0
- package/dist/browser/utils/sse.d.ts +7 -0
- package/dist/browser/utils/sse.js +67 -0
- package/dist/browser/utils/streaming.d.ts +17 -0
- package/dist/browser/utils/streaming.js +84 -0
- package/dist/browser/utils/try-fn.d.ts +3 -0
- package/dist/browser/utils/try-fn.js +59 -0
- package/dist/browser/utils/user-agent.d.ts +44 -0
- package/dist/browser/utils/user-agent.js +100 -0
- package/dist/browser/utils/whois.d.ts +32 -0
- package/dist/browser/utils/whois.js +246 -0
- package/dist/browser/websocket/client.d.ts +65 -0
- package/dist/browser/websocket/client.js +313 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/transport/fetch.d.ts +7 -1
- package/dist/transport/fetch.js +58 -76
- package/package.json +34 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ConnectionInfo, ReckerResponse, Timings, SSEEvent, ProgressEvent } from '../types/index.js';
|
|
2
|
+
import { Dispatcher } from 'undici';
|
|
3
|
+
import { type HeaderInfo, type CacheInfo, type RateLimitInfo } from '../utils/header-parser.js';
|
|
4
|
+
import { type LinkHeaderParser } from '../utils/link-header.js';
|
|
5
|
+
import type { Readable } from 'node:stream';
|
|
6
|
+
export declare class HttpResponse<T = unknown> implements ReckerResponse<T> {
|
|
7
|
+
readonly timings?: Timings;
|
|
8
|
+
readonly connection?: ConnectionInfo;
|
|
9
|
+
readonly raw: Response;
|
|
10
|
+
constructor(undiciRawResponse: Response | Dispatcher.ResponseData, options?: {
|
|
11
|
+
timings?: Timings;
|
|
12
|
+
connection?: ConnectionInfo;
|
|
13
|
+
});
|
|
14
|
+
get status(): number;
|
|
15
|
+
get statusText(): string;
|
|
16
|
+
get headers(): Headers;
|
|
17
|
+
get ok(): boolean;
|
|
18
|
+
get url(): string;
|
|
19
|
+
get cache(): CacheInfo;
|
|
20
|
+
get rateLimit(): RateLimitInfo;
|
|
21
|
+
links(): LinkHeaderParser | null;
|
|
22
|
+
get headerInfo(): HeaderInfo;
|
|
23
|
+
json<R = T>(): Promise<R>;
|
|
24
|
+
text(): Promise<string>;
|
|
25
|
+
cleanText(): Promise<string>;
|
|
26
|
+
blob(): Promise<Blob>;
|
|
27
|
+
read(): ReadableStream<Uint8Array> | null;
|
|
28
|
+
toNodeStream(): Readable | null;
|
|
29
|
+
pipe(destination: NodeJS.WritableStream): Promise<void>;
|
|
30
|
+
clone(): ReckerResponse<T>;
|
|
31
|
+
sse(): AsyncGenerator<SSEEvent>;
|
|
32
|
+
download(): AsyncGenerator<ProgressEvent>;
|
|
33
|
+
[Symbol.asyncIterator](): AsyncGenerator<Uint8Array>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { parseSSE } from '../utils/sse.js';
|
|
2
|
+
import { cleanHtml } from '../utils/html-cleaner.js';
|
|
3
|
+
import { webToNodeStream } from '../utils/streaming.js';
|
|
4
|
+
import { parseHeaders } from '../utils/header-parser.js';
|
|
5
|
+
import { parseLinkHeader } from '../utils/link-header.js';
|
|
6
|
+
import { StreamError } from './errors.js';
|
|
7
|
+
export class HttpResponse {
|
|
8
|
+
timings;
|
|
9
|
+
connection;
|
|
10
|
+
raw;
|
|
11
|
+
constructor(undiciRawResponse, options = {}) {
|
|
12
|
+
this.timings = options.timings;
|
|
13
|
+
this.connection = options.connection;
|
|
14
|
+
if (undiciRawResponse instanceof Response) {
|
|
15
|
+
this.raw = undiciRawResponse;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.raw = new Response(undiciRawResponse.body, {
|
|
19
|
+
status: undiciRawResponse.statusCode,
|
|
20
|
+
statusText: String(undiciRawResponse.statusCode),
|
|
21
|
+
headers: undiciRawResponse.headers,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
get status() {
|
|
26
|
+
return this.raw.status;
|
|
27
|
+
}
|
|
28
|
+
get statusText() {
|
|
29
|
+
return this.raw.statusText;
|
|
30
|
+
}
|
|
31
|
+
get headers() {
|
|
32
|
+
return this.raw.headers;
|
|
33
|
+
}
|
|
34
|
+
get ok() {
|
|
35
|
+
return this.raw.ok;
|
|
36
|
+
}
|
|
37
|
+
get url() {
|
|
38
|
+
return this.raw.url;
|
|
39
|
+
}
|
|
40
|
+
get cache() {
|
|
41
|
+
return parseHeaders(this.headers, this.status).cache;
|
|
42
|
+
}
|
|
43
|
+
get rateLimit() {
|
|
44
|
+
return parseHeaders(this.headers, this.status).rateLimit;
|
|
45
|
+
}
|
|
46
|
+
links() {
|
|
47
|
+
return parseLinkHeader(this.headers);
|
|
48
|
+
}
|
|
49
|
+
get headerInfo() {
|
|
50
|
+
return parseHeaders(this.headers, this.status);
|
|
51
|
+
}
|
|
52
|
+
async json() {
|
|
53
|
+
return (await this.raw.json());
|
|
54
|
+
}
|
|
55
|
+
async text() {
|
|
56
|
+
return this.raw.text();
|
|
57
|
+
}
|
|
58
|
+
async cleanText() {
|
|
59
|
+
const rawText = await this.text();
|
|
60
|
+
return cleanHtml(rawText);
|
|
61
|
+
}
|
|
62
|
+
async blob() {
|
|
63
|
+
return this.raw.blob();
|
|
64
|
+
}
|
|
65
|
+
read() {
|
|
66
|
+
return this.raw.body;
|
|
67
|
+
}
|
|
68
|
+
toNodeStream() {
|
|
69
|
+
if (!this.raw.body) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return webToNodeStream(this.raw.body);
|
|
73
|
+
}
|
|
74
|
+
async pipe(destination) {
|
|
75
|
+
const nodeStream = this.toNodeStream();
|
|
76
|
+
if (!nodeStream) {
|
|
77
|
+
throw new StreamError('Response has no body to pipe', {
|
|
78
|
+
streamType: 'response',
|
|
79
|
+
retriable: true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
nodeStream.pipe(destination);
|
|
84
|
+
nodeStream.on('end', resolve);
|
|
85
|
+
nodeStream.on('error', reject);
|
|
86
|
+
destination.on('error', reject);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
clone() {
|
|
90
|
+
return new HttpResponse(this.raw.clone(), {
|
|
91
|
+
timings: this.timings,
|
|
92
|
+
connection: this.connection
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
sse() {
|
|
96
|
+
return parseSSE(this.raw);
|
|
97
|
+
}
|
|
98
|
+
async *download() {
|
|
99
|
+
if (!this.raw.body) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const contentLength = this.headers.get('content-length');
|
|
103
|
+
const total = contentLength ? parseInt(contentLength, 10) : undefined;
|
|
104
|
+
let loaded = 0;
|
|
105
|
+
const startTime = Date.now();
|
|
106
|
+
let lastUpdate = 0;
|
|
107
|
+
let lastLoaded = 0;
|
|
108
|
+
let lastRateUpdate = startTime;
|
|
109
|
+
let smoothedRate = 0;
|
|
110
|
+
const rateSmoothingFactor = 0.3;
|
|
111
|
+
const createProgress = (isFinal) => {
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
const intervalMs = now - lastRateUpdate;
|
|
114
|
+
const bytesInInterval = loaded - lastLoaded;
|
|
115
|
+
if (intervalMs > 0) {
|
|
116
|
+
const instantRate = (bytesInInterval / intervalMs) * 1000;
|
|
117
|
+
smoothedRate = smoothedRate === 0
|
|
118
|
+
? instantRate
|
|
119
|
+
: smoothedRate * (1 - rateSmoothingFactor) + instantRate * rateSmoothingFactor;
|
|
120
|
+
}
|
|
121
|
+
lastLoaded = loaded;
|
|
122
|
+
lastRateUpdate = now;
|
|
123
|
+
let percent;
|
|
124
|
+
if (total) {
|
|
125
|
+
percent = isFinal ? 100 : Math.min((loaded / total) * 100, 99.9);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
loaded,
|
|
129
|
+
transferred: loaded,
|
|
130
|
+
total,
|
|
131
|
+
percent,
|
|
132
|
+
rate: smoothedRate,
|
|
133
|
+
estimated: total && smoothedRate > 0 ? ((total - loaded) / smoothedRate) * 1000 : undefined,
|
|
134
|
+
direction: 'download',
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const reader = this.raw.body.getReader();
|
|
138
|
+
try {
|
|
139
|
+
yield createProgress(false);
|
|
140
|
+
while (true) {
|
|
141
|
+
const { done, value } = await reader.read();
|
|
142
|
+
if (done) {
|
|
143
|
+
yield createProgress(true);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
if (value) {
|
|
147
|
+
loaded += value.byteLength;
|
|
148
|
+
const now = Date.now();
|
|
149
|
+
if (now - lastUpdate > 100) {
|
|
150
|
+
yield createProgress(false);
|
|
151
|
+
lastUpdate = now;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
reader.releaseLock();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async *[Symbol.asyncIterator]() {
|
|
161
|
+
if (!this.raw.body) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const reader = this.raw.body.getReader();
|
|
165
|
+
try {
|
|
166
|
+
while (true) {
|
|
167
|
+
const { done, value } = await reader.read();
|
|
168
|
+
if (done)
|
|
169
|
+
break;
|
|
170
|
+
if (value)
|
|
171
|
+
yield value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
reader.releaseLock();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type HashAlgorithm = 'SHA-256' | 'SHA-384' | 'SHA-512' | 'SHA-1';
|
|
2
|
+
export type HmacAlgorithm = 'SHA-256' | 'SHA-384' | 'SHA-512' | 'SHA-1';
|
|
3
|
+
export declare class BrowserCrypto {
|
|
4
|
+
private encoder;
|
|
5
|
+
hash(algorithm: HashAlgorithm, data: string): Promise<string>;
|
|
6
|
+
hashBuffer(algorithm: HashAlgorithm, data: ArrayBuffer | Uint8Array): Promise<string>;
|
|
7
|
+
hmac(algorithm: HmacAlgorithm, key: string, data: string): Promise<string>;
|
|
8
|
+
hmacBuffer(algorithm: HmacAlgorithm, key: ArrayBuffer | Uint8Array, data: string | ArrayBuffer | Uint8Array): Promise<ArrayBuffer>;
|
|
9
|
+
randomUUID(): string;
|
|
10
|
+
randomBytes(length: number): Uint8Array;
|
|
11
|
+
randomHex(length: number): string;
|
|
12
|
+
bufferToHex(buffer: ArrayBuffer | Uint8Array): string;
|
|
13
|
+
hexToBuffer(hex: string): Uint8Array;
|
|
14
|
+
base64Encode(data: string): string;
|
|
15
|
+
base64Decode(data: string): string;
|
|
16
|
+
base64UrlEncode(data: string): string;
|
|
17
|
+
base64UrlDecode(data: string): string;
|
|
18
|
+
}
|
|
19
|
+
export declare const browserCrypto: BrowserCrypto;
|
|
20
|
+
export declare const sha256: (data: string) => Promise<string>;
|
|
21
|
+
export declare const sha1: (data: string) => Promise<string>;
|
|
22
|
+
export declare const hmacSha256: (key: string, data: string) => Promise<string>;
|
|
23
|
+
export declare const randomUUID: () => string;
|
|
24
|
+
export declare const randomBytes: (length: number) => Uint8Array<ArrayBufferLike>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export class BrowserCrypto {
|
|
2
|
+
encoder = new TextEncoder();
|
|
3
|
+
async hash(algorithm, data) {
|
|
4
|
+
const dataBuffer = this.encoder.encode(data);
|
|
5
|
+
const hashBuffer = await crypto.subtle.digest(algorithm, dataBuffer);
|
|
6
|
+
return this.bufferToHex(hashBuffer);
|
|
7
|
+
}
|
|
8
|
+
async hashBuffer(algorithm, data) {
|
|
9
|
+
const buffer = data instanceof Uint8Array ? data.buffer : data;
|
|
10
|
+
const hashBuffer = await crypto.subtle.digest(algorithm, buffer);
|
|
11
|
+
return this.bufferToHex(hashBuffer);
|
|
12
|
+
}
|
|
13
|
+
async hmac(algorithm, key, data) {
|
|
14
|
+
const keyData = this.encoder.encode(key);
|
|
15
|
+
const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: algorithm }, false, ['sign']);
|
|
16
|
+
const signature = await crypto.subtle.sign('HMAC', cryptoKey, this.encoder.encode(data));
|
|
17
|
+
return this.bufferToHex(signature);
|
|
18
|
+
}
|
|
19
|
+
async hmacBuffer(algorithm, key, data) {
|
|
20
|
+
const keyBuffer = key instanceof Uint8Array ? key.buffer : key;
|
|
21
|
+
const cryptoKey = await crypto.subtle.importKey('raw', keyBuffer, { name: 'HMAC', hash: algorithm }, false, ['sign']);
|
|
22
|
+
let dataBuffer;
|
|
23
|
+
if (typeof data === 'string') {
|
|
24
|
+
dataBuffer = this.encoder.encode(data).buffer;
|
|
25
|
+
}
|
|
26
|
+
else if (data instanceof Uint8Array) {
|
|
27
|
+
dataBuffer = data.buffer;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
dataBuffer = data;
|
|
31
|
+
}
|
|
32
|
+
return crypto.subtle.sign('HMAC', cryptoKey, dataBuffer);
|
|
33
|
+
}
|
|
34
|
+
randomUUID() {
|
|
35
|
+
return crypto.randomUUID();
|
|
36
|
+
}
|
|
37
|
+
randomBytes(length) {
|
|
38
|
+
const bytes = new Uint8Array(length);
|
|
39
|
+
crypto.getRandomValues(bytes);
|
|
40
|
+
return bytes;
|
|
41
|
+
}
|
|
42
|
+
randomHex(length) {
|
|
43
|
+
return this.bufferToHex(this.randomBytes(length));
|
|
44
|
+
}
|
|
45
|
+
bufferToHex(buffer) {
|
|
46
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
47
|
+
return [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
48
|
+
}
|
|
49
|
+
hexToBuffer(hex) {
|
|
50
|
+
const matches = hex.match(/.{1,2}/g) || [];
|
|
51
|
+
return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));
|
|
52
|
+
}
|
|
53
|
+
base64Encode(data) {
|
|
54
|
+
const bytes = this.encoder.encode(data);
|
|
55
|
+
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('');
|
|
56
|
+
return btoa(binString);
|
|
57
|
+
}
|
|
58
|
+
base64Decode(data) {
|
|
59
|
+
const binString = atob(data);
|
|
60
|
+
const bytes = Uint8Array.from(binString, (m) => m.codePointAt(0));
|
|
61
|
+
return new TextDecoder().decode(bytes);
|
|
62
|
+
}
|
|
63
|
+
base64UrlEncode(data) {
|
|
64
|
+
return this.base64Encode(data)
|
|
65
|
+
.replace(/\+/g, '-')
|
|
66
|
+
.replace(/\//g, '_')
|
|
67
|
+
.replace(/=+$/, '');
|
|
68
|
+
}
|
|
69
|
+
base64UrlDecode(data) {
|
|
70
|
+
const padded = data + '='.repeat((4 - (data.length % 4)) % 4);
|
|
71
|
+
const base64 = padded.replace(/-/g, '+').replace(/_/g, '/');
|
|
72
|
+
return this.base64Decode(base64);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export const browserCrypto = new BrowserCrypto();
|
|
76
|
+
export const sha256 = (data) => browserCrypto.hash('SHA-256', data);
|
|
77
|
+
export const sha1 = (data) => browserCrypto.hash('SHA-1', data);
|
|
78
|
+
export const hmacSha256 = (key, data) => browserCrypto.hmac('SHA-256', key, data);
|
|
79
|
+
export const randomUUID = () => browserCrypto.randomUUID();
|
|
80
|
+
export const randomBytes = (length) => browserCrypto.randomBytes(length);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export * from '../core/request-promise.js';
|
|
2
|
+
export * from '../core/errors.js';
|
|
3
|
+
export * from '../core/client.js';
|
|
4
|
+
export * from '../core/request.js';
|
|
5
|
+
export * from '../core/response.js';
|
|
6
|
+
export * from '../transport/fetch.js';
|
|
7
|
+
export * from '../plugins/retry.js';
|
|
8
|
+
export * from '../plugins/rate-limit.js';
|
|
9
|
+
export * from '../plugins/dedup.js';
|
|
10
|
+
export * from '../plugins/logger.js';
|
|
11
|
+
export * from '../plugins/circuit-breaker.js';
|
|
12
|
+
export * from '../plugins/cookie-jar.js';
|
|
13
|
+
export * from '../plugins/xsrf.js';
|
|
14
|
+
export * from '../plugins/graphql.js';
|
|
15
|
+
export * from '../plugins/xml.js';
|
|
16
|
+
export * from '../plugins/server-timing.js';
|
|
17
|
+
export * from '../plugins/jsonrpc.js';
|
|
18
|
+
export * from '../plugins/grpc-web.js';
|
|
19
|
+
export * from '../plugins/soap.js';
|
|
20
|
+
export * from '../plugins/odata.js';
|
|
21
|
+
export * from '../plugins/auth.js';
|
|
22
|
+
export * from '../cache/memory-storage.js';
|
|
23
|
+
export * from '../utils/body.js';
|
|
24
|
+
export * from '../utils/header-parser.js';
|
|
25
|
+
export * from '../utils/link-header.js';
|
|
26
|
+
export * from '../utils/charset.js';
|
|
27
|
+
export * from '../constants/http-status.js';
|
|
28
|
+
export * from './crypto.js';
|
|
29
|
+
export * from './cache.js';
|
|
30
|
+
export * from './recker.js';
|
|
31
|
+
export { Client as Recker } from '../core/client.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export * from '../core/request-promise.js';
|
|
2
|
+
export * from '../core/errors.js';
|
|
3
|
+
export * from '../core/client.js';
|
|
4
|
+
export * from '../core/request.js';
|
|
5
|
+
export * from '../core/response.js';
|
|
6
|
+
export * from '../transport/fetch.js';
|
|
7
|
+
export * from '../plugins/retry.js';
|
|
8
|
+
export * from '../plugins/rate-limit.js';
|
|
9
|
+
export * from '../plugins/dedup.js';
|
|
10
|
+
export * from '../plugins/logger.js';
|
|
11
|
+
export * from '../plugins/circuit-breaker.js';
|
|
12
|
+
export * from '../plugins/cookie-jar.js';
|
|
13
|
+
export * from '../plugins/xsrf.js';
|
|
14
|
+
export * from '../plugins/graphql.js';
|
|
15
|
+
export * from '../plugins/xml.js';
|
|
16
|
+
export * from '../plugins/server-timing.js';
|
|
17
|
+
export * from '../plugins/jsonrpc.js';
|
|
18
|
+
export * from '../plugins/grpc-web.js';
|
|
19
|
+
export * from '../plugins/soap.js';
|
|
20
|
+
export * from '../plugins/odata.js';
|
|
21
|
+
export * from '../plugins/auth.js';
|
|
22
|
+
export * from '../cache/memory-storage.js';
|
|
23
|
+
export * from '../utils/body.js';
|
|
24
|
+
export * from '../utils/header-parser.js';
|
|
25
|
+
export * from '../utils/link-header.js';
|
|
26
|
+
export * from '../utils/charset.js';
|
|
27
|
+
export * from '../constants/http-status.js';
|
|
28
|
+
export * from './crypto.js';
|
|
29
|
+
export * from './cache.js';
|
|
30
|
+
export * from './recker.js';
|
|
31
|
+
export { Client as Recker } from '../core/client.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
export interface ApiKeyAuthOptions {
|
|
3
|
+
key: string | (() => string | Promise<string>);
|
|
4
|
+
in?: 'header' | 'query';
|
|
5
|
+
name?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function apiKeyAuth(options: ApiKeyAuthOptions): Middleware;
|
|
8
|
+
export declare function apiKeyAuthPlugin(options: ApiKeyAuthOptions): Plugin;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function apiKeyAuth(options) {
|
|
2
|
+
const location = options.in ?? 'header';
|
|
3
|
+
const name = options.name ?? 'X-API-Key';
|
|
4
|
+
return async (req, next) => {
|
|
5
|
+
const key = typeof options.key === 'function'
|
|
6
|
+
? await options.key()
|
|
7
|
+
: options.key;
|
|
8
|
+
if (location === 'header') {
|
|
9
|
+
const newReq = req.withHeader(name, key);
|
|
10
|
+
return next(newReq);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
const url = new URL(req.url);
|
|
14
|
+
url.searchParams.set(name, key);
|
|
15
|
+
const newReq = {
|
|
16
|
+
...req,
|
|
17
|
+
url: url.toString(),
|
|
18
|
+
};
|
|
19
|
+
return next(newReq);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function apiKeyAuthPlugin(options) {
|
|
24
|
+
return (client) => {
|
|
25
|
+
client.use(apiKeyAuth(options));
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
import { OIDCTokens } from './oidc.js';
|
|
3
|
+
export interface Auth0Options {
|
|
4
|
+
domain: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret?: string;
|
|
7
|
+
audience?: string;
|
|
8
|
+
scopes?: string[];
|
|
9
|
+
accessToken?: string | (() => string | Promise<string>);
|
|
10
|
+
refreshToken?: string;
|
|
11
|
+
tokenStorage?: {
|
|
12
|
+
get: () => Promise<OIDCTokens | null>;
|
|
13
|
+
set: (tokens: OIDCTokens) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
organization?: string;
|
|
16
|
+
connection?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function generateAuth0AuthUrl(options: Auth0Options & {
|
|
19
|
+
redirectUri: string;
|
|
20
|
+
state?: string;
|
|
21
|
+
usePKCE?: boolean;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
url: string;
|
|
24
|
+
codeVerifier?: string;
|
|
25
|
+
}>;
|
|
26
|
+
export declare function exchangeAuth0Code(options: Auth0Options & {
|
|
27
|
+
code: string;
|
|
28
|
+
redirectUri: string;
|
|
29
|
+
codeVerifier?: string;
|
|
30
|
+
}): Promise<OIDCTokens>;
|
|
31
|
+
export declare function getAuth0UserInfo(domain: string, accessToken: string): Promise<Record<string, unknown>>;
|
|
32
|
+
export declare function auth0(options: Auth0Options): Middleware;
|
|
33
|
+
export declare function auth0Plugin(options: Auth0Options): Plugin;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { oidc, generatePKCE } from './oidc.js';
|
|
2
|
+
export async function generateAuth0AuthUrl(options) {
|
|
3
|
+
const issuer = `https://${options.domain}`;
|
|
4
|
+
const pkce = options.usePKCE ? generatePKCE() : undefined;
|
|
5
|
+
const params = new URLSearchParams({
|
|
6
|
+
response_type: 'code',
|
|
7
|
+
client_id: options.clientId,
|
|
8
|
+
redirect_uri: options.redirectUri,
|
|
9
|
+
scope: (options.scopes || ['openid', 'profile', 'email']).join(' '),
|
|
10
|
+
});
|
|
11
|
+
if (options.audience) {
|
|
12
|
+
params.set('audience', options.audience);
|
|
13
|
+
}
|
|
14
|
+
if (options.state) {
|
|
15
|
+
params.set('state', options.state);
|
|
16
|
+
}
|
|
17
|
+
if (options.organization) {
|
|
18
|
+
params.set('organization', options.organization);
|
|
19
|
+
}
|
|
20
|
+
if (options.connection) {
|
|
21
|
+
params.set('connection', options.connection);
|
|
22
|
+
}
|
|
23
|
+
if (pkce) {
|
|
24
|
+
params.set('code_challenge', pkce.codeChallenge);
|
|
25
|
+
params.set('code_challenge_method', 'S256');
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
url: `${issuer}/authorize?${params.toString()}`,
|
|
29
|
+
codeVerifier: pkce?.codeVerifier,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function exchangeAuth0Code(options) {
|
|
33
|
+
const tokenUrl = `https://${options.domain}/oauth/token`;
|
|
34
|
+
const params = {
|
|
35
|
+
grant_type: 'authorization_code',
|
|
36
|
+
client_id: options.clientId,
|
|
37
|
+
code: options.code,
|
|
38
|
+
redirect_uri: options.redirectUri,
|
|
39
|
+
};
|
|
40
|
+
if (options.clientSecret) {
|
|
41
|
+
params.client_secret = options.clientSecret;
|
|
42
|
+
}
|
|
43
|
+
if (options.codeVerifier) {
|
|
44
|
+
params.code_verifier = options.codeVerifier;
|
|
45
|
+
}
|
|
46
|
+
const response = await fetch(tokenUrl, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(params),
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const error = await response.text();
|
|
55
|
+
throw new Error(`Auth0 token exchange failed: ${error}`);
|
|
56
|
+
}
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
return {
|
|
59
|
+
accessToken: data.access_token,
|
|
60
|
+
refreshToken: data.refresh_token,
|
|
61
|
+
idToken: data.id_token,
|
|
62
|
+
expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
63
|
+
tokenType: data.token_type || 'Bearer',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export async function getAuth0UserInfo(domain, accessToken) {
|
|
67
|
+
const response = await fetch(`https://${domain}/userinfo`, {
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${accessToken}`,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`Failed to get user info: ${response.status}`);
|
|
74
|
+
}
|
|
75
|
+
return response.json();
|
|
76
|
+
}
|
|
77
|
+
export function auth0(options) {
|
|
78
|
+
const issuer = `https://${options.domain}`;
|
|
79
|
+
return oidc({
|
|
80
|
+
issuer,
|
|
81
|
+
clientId: options.clientId,
|
|
82
|
+
clientSecret: options.clientSecret,
|
|
83
|
+
scopes: options.scopes || ['openid', 'profile', 'email'],
|
|
84
|
+
accessToken: options.accessToken,
|
|
85
|
+
refreshToken: options.refreshToken,
|
|
86
|
+
tokenStorage: options.tokenStorage,
|
|
87
|
+
audience: options.audience,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export function auth0Plugin(options) {
|
|
91
|
+
return (client) => {
|
|
92
|
+
client.use(auth0(options));
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
export interface AWSSignatureV4Options {
|
|
3
|
+
accessKeyId: string;
|
|
4
|
+
secretAccessKey: string;
|
|
5
|
+
region: string;
|
|
6
|
+
service: string;
|
|
7
|
+
sessionToken?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function awsSignatureV4(options: AWSSignatureV4Options): Middleware;
|
|
10
|
+
export declare function awsSignatureV4Plugin(options: AWSSignatureV4Options): Plugin;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createHash, createHmac } from 'node:crypto';
|
|
2
|
+
function sha256(str) {
|
|
3
|
+
return createHash('sha256').update(str).digest('hex');
|
|
4
|
+
}
|
|
5
|
+
export function awsSignatureV4(options) {
|
|
6
|
+
return async (req, next) => {
|
|
7
|
+
const url = new URL(req.url);
|
|
8
|
+
const host = url.host;
|
|
9
|
+
const pathname = url.pathname;
|
|
10
|
+
const queryString = url.search.slice(1);
|
|
11
|
+
const now = new Date();
|
|
12
|
+
const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
|
|
13
|
+
const dateStamp = amzDate.slice(0, 8);
|
|
14
|
+
const method = req.method;
|
|
15
|
+
const canonicalUri = pathname || '/';
|
|
16
|
+
const canonicalQueryString = queryString
|
|
17
|
+
.split('&')
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.sort()
|
|
20
|
+
.join('&');
|
|
21
|
+
let payload = '';
|
|
22
|
+
if (req.body) {
|
|
23
|
+
if (typeof req.body === 'string') {
|
|
24
|
+
payload = req.body;
|
|
25
|
+
}
|
|
26
|
+
else if (req.body instanceof ArrayBuffer) {
|
|
27
|
+
payload = Buffer.from(req.body).toString();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const payloadHash = sha256(payload);
|
|
31
|
+
const headers = {
|
|
32
|
+
host,
|
|
33
|
+
'x-amz-date': amzDate,
|
|
34
|
+
'x-amz-content-sha256': payloadHash,
|
|
35
|
+
};
|
|
36
|
+
if (options.sessionToken) {
|
|
37
|
+
headers['x-amz-security-token'] = options.sessionToken;
|
|
38
|
+
}
|
|
39
|
+
req.headers.forEach((value, key) => {
|
|
40
|
+
headers[key.toLowerCase()] = value;
|
|
41
|
+
});
|
|
42
|
+
const signedHeaders = Object.keys(headers).sort().join(';');
|
|
43
|
+
const canonicalHeaders = Object.keys(headers)
|
|
44
|
+
.sort()
|
|
45
|
+
.map(key => `${key}:${headers[key].trim()}\n`)
|
|
46
|
+
.join('');
|
|
47
|
+
const canonicalRequest = [
|
|
48
|
+
method,
|
|
49
|
+
canonicalUri,
|
|
50
|
+
canonicalQueryString,
|
|
51
|
+
canonicalHeaders,
|
|
52
|
+
signedHeaders,
|
|
53
|
+
payloadHash,
|
|
54
|
+
].join('\n');
|
|
55
|
+
const algorithm = 'AWS4-HMAC-SHA256';
|
|
56
|
+
const credentialScope = `${dateStamp}/${options.region}/${options.service}/aws4_request`;
|
|
57
|
+
const stringToSign = [
|
|
58
|
+
algorithm,
|
|
59
|
+
amzDate,
|
|
60
|
+
credentialScope,
|
|
61
|
+
sha256(canonicalRequest),
|
|
62
|
+
].join('\n');
|
|
63
|
+
const getSignatureKey = (key, dateStamp, regionName, serviceName) => {
|
|
64
|
+
const kDate = createHmac('sha256', `AWS4${key}`).update(dateStamp).digest();
|
|
65
|
+
const kRegion = createHmac('sha256', kDate).update(regionName).digest();
|
|
66
|
+
const kService = createHmac('sha256', kRegion).update(serviceName).digest();
|
|
67
|
+
const kSigning = createHmac('sha256', kService).update('aws4_request').digest();
|
|
68
|
+
return kSigning;
|
|
69
|
+
};
|
|
70
|
+
const signingKey = getSignatureKey(options.secretAccessKey, dateStamp, options.region, options.service);
|
|
71
|
+
const signature = createHmac('sha256', signingKey)
|
|
72
|
+
.update(stringToSign)
|
|
73
|
+
.digest('hex');
|
|
74
|
+
const authorizationHeader = `${algorithm} Credential=${options.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
75
|
+
let newReq = req.withHeader('Authorization', authorizationHeader);
|
|
76
|
+
newReq = newReq.withHeader('x-amz-date', amzDate);
|
|
77
|
+
newReq = newReq.withHeader('x-amz-content-sha256', payloadHash);
|
|
78
|
+
if (options.sessionToken) {
|
|
79
|
+
newReq = newReq.withHeader('x-amz-security-token', options.sessionToken);
|
|
80
|
+
}
|
|
81
|
+
return next(newReq);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function awsSignatureV4Plugin(options) {
|
|
85
|
+
return (client) => {
|
|
86
|
+
client.use(awsSignatureV4(options));
|
|
87
|
+
};
|
|
88
|
+
}
|