@crawlee/core 4.0.0-beta.99 → 4.0.0-rc.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/autoscaling/autoscaled_pool.d.ts +3 -21
- package/autoscaling/autoscaled_pool.js +105 -97
- package/autoscaling/concurrency_system.d.ts +7 -22
- package/autoscaling/concurrency_system.js +112 -100
- package/autoscaling/cpu_load_signal.d.ts +1 -2
- package/autoscaling/cpu_load_signal.js +11 -10
- package/autoscaling/event_loop_load_signal.d.ts +1 -4
- package/autoscaling/event_loop_load_signal.js +18 -18
- package/autoscaling/index.d.ts +1 -1
- package/autoscaling/index.js +1 -1
- package/autoscaling/load_signal.d.ts +8 -7
- package/autoscaling/load_signal.js +14 -12
- package/autoscaling/memory_load_signal.d.ts +3 -12
- package/autoscaling/memory_load_signal.js +41 -41
- package/autoscaling/snapshotter.d.ts +7 -10
- package/autoscaling/snapshotter.js +18 -18
- package/autoscaling/{client_load_signal.d.ts → storage_backend_load_signal.d.ts} +14 -17
- package/autoscaling/{client_load_signal.js → storage_backend_load_signal.js} +27 -27
- package/autoscaling/system_status.d.ts +9 -11
- package/autoscaling/system_status.js +13 -13
- package/configuration.d.ts +16 -16
- package/configuration.js +6 -6
- package/crawlers/context_pipeline.js +6 -6
- package/crawlers/crawler_commons.d.ts +14 -112
- package/crawlers/crawler_commons.js +1 -107
- package/crawlers/error_snapshotter.d.ts +2 -4
- package/crawlers/error_snapshotter.js +5 -5
- package/crawlers/index.d.ts +1 -1
- package/crawlers/index.js +0 -1
- package/crawlers/statistics.d.ts +164 -45
- package/crawlers/statistics.js +339 -153
- package/debug.js +4 -4
- package/enqueue_links/enqueue_links.d.ts +51 -159
- package/enqueue_links/enqueue_links.js +38 -231
- package/enqueue_links/shared.d.ts +34 -24
- package/enqueue_links/shared.js +54 -36
- package/errors.d.ts +43 -12
- package/errors.js +48 -9
- package/events/event_manager.d.ts +2 -2
- package/events/event_manager.js +7 -6
- package/events/local_event_manager.d.ts +1 -1
- package/events/local_event_manager.js +5 -5
- package/http.d.ts +9 -0
- package/http.js +28 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/log.js +5 -1
- package/memory-storage/memory-storage.d.ts +3 -11
- package/memory-storage/memory-storage.js +42 -48
- package/memory-storage/resource-clients/dataset.d.ts +1 -1
- package/memory-storage/resource-clients/dataset.js +8 -13
- package/memory-storage/resource-clients/key-value-store.d.ts +1 -1
- package/memory-storage/resource-clients/key-value-store.js +36 -38
- package/memory-storage/resource-clients/request-queue.d.ts +4 -23
- package/memory-storage/resource-clients/request-queue.js +68 -80
- package/owned_or_injected.d.ts +1 -3
- package/owned_or_injected.js +17 -17
- package/package.json +8 -9
- package/proxy_configuration.d.ts +1 -3
- package/proxy_configuration.js +18 -14
- package/recoverable_state.d.ts +80 -45
- package/recoverable_state.js +163 -75
- package/request.d.ts +3 -4
- package/request.js +57 -44
- package/router.d.ts +6 -9
- package/router.js +23 -23
- package/serialization.js +14 -13
- package/service_locator.d.ts +19 -10
- package/service_locator.js +57 -48
- package/session_pool/session.d.ts +3 -14
- package/session_pool/session.js +76 -74
- package/session_pool/session_pool.d.ts +6 -12
- package/session_pool/session_pool.js +85 -77
- package/storages/batched_adds.d.ts +37 -0
- package/storages/batched_adds.js +73 -0
- package/storages/dataset.d.ts +12 -1
- package/storages/dataset.js +133 -32
- package/storages/index.d.ts +2 -1
- package/storages/index.js +2 -1
- package/storages/key_value_store.d.ts +19 -4
- package/storages/key_value_store.js +204 -75
- package/storages/request_dedup_cache.d.ts +1 -2
- package/storages/request_dedup_cache.js +9 -9
- package/storages/request_list.d.ts +4 -23
- package/storages/request_list.js +103 -96
- package/storages/request_loader.d.ts +5 -0
- package/storages/request_manager_tandem.d.ts +1 -10
- package/storages/request_manager_tandem.js +27 -27
- package/storages/request_queue.d.ts +21 -18
- package/storages/request_queue.js +318 -177
- package/storages/sitemap_request_loader.d.ts +22 -70
- package/storages/sitemap_request_loader.js +122 -116
- package/storages/storage_instance_manager.d.ts +1 -2
- package/storages/storage_instance_manager.js +17 -17
- package/storages/storage_stats.d.ts +1 -1
- package/storages/storage_stats.js +4 -4
- package/storages/throttling_request_manager.d.ts +239 -0
- package/storages/throttling_request_manager.js +646 -0
- package/storages/transaction.d.ts +252 -0
- package/storages/transaction.js +251 -0
- package/storages/utils.d.ts +6 -3
- package/storages/utils.js +11 -2
- package/system-info/runtime.js +7 -7
- package/url.d.ts +9 -0
- package/url.js +11 -0
- package/validators.d.ts +22 -25
- package/validators.js +13 -25
- package/storages/access_checking.d.ts +0 -12
- package/storages/access_checking.js +0 -17
|
@@ -2,13 +2,15 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { DatasetBackend } from './resource-clients/dataset.js';
|
|
3
3
|
import { KeyValueStoreBackend } from './resource-clients/key-value-store.js';
|
|
4
4
|
import { RequestQueueBackend } from './resource-clients/request-queue.js';
|
|
5
|
+
/** The alias the default (unnamed) storage is opened under. */
|
|
6
|
+
const DEFAULT_STORAGE_ALIAS = '__default__';
|
|
5
7
|
export class MemoryStorageBackend {
|
|
6
8
|
logger;
|
|
7
9
|
/**
|
|
8
10
|
* Unique per-instance cache partition key. Mirrors the way `FileSystemStorageBackend` partitions its
|
|
9
11
|
* cache by storage directory: two distinct `MemoryStorageBackend` instances must not share cached backends.
|
|
10
12
|
*/
|
|
11
|
-
instanceCacheKey = `MemoryStorageBackend:${randomUUID()}`;
|
|
13
|
+
#instanceCacheKey = `MemoryStorageBackend:${randomUUID()}`;
|
|
12
14
|
keyValueStoreBackendCache = [];
|
|
13
15
|
datasetBackendCache = [];
|
|
14
16
|
requestQueueBackendCache = [];
|
|
@@ -20,24 +22,26 @@ export class MemoryStorageBackend {
|
|
|
20
22
|
* cache partitions in the storage backend cache.
|
|
21
23
|
*/
|
|
22
24
|
getStorageBackendCacheKey() {
|
|
23
|
-
return this
|
|
25
|
+
return this.#instanceCacheKey;
|
|
24
26
|
}
|
|
25
|
-
static resolveStorageKey(options) {
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
static #resolveStorageKey(options) {
|
|
28
|
+
// No identifier at all means the default storage, which is opened under the reserved alias —
|
|
29
|
+
// same rule as `resolveStorageIdentifier` in the storage frontends, so that a backend used
|
|
30
|
+
// directly lands on the very storage the frontends would have opened.
|
|
31
|
+
const alias = options.alias || (!options.id && !options.name ? DEFAULT_STORAGE_ALIAS : undefined);
|
|
32
|
+
// `alias` covers the identifier-less case, so one of the three is always set.
|
|
33
|
+
const rawKey = alias ?? options.name ?? options.id;
|
|
28
34
|
// Normalize the internal __default__ alias to the user-facing 'default' name.
|
|
29
|
-
const cacheKey = rawKey ===
|
|
30
|
-
return { isAlias, cacheKey };
|
|
35
|
+
const cacheKey = rawKey === DEFAULT_STORAGE_ALIAS ? 'default' : rawKey;
|
|
36
|
+
return { isAlias: alias !== undefined, cacheKey };
|
|
31
37
|
}
|
|
32
38
|
async createDatasetBackend(options = {}) {
|
|
33
|
-
const { isAlias, cacheKey } = MemoryStorageBackend
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return found;
|
|
40
|
-
}
|
|
39
|
+
const { isAlias, cacheKey } = MemoryStorageBackend.#resolveStorageKey(options);
|
|
40
|
+
const found = this.datasetBackendCache.find((store) => store.id === cacheKey ||
|
|
41
|
+
store.name?.toLowerCase() === cacheKey.toLowerCase() ||
|
|
42
|
+
store.cacheKey.toLowerCase() === cacheKey.toLowerCase());
|
|
43
|
+
if (found) {
|
|
44
|
+
return found;
|
|
41
45
|
}
|
|
42
46
|
const newStore = new DatasetBackend({
|
|
43
47
|
name: isAlias ? undefined : cacheKey,
|
|
@@ -48,14 +52,12 @@ export class MemoryStorageBackend {
|
|
|
48
52
|
return newStore;
|
|
49
53
|
}
|
|
50
54
|
async createKeyValueStoreBackend(options = {}) {
|
|
51
|
-
const { isAlias, cacheKey } = MemoryStorageBackend
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return found;
|
|
58
|
-
}
|
|
55
|
+
const { isAlias, cacheKey } = MemoryStorageBackend.#resolveStorageKey(options);
|
|
56
|
+
const found = this.keyValueStoreBackendCache.find((store) => store.id === cacheKey ||
|
|
57
|
+
store.name?.toLowerCase() === cacheKey.toLowerCase() ||
|
|
58
|
+
store.cacheKey.toLowerCase() === cacheKey.toLowerCase());
|
|
59
|
+
if (found) {
|
|
60
|
+
return found;
|
|
59
61
|
}
|
|
60
62
|
const newStore = new KeyValueStoreBackend({
|
|
61
63
|
name: isAlias ? undefined : cacheKey,
|
|
@@ -66,14 +68,12 @@ export class MemoryStorageBackend {
|
|
|
66
68
|
return newStore;
|
|
67
69
|
}
|
|
68
70
|
async createRequestQueueBackend(options = {}) {
|
|
69
|
-
const { isAlias, cacheKey } = MemoryStorageBackend
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return found;
|
|
76
|
-
}
|
|
71
|
+
const { isAlias, cacheKey } = MemoryStorageBackend.#resolveStorageKey(options);
|
|
72
|
+
const found = this.requestQueueBackendCache.find((queue) => queue.id === cacheKey ||
|
|
73
|
+
queue.name?.toLowerCase() === cacheKey.toLowerCase() ||
|
|
74
|
+
queue.cacheKey.toLowerCase() === cacheKey.toLowerCase());
|
|
75
|
+
if (found) {
|
|
76
|
+
return found;
|
|
77
77
|
}
|
|
78
78
|
const newStore = new RequestQueueBackend({
|
|
79
79
|
name: isAlias ? undefined : cacheKey,
|
|
@@ -102,28 +102,22 @@ export class MemoryStorageBackend {
|
|
|
102
102
|
return backends.some((store) => store.id === id);
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
|
-
* Cleans up the
|
|
106
|
-
* resets the in-memory state of the cached
|
|
107
|
-
*
|
|
108
|
-
* As with `FileSystemStorageBackend`, the run's input (the `INPUT` key in the default key-value
|
|
109
|
-
* store) is preserved — only the rest of the default storages is cleared.
|
|
105
|
+
* Cleans up the run-scoped storages before the run starts. For the in-memory storage this simply
|
|
106
|
+
* resets the in-memory state of the cached backends.
|
|
110
107
|
*/
|
|
111
108
|
async purge() {
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
// explicitly opened via `{ name: 'default' }`. (`'__default__'` never reaches `cacheKey`,
|
|
116
|
-
// as it is always normalized to `'default'` first, so it does not need to be checked here.)
|
|
109
|
+
// `#resolveStorageKey` leaves `name` unset for the default and alias-keyed storages, which is what
|
|
110
|
+
// marks them as run-scoped. `'default'` is the exception — it collapses onto the default storage.
|
|
111
|
+
const isRunScoped = (store) => store.name === undefined || store.name === 'default';
|
|
117
112
|
const isDefault = (store) => store.name === 'default' || store.cacheKey === 'default';
|
|
118
|
-
const
|
|
119
|
-
await Promise.all(cache.filter(
|
|
113
|
+
const purgeRunScoped = async (cache, purgeStore) => {
|
|
114
|
+
await Promise.all(cache.filter(isRunScoped).map(async (store) => purgeStore(store)));
|
|
120
115
|
};
|
|
121
116
|
await Promise.all([
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
purgeDefaults(this.requestQueueBackendCache, async (store) => store.purge()),
|
|
117
|
+
// Only the default store holds the run input, so it is the only one that keeps `INPUT`.
|
|
118
|
+
purgeRunScoped(this.keyValueStoreBackendCache, async (store) => isDefault(store) ? store.purgeExceptInput() : store.purge()),
|
|
119
|
+
purgeRunScoped(this.datasetBackendCache, async (store) => store.purge()),
|
|
120
|
+
purgeRunScoped(this.requestQueueBackendCache, async (store) => store.purge()),
|
|
127
121
|
]);
|
|
128
122
|
}
|
|
129
123
|
/**
|
|
@@ -14,6 +14,7 @@ export interface DatasetBackendOptions {
|
|
|
14
14
|
storageBackend: MemoryStorageBackend;
|
|
15
15
|
}
|
|
16
16
|
export declare class DatasetBackend<Data extends Dictionary = Dictionary> extends BaseClient implements storage.DatasetBackend<Data> {
|
|
17
|
+
#private;
|
|
17
18
|
name?: string;
|
|
18
19
|
/**
|
|
19
20
|
* The key used for cache lookup. For named storages, this equals the name. For alias (unnamed)
|
|
@@ -24,7 +25,6 @@ export declare class DatasetBackend<Data extends Dictionary = Dictionary> extend
|
|
|
24
25
|
accessedAt: Date;
|
|
25
26
|
modifiedAt: Date;
|
|
26
27
|
itemCount: number;
|
|
27
|
-
private readonly datasetEntries;
|
|
28
28
|
private readonly storageBackend;
|
|
29
29
|
constructor(options: DatasetBackendOptions);
|
|
30
30
|
getMetadata(): Promise<storage.DatasetInfo>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { parseArgument, schemas } from '@crawlee/utils/internal';
|
|
3
3
|
import { BaseClient } from './common/base-client.js';
|
|
4
4
|
/**
|
|
5
5
|
* This is what API returns in the x-apify-pagination-limit
|
|
@@ -22,7 +22,8 @@ export class DatasetBackend extends BaseClient {
|
|
|
22
22
|
accessedAt = new Date();
|
|
23
23
|
modifiedAt = new Date();
|
|
24
24
|
itemCount = 0;
|
|
25
|
-
datasetEntries = new Map();
|
|
25
|
+
#datasetEntries = new Map();
|
|
26
|
+
// kept as TS-private: storage-backend tests read this field at runtime
|
|
26
27
|
storageBackend;
|
|
27
28
|
constructor(options) {
|
|
28
29
|
super(options.id ?? randomUUID());
|
|
@@ -39,22 +40,16 @@ export class DatasetBackend extends BaseClient {
|
|
|
39
40
|
if (storeIndex !== -1) {
|
|
40
41
|
const [oldBackend] = this.storageBackend.datasetBackendCache.splice(storeIndex, 1);
|
|
41
42
|
oldBackend.itemCount = 0;
|
|
42
|
-
oldBackend
|
|
43
|
+
oldBackend.#datasetEntries.clear();
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
async purge() {
|
|
46
47
|
this.itemCount = 0;
|
|
47
|
-
this
|
|
48
|
+
this.#datasetEntries.clear();
|
|
48
49
|
this.updateTimestamps(true);
|
|
49
50
|
}
|
|
50
51
|
getData(options = {}) {
|
|
51
|
-
const { desc, limit, offset } =
|
|
52
|
-
.object({
|
|
53
|
-
desc: s.boolean().optional(),
|
|
54
|
-
limit: s.number().int().optional(),
|
|
55
|
-
offset: s.number().int().optional(),
|
|
56
|
-
})
|
|
57
|
-
.parse(options);
|
|
52
|
+
const { desc, limit, offset } = parseArgument(options, schemas.datasetListItemsOptions);
|
|
58
53
|
return this.getDataPage({
|
|
59
54
|
desc,
|
|
60
55
|
offset: offset ?? 0,
|
|
@@ -67,7 +62,7 @@ export class DatasetBackend extends BaseClient {
|
|
|
67
62
|
const items = [];
|
|
68
63
|
for (let idx = start; idx < end; idx++) {
|
|
69
64
|
const entryNumber = this.generateLocalEntryName(idx);
|
|
70
|
-
items.push(this
|
|
65
|
+
items.push(this.#datasetEntries.get(entryNumber));
|
|
71
66
|
}
|
|
72
67
|
this.updateTimestamps(false);
|
|
73
68
|
return {
|
|
@@ -82,7 +77,7 @@ export class DatasetBackend extends BaseClient {
|
|
|
82
77
|
async pushData(items) {
|
|
83
78
|
for (const entry of items) {
|
|
84
79
|
const idx = this.generateLocalEntryName(++this.itemCount);
|
|
85
|
-
this
|
|
80
|
+
this.#datasetEntries.set(idx, JSON.parse(JSON.stringify(entry)));
|
|
86
81
|
}
|
|
87
82
|
this.updateTimestamps(true);
|
|
88
83
|
}
|
|
@@ -19,6 +19,7 @@ export interface InternalKeyRecord {
|
|
|
19
19
|
extension: string;
|
|
20
20
|
}
|
|
21
21
|
export declare class KeyValueStoreBackend extends BaseClient implements storage.KeyValueStoreBackend {
|
|
22
|
+
#private;
|
|
22
23
|
name?: string;
|
|
23
24
|
/**
|
|
24
25
|
* The key used for cache lookup. For named storages, this equals the name. For alias (unnamed)
|
|
@@ -28,7 +29,6 @@ export declare class KeyValueStoreBackend extends BaseClient implements storage.
|
|
|
28
29
|
createdAt: Date;
|
|
29
30
|
accessedAt: Date;
|
|
30
31
|
modifiedAt: Date;
|
|
31
|
-
private readonly keyValueEntries;
|
|
32
32
|
private readonly storageBackend;
|
|
33
33
|
constructor(options: KeyValueStoreBackendOptions);
|
|
34
34
|
getMetadata(): Promise<storage.KeyValueStoreInfo>;
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { parseArgument, schemas } from '@crawlee/utils/internal';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
import { isStream, toBuffer } from '../utils.js';
|
|
4
5
|
import { BaseClient } from './common/base-client.js';
|
|
5
6
|
import mime from 'mime-types';
|
|
6
7
|
const DEFAULT_LOCAL_FILE_EXTENSION = 'bin';
|
|
8
|
+
const keySchema = z.string();
|
|
9
|
+
const inputRecordSchema = z.object({
|
|
10
|
+
key: z.string().min(1),
|
|
11
|
+
value: z.union([
|
|
12
|
+
z.null(),
|
|
13
|
+
z.string(),
|
|
14
|
+
z.number(),
|
|
15
|
+
z.instanceof(Buffer),
|
|
16
|
+
z.instanceof(ArrayBuffer),
|
|
17
|
+
schemas.typedArray,
|
|
18
|
+
// only checks the value is an actual object, not null, nor array
|
|
19
|
+
schemas.plainObject,
|
|
20
|
+
]),
|
|
21
|
+
contentType: z.string().min(1).optional(),
|
|
22
|
+
});
|
|
7
23
|
/**
|
|
8
24
|
* Key under which a run's input is stored in the default key-value store. Matches Crawlee's default
|
|
9
25
|
* `inputKey` (`CRAWLEE_INPUT_KEY`) and the `INPUT` files `FileSystemStorageBackend` preserves on purge.
|
|
@@ -19,7 +35,8 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
19
35
|
createdAt = new Date();
|
|
20
36
|
accessedAt = new Date();
|
|
21
37
|
modifiedAt = new Date();
|
|
22
|
-
keyValueEntries = new Map();
|
|
38
|
+
#keyValueEntries = new Map();
|
|
39
|
+
// kept as TS-private: storage-backend tests read this field at runtime
|
|
23
40
|
storageBackend;
|
|
24
41
|
constructor(options) {
|
|
25
42
|
super(options.id ?? randomUUID());
|
|
@@ -35,11 +52,11 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
35
52
|
const storeIndex = this.storageBackend.keyValueStoreBackendCache.findIndex((store) => store.id === this.id);
|
|
36
53
|
if (storeIndex !== -1) {
|
|
37
54
|
const [oldBackend] = this.storageBackend.keyValueStoreBackendCache.splice(storeIndex, 1);
|
|
38
|
-
oldBackend
|
|
55
|
+
oldBackend.#keyValueEntries.clear();
|
|
39
56
|
}
|
|
40
57
|
}
|
|
41
58
|
async purge() {
|
|
42
|
-
this
|
|
59
|
+
this.#keyValueEntries.clear();
|
|
43
60
|
this.updateTimestamps(true);
|
|
44
61
|
}
|
|
45
62
|
/**
|
|
@@ -49,23 +66,17 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
49
66
|
* preserve the bare `INPUT` key only.
|
|
50
67
|
*/
|
|
51
68
|
async purgeExceptInput() {
|
|
52
|
-
for (const key of this
|
|
69
|
+
for (const key of this.#keyValueEntries.keys()) {
|
|
53
70
|
if (key !== KEY_VALUE_STORE_INPUT_KEY) {
|
|
54
|
-
this
|
|
71
|
+
this.#keyValueEntries.delete(key);
|
|
55
72
|
}
|
|
56
73
|
}
|
|
57
74
|
this.updateTimestamps(true);
|
|
58
75
|
}
|
|
59
76
|
async listKeys(options = {}) {
|
|
60
|
-
const { prefix, exclusiveStartKey, limit } =
|
|
61
|
-
.object({
|
|
62
|
-
prefix: s.string().optional(),
|
|
63
|
-
exclusiveStartKey: s.string().optional(),
|
|
64
|
-
limit: s.number().int().greaterThan(0).optional(),
|
|
65
|
-
})
|
|
66
|
-
.parse(options);
|
|
77
|
+
const { prefix, exclusiveStartKey, limit } = parseArgument(options, schemas.keyValueStoreListKeysOptions);
|
|
67
78
|
const items = [];
|
|
68
|
-
for (const record of this
|
|
79
|
+
for (const record of this.#keyValueEntries.values()) {
|
|
69
80
|
const size = Buffer.byteLength(record.value);
|
|
70
81
|
items.push({
|
|
71
82
|
key: record.key,
|
|
@@ -103,7 +114,7 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
103
114
|
* @param key The key of the record to generate the public URL for.
|
|
104
115
|
*/
|
|
105
116
|
async getPublicUrl(key) {
|
|
106
|
-
|
|
117
|
+
parseArgument(key, keySchema);
|
|
107
118
|
return undefined;
|
|
108
119
|
}
|
|
109
120
|
/**
|
|
@@ -113,12 +124,12 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
113
124
|
* @returns `true` if the record exists, `false` if it does not.
|
|
114
125
|
*/
|
|
115
126
|
async recordExists(key) {
|
|
116
|
-
|
|
117
|
-
return this
|
|
127
|
+
parseArgument(key, keySchema);
|
|
128
|
+
return this.#keyValueEntries.has(key);
|
|
118
129
|
}
|
|
119
130
|
async getValue(key) {
|
|
120
|
-
|
|
121
|
-
const entry = this
|
|
131
|
+
parseArgument(key, keySchema);
|
|
132
|
+
const entry = this.#keyValueEntries.get(key);
|
|
122
133
|
if (!entry) {
|
|
123
134
|
return undefined;
|
|
124
135
|
}
|
|
@@ -135,20 +146,7 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
135
146
|
return record;
|
|
136
147
|
}
|
|
137
148
|
async setValue(record) {
|
|
138
|
-
|
|
139
|
-
key: s.string().lengthGreaterThan(0),
|
|
140
|
-
value: s.union([
|
|
141
|
-
s.null(),
|
|
142
|
-
s.string(),
|
|
143
|
-
s.number(),
|
|
144
|
-
s.instance(Buffer),
|
|
145
|
-
s.instance(ArrayBuffer),
|
|
146
|
-
s.typedArray(),
|
|
147
|
-
// disabling validation will make shapeshift only check the object given is an actual object, not null, nor array
|
|
148
|
-
s.object({}).setValidationEnabled(false),
|
|
149
|
-
]),
|
|
150
|
-
contentType: s.string().lengthGreaterThan(0).optional(),
|
|
151
|
-
}).parse(record);
|
|
149
|
+
parseArgument(record, inputRecordSchema);
|
|
152
150
|
const { key } = record;
|
|
153
151
|
let { value } = record;
|
|
154
152
|
// The frontend (KeyValueStore codec) serializes the value and resolves its content type
|
|
@@ -169,19 +167,19 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
169
167
|
const normalizedValue = typeof value === 'string'
|
|
170
168
|
? Buffer.from(value, 'utf-8')
|
|
171
169
|
: toBuffer(value);
|
|
172
|
-
const
|
|
170
|
+
const normalizedRecord = {
|
|
173
171
|
extension,
|
|
174
172
|
key,
|
|
175
173
|
value: normalizedValue,
|
|
176
174
|
contentType,
|
|
177
175
|
};
|
|
178
|
-
this
|
|
176
|
+
this.#keyValueEntries.set(key, normalizedRecord);
|
|
179
177
|
this.updateTimestamps(true);
|
|
180
178
|
}
|
|
181
179
|
async deleteValue(key) {
|
|
182
|
-
|
|
183
|
-
if (this
|
|
184
|
-
this
|
|
180
|
+
parseArgument(key, keySchema);
|
|
181
|
+
if (this.#keyValueEntries.has(key)) {
|
|
182
|
+
this.#keyValueEntries.delete(key);
|
|
185
183
|
this.updateTimestamps(true);
|
|
186
184
|
}
|
|
187
185
|
}
|
|
@@ -22,6 +22,7 @@ export interface InternalRequest {
|
|
|
22
22
|
json: string;
|
|
23
23
|
}
|
|
24
24
|
export declare class RequestQueueBackend extends BaseClient implements storage.RequestQueueBackend {
|
|
25
|
+
#private;
|
|
25
26
|
name?: string;
|
|
26
27
|
/**
|
|
27
28
|
* The key used for cache lookup. For named storages, this equals the name. For alias (unnamed)
|
|
@@ -33,26 +34,6 @@ export declare class RequestQueueBackend extends BaseClient implements storage.R
|
|
|
33
34
|
modifiedAt: Date;
|
|
34
35
|
handledRequestCount: number;
|
|
35
36
|
pendingRequestCount: number;
|
|
36
|
-
/**
|
|
37
|
-
* Serializes every operation that reads-then-writes this backend's shared queue state — the
|
|
38
|
-
* `requests` map, the `forefrontRequestIds` array, the `inProgressRequestIds` set and the request
|
|
39
|
-
* counts. Those mutations span `await` points, so without this mutex a concurrent operation could
|
|
40
|
-
* interleave and corrupt them (e.g. a head scan pruning `forefrontRequestIds` while
|
|
41
|
-
* `addBatchOfRequests` pushes to it). Held by every mutating method as well as by `isEmpty`/
|
|
42
|
-
* `isFinished`, whose head scan also prunes `forefrontRequestIds`.
|
|
43
|
-
*/
|
|
44
|
-
private readonly queueStateMutex;
|
|
45
|
-
private forefrontRequestIds;
|
|
46
|
-
/**
|
|
47
|
-
* IDs of requests currently fetched but not yet handled or reclaimed. A request in this set is
|
|
48
|
-
* "in progress" and will not be handed out again by {@link fetchNextRequest}.
|
|
49
|
-
*
|
|
50
|
-
* Unlike the file-system / platform clients, the in-memory queue lives entirely within a single
|
|
51
|
-
* process and is never shared with another consumer, so there is no need for an expiring,
|
|
52
|
-
* cross-process-visible lock — tracking in-progress requests in this set is enough.
|
|
53
|
-
*/
|
|
54
|
-
private readonly inProgressRequestIds;
|
|
55
|
-
private readonly requests;
|
|
56
37
|
private readonly storageBackend;
|
|
57
38
|
constructor(options: RequestQueueBackendOptions);
|
|
58
39
|
getMetadata(): Promise<storage.RequestQueueInfo>;
|
|
@@ -90,7 +71,7 @@ export declare class RequestQueueBackend extends BaseClient implements storage.R
|
|
|
90
71
|
listItems(): Promise<storage.UpdateRequestSchema[]>;
|
|
91
72
|
toRequestQueueInfo(): storage.RequestQueueInfo;
|
|
92
73
|
private updateTimestamps;
|
|
93
|
-
private
|
|
94
|
-
private
|
|
95
|
-
private
|
|
74
|
+
private jsonToRequest;
|
|
75
|
+
private createInternalRequest;
|
|
76
|
+
private calculateOrderNo;
|
|
96
77
|
}
|