@automerge/automerge-repo 2.5.4 → 2.5.6
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/DocHandle.d.ts +4 -3
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +6 -4
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +19 -17
- package/dist/helpers/abortable.d.ts +3 -0
- package/dist/helpers/abortable.d.ts.map +1 -1
- package/dist/helpers/abortable.js +11 -2
- package/dist/helpers/falsePromiseFactory.d.ts +2 -0
- package/dist/helpers/falsePromiseFactory.d.ts.map +1 -0
- package/dist/helpers/falsePromiseFactory.js +3 -0
- package/dist/helpers/foreverPromise.d.ts +5 -0
- package/dist/helpers/foreverPromise.d.ts.map +1 -0
- package/dist/helpers/foreverPromise.js +6 -0
- package/dist/helpers/has-at-least-one-key.d.ts +12 -0
- package/dist/helpers/has-at-least-one-key.d.ts.map +1 -0
- package/dist/helpers/has-at-least-one-key.js +18 -0
- package/dist/helpers/isPlainObject.d.ts +8 -0
- package/dist/helpers/isPlainObject.d.ts.map +1 -0
- package/dist/helpers/isPlainObject.js +9 -0
- package/dist/helpers/noop.d.ts +2 -0
- package/dist/helpers/noop.d.ts.map +1 -0
- package/dist/helpers/noop.js +3 -0
- package/dist/helpers/pause.d.ts +37 -1
- package/dist/helpers/pause.d.ts.map +1 -1
- package/dist/helpers/pause.js +56 -1
- package/dist/helpers/throttle.d.ts +42 -1
- package/dist/helpers/throttle.d.ts.map +1 -1
- package/dist/helpers/throttle.js +78 -0
- package/dist/helpers/truePromiseFactory.d.ts +2 -0
- package/dist/helpers/truePromiseFactory.d.ts.map +1 -0
- package/dist/helpers/truePromiseFactory.js +3 -0
- package/dist/presence/Presence.d.ts +1 -1
- package/dist/presence/Presence.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +2 -2
- package/package.json +2 -2
- package/src/DocHandle.ts +17 -7
- package/src/Repo.ts +33 -22
- package/src/helpers/abortable.ts +13 -9
- package/src/helpers/falsePromiseFactory.ts +3 -0
- package/src/helpers/foreverPromise.ts +6 -0
- package/src/helpers/has-at-least-one-key.ts +17 -0
- package/src/helpers/isPlainObject.ts +11 -0
- package/src/helpers/noop.ts +3 -0
- package/src/helpers/pause.ts +68 -2
- package/src/helpers/throttle.ts +86 -3
- package/src/helpers/truePromiseFactory.ts +3 -0
- package/src/presence/Presence.ts +4 -1
- package/src/synchronizer/DocSynchronizer.ts +5 -2
- package/test/AutomergeUrl.test.ts +1 -1
- package/test/DocHandle.test.ts +27 -19
- package/test/DocSynchronizer.test.ts +69 -1
- package/test/Repo.test.ts +159 -1
- package/test/abortable.test.ts +185 -0
- package/test/pause.test.ts +93 -0
- package/test/remoteHeads.test.ts +6 -4
- package/test/throttle.test.ts +154 -0
package/dist/DocHandle.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
|
|
|
21
21
|
#private;
|
|
22
22
|
documentId: DocumentId;
|
|
23
23
|
/** @hidden */
|
|
24
|
-
constructor(documentId: DocumentId, options?: DocHandleOptions<T>);
|
|
24
|
+
constructor(documentId: DocumentId, refConstructor: <TDoc, TPath extends readonly PathInput[]>(handle: DocHandle<TDoc>, path: [...TPath]) => Ref<any>, options?: DocHandleOptions<T>);
|
|
25
25
|
/** Our documentId in Automerge URL form.
|
|
26
26
|
*/
|
|
27
27
|
get url(): AutomergeUrl;
|
|
@@ -57,7 +57,7 @@ export declare class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
|
|
|
57
57
|
*/
|
|
58
58
|
inState: (states: HandleState[]) => boolean;
|
|
59
59
|
/** @hidden */
|
|
60
|
-
get state(): "
|
|
60
|
+
get state(): "idle" | "loading" | "requesting" | "ready" | "unavailable" | "unloaded" | "deleted";
|
|
61
61
|
/**
|
|
62
62
|
* Returns promise that resolves when document is in one of the given states (default is 'ready' state)
|
|
63
63
|
*
|
|
@@ -263,7 +263,8 @@ export type SyncInfo = {
|
|
|
263
263
|
lastSyncTimestamp: number;
|
|
264
264
|
};
|
|
265
265
|
/** @hidden */
|
|
266
|
-
export type DocHandleOptions<T> =
|
|
266
|
+
export type DocHandleOptions<T> = // NEW DOCUMENTS
|
|
267
|
+
{
|
|
267
268
|
/** If we know this is a new document (because we're creating it) this should be set to true. */
|
|
268
269
|
isNew: true;
|
|
269
270
|
/** The initial value of the document. */
|
package/dist/DocHandle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAU5C,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAEL,YAAY,EAEb,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"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"}
|
package/dist/DocHandle.js
CHANGED
|
@@ -7,7 +7,6 @@ import { encode } from "./helpers/cbor.js";
|
|
|
7
7
|
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
8
8
|
import { withTimeout } from "./helpers/withTimeout.js";
|
|
9
9
|
import { AbortError, isAbortErrorLike, } from "./helpers/abortable.js";
|
|
10
|
-
import { RefImpl } from "./refs/ref.js";
|
|
11
10
|
/**
|
|
12
11
|
* A DocHandle is a wrapper around a single Automerge document that lets us listen for changes and
|
|
13
12
|
* notify the network and storage of new changes.
|
|
@@ -39,10 +38,13 @@ export class DocHandle extends EventEmitter {
|
|
|
39
38
|
#viewCache = new Map();
|
|
40
39
|
/** Cache for ref instances, keyed by serialized path */
|
|
41
40
|
#refCache = new Map();
|
|
41
|
+
/** Factory for creating Ref instances, injected by Repo to avoid circular imports */
|
|
42
|
+
#refConstructor;
|
|
42
43
|
/** @hidden */
|
|
43
|
-
constructor(documentId, options = {}) {
|
|
44
|
+
constructor(documentId, refConstructor, options = {}) {
|
|
44
45
|
super();
|
|
45
46
|
this.documentId = documentId;
|
|
47
|
+
this.#refConstructor = refConstructor;
|
|
46
48
|
if ("timeoutDelay" in options && options.timeoutDelay) {
|
|
47
49
|
this.#timeoutDelay = options.timeoutDelay;
|
|
48
50
|
}
|
|
@@ -367,7 +369,7 @@ export class DocHandle extends EventEmitter {
|
|
|
367
369
|
return cachedHandle;
|
|
368
370
|
}
|
|
369
371
|
// Create a new handle with the same documentId but fixed heads
|
|
370
|
-
const handle = new DocHandle(this.documentId, {
|
|
372
|
+
const handle = new DocHandle(this.documentId, this.#refConstructor, {
|
|
371
373
|
heads,
|
|
372
374
|
timeoutDelay: this.#timeoutDelay,
|
|
373
375
|
});
|
|
@@ -624,7 +626,7 @@ export class DocHandle extends EventEmitter {
|
|
|
624
626
|
return existingRef;
|
|
625
627
|
}
|
|
626
628
|
// Create new ref and cache it
|
|
627
|
-
const newRef =
|
|
629
|
+
const newRef = this.#refConstructor(this, segments);
|
|
628
630
|
this.#refCache.set(cacheKey, new WeakRef(newRef));
|
|
629
631
|
return newRef;
|
|
630
632
|
}
|
package/dist/Repo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,MAAM,2BAA2B,CAAA;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAS5C,OAAO,EAEL,SAAS,EAKV,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EACL,uBAAuB,EACvB,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAA;AACjF,OAAO,EACL,cAAc,EAEf,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EAEZ,UAAU,EACV,MAAM,EACP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAa,YAAY,EAAc,MAAM,wBAAwB,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
|
package/dist/Repo.js
CHANGED
|
@@ -5,11 +5,17 @@ import { binaryToDocumentId, encodeHeads, generateAutomergeUrl, interpretAsDocum
|
|
|
5
5
|
import { DELETED, DocHandle, READY, UNAVAILABLE, UNLOADED, } from "./DocHandle.js";
|
|
6
6
|
import { RemoteHeadsSubscriptions } from "./RemoteHeadsSubscriptions.js";
|
|
7
7
|
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
8
|
-
import {
|
|
8
|
+
import { asyncThrottle } from "./helpers/throttle.js";
|
|
9
9
|
import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
|
|
10
10
|
import { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
11
11
|
import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
|
|
12
12
|
import { abortable, AbortError } from "./helpers/abortable.js";
|
|
13
|
+
import { RefImpl } from "./refs/ref.js";
|
|
14
|
+
import { foreverPromise } from "./helpers/foreverPromise.js";
|
|
15
|
+
import { noop } from "./helpers/noop.js";
|
|
16
|
+
import { truePromiseFactory } from "./helpers/truePromiseFactory.js";
|
|
17
|
+
import { isPlainObject } from "./helpers/isPlainObject.js";
|
|
18
|
+
import { hasAtLeastOneKey } from "./helpers/has-at-least-one-key.js";
|
|
13
19
|
function randomPeerId() {
|
|
14
20
|
return ("peer-" + Math.random().toString(36).slice(4));
|
|
15
21
|
}
|
|
@@ -35,8 +41,8 @@ export class Repo extends EventEmitter {
|
|
|
35
41
|
/** @hidden */
|
|
36
42
|
synchronizer;
|
|
37
43
|
#shareConfig = {
|
|
38
|
-
announce:
|
|
39
|
-
access:
|
|
44
|
+
announce: truePromiseFactory,
|
|
45
|
+
access: truePromiseFactory,
|
|
40
46
|
};
|
|
41
47
|
/** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
|
|
42
48
|
/** @hidden */
|
|
@@ -58,7 +64,7 @@ export class Repo extends EventEmitter {
|
|
|
58
64
|
if (sharePolicy) {
|
|
59
65
|
this.#shareConfig = {
|
|
60
66
|
announce: sharePolicy,
|
|
61
|
-
access:
|
|
67
|
+
access: truePromiseFactory,
|
|
62
68
|
};
|
|
63
69
|
}
|
|
64
70
|
if (shareConfig) {
|
|
@@ -102,16 +108,13 @@ export class Repo extends EventEmitter {
|
|
|
102
108
|
this.#saveFn = ({ handle, doc }) => {
|
|
103
109
|
let fn = this.#saveFns[handle.documentId];
|
|
104
110
|
if (!fn) {
|
|
105
|
-
fn =
|
|
106
|
-
void this.storageSubsystem.saveDoc(handle.documentId, doc);
|
|
107
|
-
}, this.#saveDebounceRate);
|
|
108
|
-
this.#saveFns[handle.documentId] = fn;
|
|
111
|
+
fn = this.#saveFns[handle.documentId] = asyncThrottle(({ doc, handle, }) => this.storageSubsystem.saveDoc(handle.documentId, doc), this.#saveDebounceRate);
|
|
109
112
|
}
|
|
110
|
-
fn({ handle, doc });
|
|
113
|
+
void fn({ handle, doc });
|
|
111
114
|
};
|
|
112
115
|
}
|
|
113
116
|
else {
|
|
114
|
-
this.#saveFn =
|
|
117
|
+
this.#saveFn = noop;
|
|
115
118
|
}
|
|
116
119
|
// NETWORK
|
|
117
120
|
// The network subsystem deals with sending and receiving messages to and from peers.
|
|
@@ -250,11 +253,9 @@ export class Repo extends EventEmitter {
|
|
|
250
253
|
}
|
|
251
254
|
let handler = this.#throttledSaveSyncStateHandlers[storageId];
|
|
252
255
|
if (!handler) {
|
|
253
|
-
handler = this.#throttledSaveSyncStateHandlers[storageId] =
|
|
254
|
-
void this.storageSubsystem.saveSyncState(documentId, storageId, syncState);
|
|
255
|
-
}, this.#saveDebounceRate);
|
|
256
|
+
handler = this.#throttledSaveSyncStateHandlers[storageId] = asyncThrottle(({ documentId, syncState }) => this.storageSubsystem.saveSyncState(documentId, storageId, syncState), this.#saveDebounceRate);
|
|
256
257
|
}
|
|
257
|
-
handler(payload);
|
|
258
|
+
void handler(payload);
|
|
258
259
|
}
|
|
259
260
|
/** Returns an existing handle if we have it; creates one otherwise. */
|
|
260
261
|
#getHandle({ documentId, }) {
|
|
@@ -264,7 +265,7 @@ export class Repo extends EventEmitter {
|
|
|
264
265
|
// If not, create a new handle, cache it, and return it
|
|
265
266
|
if (!documentId)
|
|
266
267
|
throw new Error(`Invalid documentId ${documentId}`);
|
|
267
|
-
const handle = new DocHandle(documentId);
|
|
268
|
+
const handle = new DocHandle(documentId, (handle, path) => new RefImpl(handle, path));
|
|
268
269
|
this.#handleCache[documentId] = handle;
|
|
269
270
|
return handle;
|
|
270
271
|
}
|
|
@@ -305,7 +306,8 @@ export class Repo extends EventEmitter {
|
|
|
305
306
|
*/
|
|
306
307
|
create(initialValue) {
|
|
307
308
|
let initialDoc;
|
|
308
|
-
|
|
309
|
+
// If the initial value is an empty object, use the empty change initialisation path instead of the from path
|
|
310
|
+
if (isPlainObject(initialValue) && hasAtLeastOneKey(initialValue)) {
|
|
309
311
|
initialDoc = Automerge.from(initialValue);
|
|
310
312
|
}
|
|
311
313
|
else {
|
|
@@ -456,7 +458,7 @@ export class Repo extends EventEmitter {
|
|
|
456
458
|
};
|
|
457
459
|
progressSignal.notify(initial);
|
|
458
460
|
// Start the loading process
|
|
459
|
-
void this.#loadDocumentWithProgress(id, documentId, handle, progressSignal, signal ? abortable(
|
|
461
|
+
void this.#loadDocumentWithProgress(id, documentId, handle, progressSignal, signal ? abortable(foreverPromise, signal) : foreverPromise);
|
|
460
462
|
const result = {
|
|
461
463
|
...initial,
|
|
462
464
|
peek: progressSignal.peek,
|
|
@@ -26,6 +26,7 @@ export declare const isAbortErrorLike: (candidate: unknown) => boolean;
|
|
|
26
26
|
* @remarks
|
|
27
27
|
* This utility wraps a Promise and rejects when the provided AbortSignal is aborted.
|
|
28
28
|
* It's designed to make Promise awaits abortable.
|
|
29
|
+
* It is unnecessary for async APIs like `fetch()` that support abort already
|
|
29
30
|
*
|
|
30
31
|
* @example
|
|
31
32
|
* ```typescript
|
|
@@ -40,6 +41,8 @@ export declare const isAbortErrorLike: (candidate: unknown) => boolean;
|
|
|
40
41
|
* }
|
|
41
42
|
* }
|
|
42
43
|
*
|
|
44
|
+
* // fetch already supports signal; so abortable() is NOT needed:
|
|
45
|
+
* const a = await fetch(url, { signal });
|
|
43
46
|
* ```
|
|
44
47
|
*
|
|
45
48
|
* @param p - A Promise to wrap
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"abortable.d.ts","sourceRoot":"","sources":["../../src/helpers/abortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,qBAAa,UAAW,SAAQ,YAAY;gBAC9B,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,OAAO,KAAG,OAQrD,CAAA;AAED
|
|
1
|
+
{"version":3,"file":"abortable.d.ts","sourceRoot":"","sources":["../../src/helpers/abortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,qBAAa,UAAW,SAAQ,YAAY;gBAC9B,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,OAAO,KAAG,OAQrD,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB"}
|
|
@@ -34,6 +34,7 @@ export const isAbortErrorLike = (candidate) => {
|
|
|
34
34
|
* @remarks
|
|
35
35
|
* This utility wraps a Promise and rejects when the provided AbortSignal is aborted.
|
|
36
36
|
* It's designed to make Promise awaits abortable.
|
|
37
|
+
* It is unnecessary for async APIs like `fetch()` that support abort already
|
|
37
38
|
*
|
|
38
39
|
* @example
|
|
39
40
|
* ```typescript
|
|
@@ -48,6 +49,8 @@ export const isAbortErrorLike = (candidate) => {
|
|
|
48
49
|
* }
|
|
49
50
|
* }
|
|
50
51
|
*
|
|
52
|
+
* // fetch already supports signal; so abortable() is NOT needed:
|
|
53
|
+
* const a = await fetch(url, { signal });
|
|
51
54
|
* ```
|
|
52
55
|
*
|
|
53
56
|
* @param p - A Promise to wrap
|
|
@@ -57,13 +60,16 @@ export const isAbortErrorLike = (candidate) => {
|
|
|
57
60
|
* @throws {DOMException} With name "AbortError" if aborted before p settles
|
|
58
61
|
*/
|
|
59
62
|
export function abortable(p, signal) {
|
|
63
|
+
if (signal?.aborted)
|
|
64
|
+
return Promise.reject(signal.reason);
|
|
60
65
|
let settled = false;
|
|
61
66
|
return new Promise((resolve, reject) => {
|
|
62
|
-
|
|
67
|
+
const onAbort = () => {
|
|
63
68
|
if (!settled) {
|
|
64
69
|
reject(new AbortError());
|
|
65
70
|
}
|
|
66
|
-
}
|
|
71
|
+
};
|
|
72
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
67
73
|
p.then(result => {
|
|
68
74
|
resolve(result);
|
|
69
75
|
})
|
|
@@ -72,6 +78,9 @@ export function abortable(p, signal) {
|
|
|
72
78
|
})
|
|
73
79
|
.finally(() => {
|
|
74
80
|
settled = true;
|
|
81
|
+
//listener is added with `{ once: true }`, but this is not enough if signal never receives abort.
|
|
82
|
+
//onAbort is noop once settled, but it is important to cleanup because of closure to Promise's reject
|
|
83
|
+
signal?.removeEventListener("abort", onAbort);
|
|
75
84
|
});
|
|
76
85
|
});
|
|
77
86
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"falsePromiseFactory.d.ts","sourceRoot":"","sources":["../../src/helpers/falsePromiseFactory.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,mBAAmB,wBAAoB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreverPromise.d.ts","sourceRoot":"","sources":["../../src/helpers/foreverPromise.ts"],"names":[],"mappings":"AACA;;GAEG;AACH,eAAO,MAAM,cAAc,gBAA+B,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test if object has at least one key
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Faster than `Object.keys(obj).length > 0` for large object
|
|
6
|
+
* - No Allocation: It doesn't create a massive array in memory.
|
|
7
|
+
* - Short-Circuiting: If the object has 10,000 keys, Object.keys() will visit all 10,000. This function stops at the 1st key.
|
|
8
|
+
*
|
|
9
|
+
* Like `Object.keys()`, only own enumerable properties are considered, so behaviour is identical to `Object.keys(obj).length > 0`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const hasAtLeastOneKey: (obj: Record<string, unknown>) => boolean;
|
|
12
|
+
//# sourceMappingURL=has-at-least-one-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"has-at-least-one-key.d.ts","sourceRoot":"","sources":["../../src/helpers/has-at-least-one-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OAM/D,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test if object has at least one key
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Faster than `Object.keys(obj).length > 0` for large object
|
|
6
|
+
* - No Allocation: It doesn't create a massive array in memory.
|
|
7
|
+
* - Short-Circuiting: If the object has 10,000 keys, Object.keys() will visit all 10,000. This function stops at the 1st key.
|
|
8
|
+
*
|
|
9
|
+
* Like `Object.keys()`, only own enumerable properties are considered, so behaviour is identical to `Object.keys(obj).length > 0`.
|
|
10
|
+
*/
|
|
11
|
+
export const hasAtLeastOneKey = (obj) => {
|
|
12
|
+
for (const _ in obj) {
|
|
13
|
+
//https://caniuse.com/mdn-javascript_builtins_object_hasown
|
|
14
|
+
if (Object.hasOwn(obj, _))
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a value is a plain object.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The value to check.
|
|
5
|
+
* @returns `true` if the value is a plain object, `false` otherwise.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
8
|
+
//# sourceMappingURL=isPlainObject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isPlainObject.d.ts","sourceRoot":"","sources":["../../src/helpers/isPlainObject.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a value is a plain object.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The value to check.
|
|
5
|
+
* @returns `true` if the value is a plain object, `false` otherwise.
|
|
6
|
+
*/
|
|
7
|
+
export function isPlainObject(value) {
|
|
8
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop.d.ts","sourceRoot":"","sources":["../../src/helpers/noop.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,QAAO,IAAU,CAAA"}
|
package/dist/helpers/pause.d.ts
CHANGED
|
@@ -1,2 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Creates a promise that resolves after a specified number of milliseconds.
|
|
3
|
+
* The pause can be aborted using an AbortSignal.
|
|
4
|
+
*
|
|
5
|
+
* @param milliseconds - The number of milliseconds to pause. Defaults to 0.
|
|
6
|
+
* @param signal - An optional AbortSignal that can be used to cancel the pause.
|
|
7
|
+
* @returns A Promise that resolves after the specified delay, or rejects with an AbortError if cancelled.
|
|
8
|
+
*
|
|
9
|
+
* @throws {AbortError} Thrown when the pause is cancelled via the AbortSignal.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Basic usage
|
|
14
|
+
* await pause(1000); // Pause for 1 second
|
|
15
|
+
*
|
|
16
|
+
* // With abort signal
|
|
17
|
+
* const controller = new AbortController();
|
|
18
|
+
* setTimeout(() => controller.abort(), 500); // Cancel after 500ms
|
|
19
|
+
* await pause(1000, controller.signal); // Will be cancelled
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Multiple signals can be observed using the AbortSignal.any() static method.
|
|
24
|
+
* This allows you to pause until either the timeout completes or any of multiple
|
|
25
|
+
* abort signals are triggered.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const signal1 = new AbortController().signal;
|
|
30
|
+
* const signal2 = new AbortController().signal;
|
|
31
|
+
* const combinedSignal = AbortSignal.any([signal1, signal2]);
|
|
32
|
+
* await pause(5000, combinedSignal); // Pause until timeout or either signal aborts
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare const pause: (milliseconds?: number, options?: {
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}) => Promise<void>;
|
|
2
38
|
//# sourceMappingURL=pause.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pause.d.ts","sourceRoot":"","sources":["../../src/helpers/pause.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pause.d.ts","sourceRoot":"","sources":["../../src/helpers/pause.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,KAAK,GAChB,eAAc,MAAU,EACxB,UAAU;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,kBAuBnC,CAAA"}
|
package/dist/helpers/pause.js
CHANGED
|
@@ -1,3 +1,58 @@
|
|
|
1
1
|
/* c8 ignore start */
|
|
2
|
-
|
|
2
|
+
import { AbortError } from "./abortable.js";
|
|
3
|
+
const abortEvent = "abort";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a promise that resolves after a specified number of milliseconds.
|
|
6
|
+
* The pause can be aborted using an AbortSignal.
|
|
7
|
+
*
|
|
8
|
+
* @param milliseconds - The number of milliseconds to pause. Defaults to 0.
|
|
9
|
+
* @param signal - An optional AbortSignal that can be used to cancel the pause.
|
|
10
|
+
* @returns A Promise that resolves after the specified delay, or rejects with an AbortError if cancelled.
|
|
11
|
+
*
|
|
12
|
+
* @throws {AbortError} Thrown when the pause is cancelled via the AbortSignal.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Basic usage
|
|
17
|
+
* await pause(1000); // Pause for 1 second
|
|
18
|
+
*
|
|
19
|
+
* // With abort signal
|
|
20
|
+
* const controller = new AbortController();
|
|
21
|
+
* setTimeout(() => controller.abort(), 500); // Cancel after 500ms
|
|
22
|
+
* await pause(1000, controller.signal); // Will be cancelled
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Multiple signals can be observed using the AbortSignal.any() static method.
|
|
27
|
+
* This allows you to pause until either the timeout completes or any of multiple
|
|
28
|
+
* abort signals are triggered.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const signal1 = new AbortController().signal;
|
|
33
|
+
* const signal2 = new AbortController().signal;
|
|
34
|
+
* const combinedSignal = AbortSignal.any([signal1, signal2]);
|
|
35
|
+
* await pause(5000, combinedSignal); // Pause until timeout or either signal aborts
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export const pause = (milliseconds = 0, options) => {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const { signal } = options ?? {};
|
|
41
|
+
if (signal?.aborted) {
|
|
42
|
+
reject(new AbortError());
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const abortListener = signal &&
|
|
46
|
+
(() => {
|
|
47
|
+
reject(new AbortError());
|
|
48
|
+
clearTimeout(id);
|
|
49
|
+
});
|
|
50
|
+
abortListener &&
|
|
51
|
+
signal?.addEventListener(abortEvent, abortListener, { once: true });
|
|
52
|
+
const id = setTimeout(() => {
|
|
53
|
+
resolve();
|
|
54
|
+
abortListener && signal?.removeEventListener(abortEvent, abortListener);
|
|
55
|
+
}, milliseconds);
|
|
56
|
+
});
|
|
57
|
+
};
|
|
3
58
|
/* c8 ignore end */
|
|
@@ -24,5 +24,46 @@
|
|
|
24
24
|
* target.addEventListener('frequent-event', callback);
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
|
-
export declare const throttle: <F extends (...args: Parameters<F>) => ReturnType<F>>(fn: F, delay: number) => (...args: Parameters<F>) => void;
|
|
27
|
+
export declare const throttle: <F extends (...args: Parameters<F>) => ReturnType<F>>(fn: F, delay: number) => ((...args: Parameters<F>) => void);
|
|
28
|
+
/**
|
|
29
|
+
* Throttles an async function to execute at most once per delay period
|
|
30
|
+
*
|
|
31
|
+
* Unlike regular throttle, this ensures:
|
|
32
|
+
* - Previous calls complete before new ones start (so there is no race with previous calls)
|
|
33
|
+
* - There's always a minimum delay between executions
|
|
34
|
+
* - The latest call always runs (canceling previous pending calls)
|
|
35
|
+
* - Each call waits for the previous execution to complete
|
|
36
|
+
*
|
|
37
|
+
* This creates a batching behavior that prevents flooding while ensuring
|
|
38
|
+
* the final state is always committed.
|
|
39
|
+
*
|
|
40
|
+
* **Note on AbortSignal**: If you need abort functionality, implement it as an
|
|
41
|
+
* argument to `fn`. The wrapped function is responsible for responding to the
|
|
42
|
+
* abort signal, not the throttle mechanism itself.
|
|
43
|
+
*
|
|
44
|
+
* @param fn - The async function to throttle
|
|
45
|
+
* @param delay - Minimum delay in milliseconds between executions
|
|
46
|
+
* @returns A throttled version of the function
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const throttledSave = asyncThrottle(async (data) => {
|
|
51
|
+
* await save(data)
|
|
52
|
+
* }, 100)
|
|
53
|
+
*
|
|
54
|
+
* // Multiple rapid calls will be throttled
|
|
55
|
+
* throttledSave(data1) // Waits 100ms, then executes
|
|
56
|
+
* throttledSave(data2) // Waits for data1 to complete + 100ms delay
|
|
57
|
+
* throttledSave(data3) // Cancels data2, waits for data1 + 100ms delay
|
|
58
|
+
*
|
|
59
|
+
* // Example with AbortSignal support
|
|
60
|
+
* const throttledFetch = asyncThrottle(async (url, signal) => {
|
|
61
|
+
* return fetch(url, { signal })
|
|
62
|
+
* }, 100)
|
|
63
|
+
* const controller = new AbortController()
|
|
64
|
+
* throttledFetch('/api/data', controller.signal)
|
|
65
|
+
* controller.abort() // Aborts the fetch inside fn
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare const asyncThrottle: <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, delay: number) => ((...args: TArgs) => Promise<TReturn>);
|
|
28
69
|
//# sourceMappingURL=throttle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../src/helpers/throttle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,EAC1E,IAAI,CAAC,EACL,OAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../src/helpers/throttle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,EAC1E,IAAI,CAAC,EACL,OAAO,MAAM,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAYnC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,aAAa,GAAI,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EAC5D,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,EACxC,OAAO,MAAM,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAsCvC,CAAA"}
|
package/dist/helpers/throttle.js
CHANGED
|
@@ -37,3 +37,81 @@ export const throttle = (fn, delay) => {
|
|
|
37
37
|
}, wait);
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Throttles an async function to execute at most once per delay period
|
|
42
|
+
*
|
|
43
|
+
* Unlike regular throttle, this ensures:
|
|
44
|
+
* - Previous calls complete before new ones start (so there is no race with previous calls)
|
|
45
|
+
* - There's always a minimum delay between executions
|
|
46
|
+
* - The latest call always runs (canceling previous pending calls)
|
|
47
|
+
* - Each call waits for the previous execution to complete
|
|
48
|
+
*
|
|
49
|
+
* This creates a batching behavior that prevents flooding while ensuring
|
|
50
|
+
* the final state is always committed.
|
|
51
|
+
*
|
|
52
|
+
* **Note on AbortSignal**: If you need abort functionality, implement it as an
|
|
53
|
+
* argument to `fn`. The wrapped function is responsible for responding to the
|
|
54
|
+
* abort signal, not the throttle mechanism itself.
|
|
55
|
+
*
|
|
56
|
+
* @param fn - The async function to throttle
|
|
57
|
+
* @param delay - Minimum delay in milliseconds between executions
|
|
58
|
+
* @returns A throttled version of the function
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const throttledSave = asyncThrottle(async (data) => {
|
|
63
|
+
* await save(data)
|
|
64
|
+
* }, 100)
|
|
65
|
+
*
|
|
66
|
+
* // Multiple rapid calls will be throttled
|
|
67
|
+
* throttledSave(data1) // Waits 100ms, then executes
|
|
68
|
+
* throttledSave(data2) // Waits for data1 to complete + 100ms delay
|
|
69
|
+
* throttledSave(data3) // Cancels data2, waits for data1 + 100ms delay
|
|
70
|
+
*
|
|
71
|
+
* // Example with AbortSignal support
|
|
72
|
+
* const throttledFetch = asyncThrottle(async (url, signal) => {
|
|
73
|
+
* return fetch(url, { signal })
|
|
74
|
+
* }, 100)
|
|
75
|
+
* const controller = new AbortController()
|
|
76
|
+
* throttledFetch('/api/data', controller.signal)
|
|
77
|
+
* controller.abort() // Aborts the fetch inside fn
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export const asyncThrottle = (fn, delay) => {
|
|
81
|
+
let lastCall = Date.now();
|
|
82
|
+
let timeout;
|
|
83
|
+
let currentPromise;
|
|
84
|
+
return async function (...args) {
|
|
85
|
+
// Wait for any previous call to settle, so that there is not a race with
|
|
86
|
+
// throttled calls still running
|
|
87
|
+
if (currentPromise) {
|
|
88
|
+
try {
|
|
89
|
+
await currentPromise;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// noop if error thrown here (just waiting for it to settle)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Clear any pending timeout
|
|
96
|
+
if (timeout) {
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
}
|
|
99
|
+
const wait = lastCall + delay - Date.now(); //if negative, executes immediately
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
timeout = setTimeout(async () => {
|
|
102
|
+
try {
|
|
103
|
+
currentPromise = fn(...args);
|
|
104
|
+
resolve(await currentPromise);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
reject(error);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
lastCall = Date.now();
|
|
111
|
+
currentPromise = undefined;
|
|
112
|
+
timeout = undefined;
|
|
113
|
+
}
|
|
114
|
+
}, wait);
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"truePromiseFactory.d.ts","sourceRoot":"","sources":["../../src/helpers/truePromiseFactory.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,kBAAkB,wBAAmB,CAAA"}
|