@crawlee/fs-storage 4.0.0-beta.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +201 -0
- package/README.md +153 -0
- package/file-system-storage.d.ts +87 -0
- package/file-system-storage.js +229 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +57 -0
- package/resource-clients/cached-id-client.d.ts +11 -0
- package/resource-clients/cached-id-client.js +13 -0
- package/resource-clients/dataset.d.ts +36 -0
- package/resource-clients/dataset.js +75 -0
- package/resource-clients/key-value-store.d.ts +81 -0
- package/resource-clients/key-value-store.js +239 -0
- package/resource-clients/request-queue.d.ts +51 -0
- package/resource-clients/request-queue.js +119 -0
- package/utils.d.ts +1 -0
- package/utils.js +5 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { s } from '@sapphire/shapeshift';
|
|
2
|
+
import { CachedIdClient } from './cached-id-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Convert a request (either a Crawlee `Request` instance or a plain schema object) into a plain object
|
|
5
|
+
* whose properties are all enumerable.
|
|
6
|
+
*
|
|
7
|
+
* Crawlee's `Request` stores internal metadata (crawl depth, enqueue strategy, session id, ...) in a
|
|
8
|
+
* *non-enumerable* `userData.__crawlee` bag. The native `@crawlee/fs-storage-native` client reads
|
|
9
|
+
* request properties directly over the N-API boundary, which only exposes enumerable own properties
|
|
10
|
+
* and does not honor `toJSON`. Passing a `Request` straight through would therefore silently drop the
|
|
11
|
+
* `__crawlee` metadata, resetting `crawlDepth` to 0 on the next `fetchNextRequest` (breaking e.g.
|
|
12
|
+
* `maxCrawlDepth` and enqueue-strategy handling). Round-tripping through JSON invokes the request's
|
|
13
|
+
* `toJSON`, flattening everything into enumerable properties the native client can persist.
|
|
14
|
+
*/
|
|
15
|
+
function plainifyRequest(request) {
|
|
16
|
+
return JSON.parse(JSON.stringify(request));
|
|
17
|
+
}
|
|
18
|
+
const requestShape = s
|
|
19
|
+
.object({
|
|
20
|
+
id: s.string(),
|
|
21
|
+
url: s.string().url({ allowedProtocols: ['http:', 'https:'] }),
|
|
22
|
+
uniqueKey: s.string(),
|
|
23
|
+
method: s.string().optional(),
|
|
24
|
+
retryCount: s.number().int().optional(),
|
|
25
|
+
handledAt: s.union([s.string(), s.date().valid()]).optional(),
|
|
26
|
+
})
|
|
27
|
+
.passthrough();
|
|
28
|
+
const requestShapeWithoutId = requestShape.omit(['id']);
|
|
29
|
+
const batchRequestShapeWithoutId = requestShapeWithoutId.array();
|
|
30
|
+
const requestOptionsShape = s.object({
|
|
31
|
+
forefront: s.boolean().optional(),
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* A file-system request queue backend backed by the native `@crawlee/fs-storage-native` Rust
|
|
35
|
+
* extension.
|
|
36
|
+
*
|
|
37
|
+
* Request ordering, in-progress locking and state persistence are all owned by the native client.
|
|
38
|
+
* This adapter forwards each operation and converts result shapes to the `@crawlee/types` interfaces.
|
|
39
|
+
*/
|
|
40
|
+
export class RequestQueueBackend extends CachedIdClient {
|
|
41
|
+
name;
|
|
42
|
+
cacheKey;
|
|
43
|
+
nativeBackend;
|
|
44
|
+
constructor(options) {
|
|
45
|
+
super();
|
|
46
|
+
this.name = options.name;
|
|
47
|
+
this.cacheKey = options.cacheKey;
|
|
48
|
+
this.nativeBackend = options.nativeBackend;
|
|
49
|
+
}
|
|
50
|
+
get requestQueueDirectory() {
|
|
51
|
+
return this.nativeBackend.pathToRq;
|
|
52
|
+
}
|
|
53
|
+
static async create(options) {
|
|
54
|
+
const backend = new RequestQueueBackend(options);
|
|
55
|
+
backend.cachedId = (await options.nativeBackend.getMetadata()).id;
|
|
56
|
+
return backend;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Tells the native client how long (in seconds) a fetched request stays locked before it becomes
|
|
60
|
+
* available again.
|
|
61
|
+
*/
|
|
62
|
+
async setExpectedRequestProcessingTimeSecs(secs) {
|
|
63
|
+
await this.nativeBackend.setExpectedRequestProcessingTime(secs);
|
|
64
|
+
}
|
|
65
|
+
async getMetadata() {
|
|
66
|
+
return this.nativeBackend.getMetadata();
|
|
67
|
+
}
|
|
68
|
+
async drop() {
|
|
69
|
+
await this.nativeBackend.dropStorage();
|
|
70
|
+
}
|
|
71
|
+
async purge() {
|
|
72
|
+
await this.nativeBackend.purge();
|
|
73
|
+
}
|
|
74
|
+
async addBatchOfRequests(requests, options = {}) {
|
|
75
|
+
batchRequestShapeWithoutId.parse(requests);
|
|
76
|
+
requestOptionsShape.parse(options);
|
|
77
|
+
const response = await this.nativeBackend.addBatchOfRequests(requests.map((request) => plainifyRequest(request)), options.forefront ?? false);
|
|
78
|
+
// `processedRequests` is structurally identical between the native and `storage` types, so it
|
|
79
|
+
// passes through unchanged. `unprocessedRequests` only differs in that the native `method` is
|
|
80
|
+
// a plain `string`, hence the cast to the narrower `AllowedHttpMethods` union.
|
|
81
|
+
return {
|
|
82
|
+
processedRequests: response.processedRequests,
|
|
83
|
+
unprocessedRequests: response.unprocessedRequests,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async getRequest(uniqueKey) {
|
|
87
|
+
s.string().parse(uniqueKey);
|
|
88
|
+
// The native client tags requests with an internal `orderNo`; it's harmless to leak, so we
|
|
89
|
+
// hand the request back as-is rather than copying it just to drop one undeclared property.
|
|
90
|
+
// The native client already returns `undefined` for a missing request, matching this contract.
|
|
91
|
+
return (await this.nativeBackend.getRequest(uniqueKey));
|
|
92
|
+
}
|
|
93
|
+
async fetchNextRequest() {
|
|
94
|
+
return (await this.nativeBackend.fetchNextRequest());
|
|
95
|
+
}
|
|
96
|
+
async markRequestAsHandled(request) {
|
|
97
|
+
requestShape.parse(request);
|
|
98
|
+
return (await this.nativeBackend.markRequestAsHandled(plainifyRequest(request))) ?? undefined;
|
|
99
|
+
}
|
|
100
|
+
async reclaimRequest(request, options = {}) {
|
|
101
|
+
requestShape.parse(request);
|
|
102
|
+
requestOptionsShape.parse(options);
|
|
103
|
+
return ((await this.nativeBackend.reclaimRequest(plainifyRequest(request), options.forefront ?? false)) ?? undefined);
|
|
104
|
+
}
|
|
105
|
+
async isEmpty() {
|
|
106
|
+
return this.nativeBackend.isEmpty();
|
|
107
|
+
}
|
|
108
|
+
async isFinished() {
|
|
109
|
+
return this.nativeBackend.isFinished();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Persist the native client's in-memory state to disk. Called by
|
|
113
|
+
* {@link FileSystemStorageBackend.teardown} so that fetched-but-unhandled requests are not stuck
|
|
114
|
+
* for the next consumer of the same on-disk queue.
|
|
115
|
+
*/
|
|
116
|
+
async persistState() {
|
|
117
|
+
await this.nativeBackend.persistState();
|
|
118
|
+
}
|
|
119
|
+
}
|
package/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isStream(value: any): boolean;
|