recker 1.0.26 → 1.0.27-next.1cb21f8
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 +357 -0
- package/dist/browser/scrape/types.d.ts +108 -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 +143 -3
- package/dist/cli/tui/shell.d.ts +1 -0
- package/dist/cli/tui/shell.js +157 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/scrape/extractors.js +2 -1
- package/dist/scrape/types.d.ts +2 -1
- package/dist/seo/analyzer.d.ts +42 -0
- package/dist/seo/analyzer.js +715 -0
- package/dist/seo/index.d.ts +5 -0
- package/dist/seo/index.js +2 -0
- package/dist/seo/rules/accessibility.d.ts +2 -0
- package/dist/seo/rules/accessibility.js +128 -0
- package/dist/seo/rules/content.d.ts +2 -0
- package/dist/seo/rules/content.js +236 -0
- package/dist/seo/rules/images.d.ts +2 -0
- package/dist/seo/rules/images.js +180 -0
- package/dist/seo/rules/index.d.ts +20 -0
- package/dist/seo/rules/index.js +72 -0
- package/dist/seo/rules/links.d.ts +2 -0
- package/dist/seo/rules/links.js +150 -0
- package/dist/seo/rules/meta.d.ts +2 -0
- package/dist/seo/rules/meta.js +523 -0
- package/dist/seo/rules/mobile.d.ts +2 -0
- package/dist/seo/rules/mobile.js +71 -0
- package/dist/seo/rules/performance.d.ts +2 -0
- package/dist/seo/rules/performance.js +246 -0
- package/dist/seo/rules/schema.d.ts +2 -0
- package/dist/seo/rules/schema.js +54 -0
- package/dist/seo/rules/security.d.ts +2 -0
- package/dist/seo/rules/security.js +147 -0
- package/dist/seo/rules/structural.d.ts +2 -0
- package/dist/seo/rules/structural.js +155 -0
- package/dist/seo/rules/technical.d.ts +2 -0
- package/dist/seo/rules/technical.js +223 -0
- package/dist/seo/rules/thresholds.d.ts +196 -0
- package/dist/seo/rules/thresholds.js +118 -0
- package/dist/seo/rules/types.d.ts +191 -0
- package/dist/seo/rules/types.js +11 -0
- package/dist/seo/types.d.ts +160 -0
- package/dist/seo/types.js +1 -0
- package/dist/transport/fetch.d.ts +7 -1
- package/dist/transport/fetch.js +58 -76
- package/dist/utils/columns.d.ts +14 -0
- package/dist/utils/columns.js +69 -0
- package/package.json +34 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface CacheEntry<T = unknown> {
|
|
2
|
+
key: string;
|
|
3
|
+
value: T;
|
|
4
|
+
createdAt: number;
|
|
5
|
+
expiresAt?: number;
|
|
6
|
+
etag?: string;
|
|
7
|
+
lastModified?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BrowserCacheOptions {
|
|
10
|
+
dbName?: string;
|
|
11
|
+
storeName?: string;
|
|
12
|
+
defaultTTL?: number;
|
|
13
|
+
maxEntries?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class IndexedDBStorage {
|
|
16
|
+
private dbName;
|
|
17
|
+
private storeName;
|
|
18
|
+
private defaultTTL;
|
|
19
|
+
private maxEntries;
|
|
20
|
+
private db;
|
|
21
|
+
private initPromise;
|
|
22
|
+
constructor(options?: BrowserCacheOptions);
|
|
23
|
+
init(): Promise<void>;
|
|
24
|
+
get<T = unknown>(key: string): Promise<CacheEntry<T> | null>;
|
|
25
|
+
set<T = unknown>(key: string, value: T, ttl?: number, metadata?: {
|
|
26
|
+
etag?: string;
|
|
27
|
+
lastModified?: string;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
delete(key: string): Promise<boolean>;
|
|
30
|
+
has(key: string): Promise<boolean>;
|
|
31
|
+
clear(): Promise<void>;
|
|
32
|
+
keys(): Promise<string[]>;
|
|
33
|
+
size(): Promise<number>;
|
|
34
|
+
cleanup(): Promise<number>;
|
|
35
|
+
private enforceMaxEntries;
|
|
36
|
+
close(): void;
|
|
37
|
+
destroy(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export declare function isIndexedDBAvailable(): boolean;
|
|
40
|
+
export declare function getBrowserCacheStorage(options?: BrowserCacheOptions): IndexedDBStorage | null;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
export class IndexedDBStorage {
|
|
2
|
+
dbName;
|
|
3
|
+
storeName;
|
|
4
|
+
defaultTTL;
|
|
5
|
+
maxEntries;
|
|
6
|
+
db = null;
|
|
7
|
+
initPromise = null;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.dbName = options.dbName ?? 'recker-cache';
|
|
10
|
+
this.storeName = options.storeName ?? 'responses';
|
|
11
|
+
this.defaultTTL = options.defaultTTL ?? 5 * 60 * 1000;
|
|
12
|
+
this.maxEntries = options.maxEntries ?? 1000;
|
|
13
|
+
}
|
|
14
|
+
async init() {
|
|
15
|
+
if (this.db)
|
|
16
|
+
return;
|
|
17
|
+
if (this.initPromise)
|
|
18
|
+
return this.initPromise;
|
|
19
|
+
this.initPromise = new Promise((resolve, reject) => {
|
|
20
|
+
const request = indexedDB.open(this.dbName, 1);
|
|
21
|
+
request.onerror = () => {
|
|
22
|
+
reject(new Error(`Failed to open IndexedDB: ${request.error?.message}`));
|
|
23
|
+
};
|
|
24
|
+
request.onsuccess = () => {
|
|
25
|
+
this.db = request.result;
|
|
26
|
+
resolve();
|
|
27
|
+
};
|
|
28
|
+
request.onupgradeneeded = (event) => {
|
|
29
|
+
const db = event.target.result;
|
|
30
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
31
|
+
const store = db.createObjectStore(this.storeName, { keyPath: 'key' });
|
|
32
|
+
store.createIndex('expiresAt', 'expiresAt', { unique: false });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
return this.initPromise;
|
|
37
|
+
}
|
|
38
|
+
async get(key) {
|
|
39
|
+
await this.init();
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const transaction = this.db.transaction(this.storeName, 'readonly');
|
|
42
|
+
const store = transaction.objectStore(this.storeName);
|
|
43
|
+
const request = store.get(key);
|
|
44
|
+
request.onerror = () => reject(request.error);
|
|
45
|
+
request.onsuccess = () => {
|
|
46
|
+
const entry = request.result;
|
|
47
|
+
if (!entry) {
|
|
48
|
+
resolve(null);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (entry.expiresAt && entry.expiresAt < Date.now()) {
|
|
52
|
+
this.delete(key).catch(() => { });
|
|
53
|
+
resolve(null);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
resolve(entry);
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async set(key, value, ttl, metadata) {
|
|
61
|
+
await this.init();
|
|
62
|
+
const entry = {
|
|
63
|
+
key,
|
|
64
|
+
value,
|
|
65
|
+
createdAt: Date.now(),
|
|
66
|
+
expiresAt: ttl !== undefined ? Date.now() + ttl : undefined,
|
|
67
|
+
etag: metadata?.etag,
|
|
68
|
+
lastModified: metadata?.lastModified,
|
|
69
|
+
};
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
const transaction = this.db.transaction(this.storeName, 'readwrite');
|
|
72
|
+
const store = transaction.objectStore(this.storeName);
|
|
73
|
+
const request = store.put(entry);
|
|
74
|
+
request.onerror = () => reject(request.error);
|
|
75
|
+
request.onsuccess = () => resolve();
|
|
76
|
+
transaction.oncomplete = () => {
|
|
77
|
+
this.enforceMaxEntries().catch(() => { });
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async delete(key) {
|
|
82
|
+
await this.init();
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const transaction = this.db.transaction(this.storeName, 'readwrite');
|
|
85
|
+
const store = transaction.objectStore(this.storeName);
|
|
86
|
+
const request = store.delete(key);
|
|
87
|
+
request.onerror = () => reject(request.error);
|
|
88
|
+
request.onsuccess = () => resolve(true);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async has(key) {
|
|
92
|
+
const entry = await this.get(key);
|
|
93
|
+
return entry !== null;
|
|
94
|
+
}
|
|
95
|
+
async clear() {
|
|
96
|
+
await this.init();
|
|
97
|
+
return new Promise((resolve, reject) => {
|
|
98
|
+
const transaction = this.db.transaction(this.storeName, 'readwrite');
|
|
99
|
+
const store = transaction.objectStore(this.storeName);
|
|
100
|
+
const request = store.clear();
|
|
101
|
+
request.onerror = () => reject(request.error);
|
|
102
|
+
request.onsuccess = () => resolve();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async keys() {
|
|
106
|
+
await this.init();
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
const transaction = this.db.transaction(this.storeName, 'readonly');
|
|
109
|
+
const store = transaction.objectStore(this.storeName);
|
|
110
|
+
const request = store.getAllKeys();
|
|
111
|
+
request.onerror = () => reject(request.error);
|
|
112
|
+
request.onsuccess = () => resolve(request.result);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async size() {
|
|
116
|
+
await this.init();
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const transaction = this.db.transaction(this.storeName, 'readonly');
|
|
119
|
+
const store = transaction.objectStore(this.storeName);
|
|
120
|
+
const request = store.count();
|
|
121
|
+
request.onerror = () => reject(request.error);
|
|
122
|
+
request.onsuccess = () => resolve(request.result);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
async cleanup() {
|
|
126
|
+
await this.init();
|
|
127
|
+
const now = Date.now();
|
|
128
|
+
let removed = 0;
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const transaction = this.db.transaction(this.storeName, 'readwrite');
|
|
131
|
+
const store = transaction.objectStore(this.storeName);
|
|
132
|
+
const index = store.index('expiresAt');
|
|
133
|
+
const range = IDBKeyRange.upperBound(now);
|
|
134
|
+
const request = index.openCursor(range);
|
|
135
|
+
request.onerror = () => reject(request.error);
|
|
136
|
+
request.onsuccess = (event) => {
|
|
137
|
+
const cursor = event.target.result;
|
|
138
|
+
if (cursor) {
|
|
139
|
+
cursor.delete();
|
|
140
|
+
removed++;
|
|
141
|
+
cursor.continue();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
transaction.oncomplete = () => resolve(removed);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async enforceMaxEntries() {
|
|
148
|
+
const currentSize = await this.size();
|
|
149
|
+
if (currentSize <= this.maxEntries)
|
|
150
|
+
return;
|
|
151
|
+
const toRemove = currentSize - this.maxEntries;
|
|
152
|
+
return new Promise((resolve, reject) => {
|
|
153
|
+
const transaction = this.db.transaction(this.storeName, 'readwrite');
|
|
154
|
+
const store = transaction.objectStore(this.storeName);
|
|
155
|
+
const index = store.index('expiresAt');
|
|
156
|
+
let removed = 0;
|
|
157
|
+
const request = index.openCursor();
|
|
158
|
+
request.onerror = () => reject(request.error);
|
|
159
|
+
request.onsuccess = (event) => {
|
|
160
|
+
const cursor = event.target.result;
|
|
161
|
+
if (cursor && removed < toRemove) {
|
|
162
|
+
cursor.delete();
|
|
163
|
+
removed++;
|
|
164
|
+
cursor.continue();
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
transaction.oncomplete = () => resolve();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
close() {
|
|
171
|
+
if (this.db) {
|
|
172
|
+
this.db.close();
|
|
173
|
+
this.db = null;
|
|
174
|
+
this.initPromise = null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async destroy() {
|
|
178
|
+
this.close();
|
|
179
|
+
return new Promise((resolve, reject) => {
|
|
180
|
+
const request = indexedDB.deleteDatabase(this.dbName);
|
|
181
|
+
request.onerror = () => reject(request.error);
|
|
182
|
+
request.onsuccess = () => resolve();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
export function isIndexedDBAvailable() {
|
|
187
|
+
try {
|
|
188
|
+
return typeof indexedDB !== 'undefined' && indexedDB !== null;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export function getBrowserCacheStorage(options) {
|
|
195
|
+
if (isIndexedDBAvailable()) {
|
|
196
|
+
return new IndexedDBStorage(options);
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
@@ -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,26 @@
|
|
|
1
|
+
import { Client, type ExtendedClientOptions } from '../core/client.js';
|
|
2
|
+
import { type RequestPromise } from '../core/request-promise.js';
|
|
3
|
+
import type { RequestOptions } from '../types/index.js';
|
|
4
|
+
export declare function get(url: string, options?: RequestOptions): RequestPromise;
|
|
5
|
+
export declare function post(url: string, options?: RequestOptions): RequestPromise;
|
|
6
|
+
export declare function put(url: string, options?: RequestOptions): RequestPromise;
|
|
7
|
+
export declare function patch(url: string, options?: RequestOptions): RequestPromise;
|
|
8
|
+
export declare function del(url: string, options?: RequestOptions): RequestPromise;
|
|
9
|
+
export declare function head(url: string, options?: RequestOptions): RequestPromise;
|
|
10
|
+
export declare function options(url: string, options?: RequestOptions): RequestPromise;
|
|
11
|
+
export declare function ws(url: string, protocols?: string | string[]): WebSocket;
|
|
12
|
+
export declare const recker: {
|
|
13
|
+
get: typeof get;
|
|
14
|
+
post: typeof post;
|
|
15
|
+
put: typeof put;
|
|
16
|
+
patch: typeof patch;
|
|
17
|
+
delete: typeof del;
|
|
18
|
+
head: typeof head;
|
|
19
|
+
options: typeof options;
|
|
20
|
+
ws: typeof ws;
|
|
21
|
+
client: (opts?: ExtendedClientOptions) => Client;
|
|
22
|
+
reset: () => void;
|
|
23
|
+
isBrowser: true;
|
|
24
|
+
unavailable: readonly ["whois", "whoisAvailable", "dns", "dnsSecurity", "dnsClient", "whoisClient", "ai", "aiClient"];
|
|
25
|
+
};
|
|
26
|
+
export default recker;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createClient } from '../core/client.js';
|
|
2
|
+
import { FetchTransport } from '../transport/fetch.js';
|
|
3
|
+
let _defaultClient = null;
|
|
4
|
+
function getDefaultClient() {
|
|
5
|
+
if (!_defaultClient) {
|
|
6
|
+
_defaultClient = createClient({
|
|
7
|
+
transport: new FetchTransport(),
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
return _defaultClient;
|
|
11
|
+
}
|
|
12
|
+
export function get(url, options) {
|
|
13
|
+
return getDefaultClient().get(url, options);
|
|
14
|
+
}
|
|
15
|
+
export function post(url, options) {
|
|
16
|
+
return getDefaultClient().post(url, options);
|
|
17
|
+
}
|
|
18
|
+
export function put(url, options) {
|
|
19
|
+
return getDefaultClient().put(url, options);
|
|
20
|
+
}
|
|
21
|
+
export function patch(url, options) {
|
|
22
|
+
return getDefaultClient().patch(url, options);
|
|
23
|
+
}
|
|
24
|
+
export function del(url, options) {
|
|
25
|
+
return getDefaultClient().delete(url, options);
|
|
26
|
+
}
|
|
27
|
+
export function head(url, options) {
|
|
28
|
+
return getDefaultClient().head(url, options);
|
|
29
|
+
}
|
|
30
|
+
export function options(url, options) {
|
|
31
|
+
return getDefaultClient().options(url, options);
|
|
32
|
+
}
|
|
33
|
+
export function ws(url, protocols) {
|
|
34
|
+
return new WebSocket(url, protocols);
|
|
35
|
+
}
|
|
36
|
+
export const recker = {
|
|
37
|
+
get,
|
|
38
|
+
post,
|
|
39
|
+
put,
|
|
40
|
+
patch,
|
|
41
|
+
delete: del,
|
|
42
|
+
head,
|
|
43
|
+
options,
|
|
44
|
+
ws,
|
|
45
|
+
client: (opts) => createClient({ ...opts, transport: new FetchTransport() }),
|
|
46
|
+
reset: () => {
|
|
47
|
+
_defaultClient = null;
|
|
48
|
+
},
|
|
49
|
+
isBrowser: true,
|
|
50
|
+
unavailable: [
|
|
51
|
+
'whois',
|
|
52
|
+
'whoisAvailable',
|
|
53
|
+
'dns',
|
|
54
|
+
'dnsSecurity',
|
|
55
|
+
'dnsClient',
|
|
56
|
+
'whoisClient',
|
|
57
|
+
'ai',
|
|
58
|
+
'aiClient',
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
export default recker;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CacheEntry, CacheStorage } from '../types/index.js';
|
|
2
|
+
export declare class FileStorage implements CacheStorage {
|
|
3
|
+
private dir;
|
|
4
|
+
constructor(baseDir?: string);
|
|
5
|
+
private getHash;
|
|
6
|
+
private getPath;
|
|
7
|
+
private ensureDir;
|
|
8
|
+
get(key: string): Promise<CacheEntry | undefined>;
|
|
9
|
+
set(key: string, entry: CacheEntry, ttl?: number): Promise<void>;
|
|
10
|
+
delete(key: string): Promise<void>;
|
|
11
|
+
clear(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile, unlink, rm } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
export class FileStorage {
|
|
6
|
+
dir;
|
|
7
|
+
constructor(baseDir = '.recker/cache') {
|
|
8
|
+
this.dir = baseDir;
|
|
9
|
+
}
|
|
10
|
+
getHash(key) {
|
|
11
|
+
return createHash('md5').update(key).digest('hex');
|
|
12
|
+
}
|
|
13
|
+
getPath(key) {
|
|
14
|
+
return join(this.dir, `${this.getHash(key)}.json`);
|
|
15
|
+
}
|
|
16
|
+
async ensureDir() {
|
|
17
|
+
if (!existsSync(this.dir)) {
|
|
18
|
+
await mkdir(this.dir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async get(key) {
|
|
22
|
+
try {
|
|
23
|
+
const path = this.getPath(key);
|
|
24
|
+
if (!existsSync(path))
|
|
25
|
+
return undefined;
|
|
26
|
+
const content = await readFile(path, 'utf-8');
|
|
27
|
+
const data = JSON.parse(content);
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async set(key, entry, ttl) {
|
|
35
|
+
await this.ensureDir();
|
|
36
|
+
const path = this.getPath(key);
|
|
37
|
+
await writeFile(path, JSON.stringify(entry), 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
async delete(key) {
|
|
40
|
+
const path = this.getPath(key);
|
|
41
|
+
if (existsSync(path)) {
|
|
42
|
+
await unlink(path);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async clear() {
|
|
46
|
+
if (existsSync(this.dir)) {
|
|
47
|
+
await rm(this.dir, { recursive: true, force: true });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function getEffectiveTotalMemoryBytes(): number;
|
|
2
|
+
export interface ResolvedMemoryLimit {
|
|
3
|
+
maxMemoryBytes: number;
|
|
4
|
+
derivedFromPercent: boolean;
|
|
5
|
+
effectiveTotal: number;
|
|
6
|
+
heapLimit: number;
|
|
7
|
+
inferredPercent: number | null;
|
|
8
|
+
}
|
|
9
|
+
export interface MemoryLimitOptions {
|
|
10
|
+
maxMemoryBytes?: number;
|
|
11
|
+
maxMemoryPercent?: number;
|
|
12
|
+
safetyPercent?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveCacheMemoryLimit(options?: MemoryLimitOptions): ResolvedMemoryLimit;
|
|
15
|
+
export declare function formatBytes(bytes: number): string;
|
|
16
|
+
export declare function getHeapStats(): {
|
|
17
|
+
heapUsed: number;
|
|
18
|
+
heapLimit: number;
|
|
19
|
+
heapRatio: number;
|
|
20
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import v8 from 'node:v8';
|
|
4
|
+
const DEFAULT_TOTAL_PERCENT = 0.5;
|
|
5
|
+
const DEFAULT_HEAP_PERCENT = 0.6;
|
|
6
|
+
function readCgroupLimit() {
|
|
7
|
+
const candidates = [
|
|
8
|
+
'/sys/fs/cgroup/memory.max',
|
|
9
|
+
'/sys/fs/cgroup/memory/memory.limit_in_bytes',
|
|
10
|
+
];
|
|
11
|
+
for (const file of candidates) {
|
|
12
|
+
try {
|
|
13
|
+
if (fs.existsSync(file)) {
|
|
14
|
+
const raw = fs.readFileSync(file, 'utf8').trim();
|
|
15
|
+
if (!raw || raw === 'max')
|
|
16
|
+
continue;
|
|
17
|
+
const value = Number.parseInt(raw, 10);
|
|
18
|
+
if (Number.isFinite(value) && value > 0) {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
export function getEffectiveTotalMemoryBytes() {
|
|
29
|
+
const cgroupLimit = readCgroupLimit();
|
|
30
|
+
if (cgroupLimit && Number.isFinite(cgroupLimit) && cgroupLimit > 0) {
|
|
31
|
+
return cgroupLimit;
|
|
32
|
+
}
|
|
33
|
+
return os.totalmem();
|
|
34
|
+
}
|
|
35
|
+
export function resolveCacheMemoryLimit(options = {}) {
|
|
36
|
+
const { maxMemoryBytes, maxMemoryPercent, safetyPercent } = options;
|
|
37
|
+
const heapStats = v8.getHeapStatistics();
|
|
38
|
+
const heapLimit = heapStats?.heap_size_limit ?? 0;
|
|
39
|
+
const effectiveTotal = getEffectiveTotalMemoryBytes();
|
|
40
|
+
let resolvedBytes = 0;
|
|
41
|
+
let derivedFromPercent = false;
|
|
42
|
+
if (typeof maxMemoryBytes === 'number' && maxMemoryBytes > 0) {
|
|
43
|
+
resolvedBytes = maxMemoryBytes;
|
|
44
|
+
}
|
|
45
|
+
else if (typeof maxMemoryPercent === 'number' && maxMemoryPercent > 0) {
|
|
46
|
+
const percent = Math.max(0, Math.min(maxMemoryPercent, 1));
|
|
47
|
+
resolvedBytes = Math.floor(effectiveTotal * percent);
|
|
48
|
+
derivedFromPercent = true;
|
|
49
|
+
}
|
|
50
|
+
const safeTotalPercent = typeof safetyPercent === 'number' && safetyPercent > 0 && safetyPercent <= 1
|
|
51
|
+
? safetyPercent
|
|
52
|
+
: DEFAULT_TOTAL_PERCENT;
|
|
53
|
+
const totalCap = Math.floor(effectiveTotal * safeTotalPercent);
|
|
54
|
+
if (resolvedBytes === 0 || totalCap < resolvedBytes) {
|
|
55
|
+
resolvedBytes = totalCap;
|
|
56
|
+
derivedFromPercent = derivedFromPercent || (maxMemoryPercent ?? 0) > 0;
|
|
57
|
+
}
|
|
58
|
+
if (heapLimit > 0) {
|
|
59
|
+
const heapCap = Math.floor(heapLimit * DEFAULT_HEAP_PERCENT);
|
|
60
|
+
if (resolvedBytes === 0 || heapCap < resolvedBytes) {
|
|
61
|
+
resolvedBytes = heapCap;
|
|
62
|
+
derivedFromPercent = derivedFromPercent || (maxMemoryPercent ?? 0) > 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!Number.isFinite(resolvedBytes) || resolvedBytes <= 0) {
|
|
66
|
+
resolvedBytes = Math.floor(effectiveTotal * DEFAULT_TOTAL_PERCENT);
|
|
67
|
+
derivedFromPercent = true;
|
|
68
|
+
}
|
|
69
|
+
const inferredPercent = effectiveTotal > 0 ? resolvedBytes / effectiveTotal : null;
|
|
70
|
+
return {
|
|
71
|
+
maxMemoryBytes: resolvedBytes,
|
|
72
|
+
derivedFromPercent,
|
|
73
|
+
effectiveTotal,
|
|
74
|
+
heapLimit,
|
|
75
|
+
inferredPercent,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function formatBytes(bytes) {
|
|
79
|
+
if (bytes === 0)
|
|
80
|
+
return '0 B';
|
|
81
|
+
const k = 1024;
|
|
82
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
83
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
84
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
85
|
+
}
|
|
86
|
+
export function getHeapStats() {
|
|
87
|
+
const heapStats = v8.getHeapStatistics();
|
|
88
|
+
const { heapUsed } = process.memoryUsage();
|
|
89
|
+
const heapLimit = heapStats?.heap_size_limit ?? 0;
|
|
90
|
+
const heapRatio = heapLimit > 0 ? heapUsed / heapLimit : 0;
|
|
91
|
+
return {
|
|
92
|
+
heapUsed,
|
|
93
|
+
heapLimit,
|
|
94
|
+
heapRatio,
|
|
95
|
+
};
|
|
96
|
+
}
|