batchkit 0.1.0 → 0.2.0-beta.1
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/README.md +5 -9
- package/dist/batch.d.ts.map +1 -1
- package/dist/index.js +29 -7
- package/package.json +1 -1
- package/src/batch.ts +9 -5
- package/src/trace.ts +30 -3
- package/dist/batch.d.ts +0 -3
- package/dist/errors.d.ts +0 -4
- package/dist/errors.d.ts.map +0 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/indexed.d.ts +0 -2
- package/dist/indexed.d.ts.map +0 -1
- package/dist/match.d.ts +0 -6
- package/dist/match.d.ts.map +0 -1
- package/dist/schedulers.d.ts +0 -8
- package/dist/schedulers.d.ts.map +0 -1
- package/dist/trace.d.ts +0 -6
- package/dist/trace.d.ts.map +0 -1
- package/dist/types.d.ts +0 -61
- package/dist/types.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# batchkit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tiny batching library. Supports various scheduling and deduplication strategies.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -20,17 +20,13 @@ const users = batch(
|
|
|
20
20
|
'id'
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
// These calls are
|
|
23
|
+
// These calls are batched into one database query
|
|
24
24
|
const [alice, bob] = await Promise.all([
|
|
25
25
|
users.get(1),
|
|
26
26
|
users.get(2),
|
|
27
27
|
])
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
That's it. Two arguments:
|
|
31
|
-
1. A function that fetches many items at once
|
|
32
|
-
2. The field to match results by
|
|
33
|
-
|
|
34
30
|
## API
|
|
35
31
|
|
|
36
32
|
### `batch(fn, match, options?)`
|
|
@@ -140,7 +136,7 @@ Batches all calls within the same event loop tick:
|
|
|
140
136
|
```typescript
|
|
141
137
|
const users = batch(fn, 'id')
|
|
142
138
|
|
|
143
|
-
//
|
|
139
|
+
// these synchronous invocations are batched into one request
|
|
144
140
|
users.get(1)
|
|
145
141
|
users.get(2)
|
|
146
142
|
users.get(3)
|
|
@@ -231,7 +227,7 @@ function UserAvatar({ userId }: { userId: string }) {
|
|
|
231
227
|
return <img src={data?.avatar} />
|
|
232
228
|
}
|
|
233
229
|
|
|
234
|
-
// Rendering 100 UserAvatars
|
|
230
|
+
// Rendering 100 UserAvatars from a service -> 1 HTTP request
|
|
235
231
|
```
|
|
236
232
|
|
|
237
233
|
### API with Rate Limits
|
|
@@ -248,7 +244,7 @@ const products = batch(
|
|
|
248
244
|
|
|
249
245
|
## TypeScript
|
|
250
246
|
|
|
251
|
-
|
|
247
|
+
Correctly infers types based on call site
|
|
252
248
|
|
|
253
249
|
```typescript
|
|
254
250
|
type User = { id: number; name: string }
|
package/dist/batch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,OAAO,EACP,OAAO,EACP,YAAY,EAEZ,KAAK,EAGN,MAAM,SAAS,CAAC;AAEjB,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EACxB,EAAE,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EACjB,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAClB,OAAO,GAAE,YAAY,CAAC,CAAC,CAAM,GAC5B,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,OAAO,EACP,OAAO,EACP,YAAY,EAEZ,KAAK,EAGN,MAAM,SAAS,CAAC;AAEjB,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EACxB,EAAE,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EACjB,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAClB,OAAO,GAAE,YAAY,CAAC,CAAC,CAAM,GAC5B,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CA8Rf"}
|
package/dist/index.js
CHANGED
|
@@ -66,16 +66,32 @@ function onIdle(options) {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// src/trace.ts
|
|
69
|
+
function getDevtools() {
|
|
70
|
+
if (typeof window !== "undefined" && window.__BATCHKIT_DEVTOOLS__) {
|
|
71
|
+
return window.__BATCHKIT_DEVTOOLS__;
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
69
75
|
function createTracer(name, handler) {
|
|
70
76
|
let batchCounter = 0;
|
|
77
|
+
let registeredWithDevtools = false;
|
|
71
78
|
function emit(event) {
|
|
72
|
-
|
|
73
|
-
return;
|
|
79
|
+
const timestamp = performance.now();
|
|
74
80
|
const fullEvent = {
|
|
75
81
|
...event,
|
|
76
|
-
timestamp
|
|
82
|
+
timestamp
|
|
77
83
|
};
|
|
78
|
-
handler
|
|
84
|
+
if (handler) {
|
|
85
|
+
handler(fullEvent);
|
|
86
|
+
}
|
|
87
|
+
const devtools = getDevtools();
|
|
88
|
+
if (devtools && name) {
|
|
89
|
+
if (!registeredWithDevtools) {
|
|
90
|
+
devtools.register({ name, registeredAt: timestamp });
|
|
91
|
+
registeredWithDevtools = true;
|
|
92
|
+
}
|
|
93
|
+
devtools.emit(name, fullEvent);
|
|
94
|
+
}
|
|
79
95
|
}
|
|
80
96
|
function nextBatchId() {
|
|
81
97
|
return `${name ?? "batch"}-${++batchCounter}`;
|
|
@@ -153,11 +169,13 @@ function batch(fn, match, options = {}) {
|
|
|
153
169
|
if (request.aborted)
|
|
154
170
|
continue;
|
|
155
171
|
const cacheKey = keyFn(request.key);
|
|
156
|
-
|
|
157
|
-
|
|
172
|
+
let requests = keyToRequests.get(cacheKey);
|
|
173
|
+
if (!requests) {
|
|
174
|
+
requests = [];
|
|
175
|
+
keyToRequests.set(cacheKey, requests);
|
|
158
176
|
uniqueKeys.push(request.key);
|
|
159
177
|
}
|
|
160
|
-
|
|
178
|
+
requests.push(request);
|
|
161
179
|
}
|
|
162
180
|
if (uniqueKeys.length === 0)
|
|
163
181
|
return;
|
|
@@ -186,6 +204,8 @@ function batch(fn, match, options = {}) {
|
|
|
186
204
|
for (const key of uniqueKeys) {
|
|
187
205
|
const cacheKey = keyFn(key);
|
|
188
206
|
const requests = keyToRequests.get(cacheKey);
|
|
207
|
+
if (!requests)
|
|
208
|
+
continue;
|
|
189
209
|
const value = indexedMatcher(recordResults, key);
|
|
190
210
|
for (const request of requests) {
|
|
191
211
|
if (request.aborted)
|
|
@@ -205,6 +225,8 @@ function batch(fn, match, options = {}) {
|
|
|
205
225
|
for (const key of uniqueKeys) {
|
|
206
226
|
const cacheKey = keyFn(key);
|
|
207
227
|
const requests = keyToRequests.get(cacheKey);
|
|
228
|
+
if (!requests)
|
|
229
|
+
continue;
|
|
208
230
|
const value = matchFn(arrayResults, key);
|
|
209
231
|
for (const request of requests) {
|
|
210
232
|
if (request.aborted)
|
package/package.json
CHANGED
package/src/batch.ts
CHANGED
|
@@ -104,11 +104,13 @@ export function batch<K, V>(
|
|
|
104
104
|
|
|
105
105
|
const cacheKey = keyFn(request.key);
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
let requests = keyToRequests.get(cacheKey);
|
|
108
|
+
if (!requests) {
|
|
109
|
+
requests = [];
|
|
110
|
+
keyToRequests.set(cacheKey, requests);
|
|
109
111
|
uniqueKeys.push(request.key);
|
|
110
112
|
}
|
|
111
|
-
|
|
113
|
+
requests.push(request);
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
if (uniqueKeys.length === 0) return;
|
|
@@ -144,7 +146,8 @@ export function batch<K, V>(
|
|
|
144
146
|
const recordResults = results as Record<string, V>;
|
|
145
147
|
for (const key of uniqueKeys) {
|
|
146
148
|
const cacheKey = keyFn(key);
|
|
147
|
-
const requests = keyToRequests.get(cacheKey)
|
|
149
|
+
const requests = keyToRequests.get(cacheKey);
|
|
150
|
+
if (!requests) continue;
|
|
148
151
|
const value = indexedMatcher(recordResults, key);
|
|
149
152
|
|
|
150
153
|
for (const request of requests) {
|
|
@@ -169,7 +172,8 @@ export function batch<K, V>(
|
|
|
169
172
|
|
|
170
173
|
for (const key of uniqueKeys) {
|
|
171
174
|
const cacheKey = keyFn(key);
|
|
172
|
-
const requests = keyToRequests.get(cacheKey)
|
|
175
|
+
const requests = keyToRequests.get(cacheKey);
|
|
176
|
+
if (!requests) continue;
|
|
173
177
|
const value = matchFn(arrayResults, key);
|
|
174
178
|
|
|
175
179
|
for (const request of requests) {
|
package/src/trace.ts
CHANGED
|
@@ -1,20 +1,47 @@
|
|
|
1
1
|
import type { TraceEvent, TraceEventData, TraceHandler } from './types';
|
|
2
2
|
|
|
3
|
+
interface DevtoolsRegistry {
|
|
4
|
+
register(info: { name: string; registeredAt: number }): void;
|
|
5
|
+
emit(name: string, event: unknown): void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
declare const window: { __BATCHKIT_DEVTOOLS__?: DevtoolsRegistry } | undefined;
|
|
9
|
+
|
|
10
|
+
function getDevtools(): DevtoolsRegistry | undefined {
|
|
11
|
+
// biome-ignore lint/complexity/useOptionalChain: need typeof check for Node.js
|
|
12
|
+
if (typeof window !== 'undefined' && window.__BATCHKIT_DEVTOOLS__) {
|
|
13
|
+
return window.__BATCHKIT_DEVTOOLS__;
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
export function createTracer<K>(
|
|
4
19
|
name: string | undefined,
|
|
5
20
|
handler: TraceHandler<K> | undefined,
|
|
6
21
|
) {
|
|
7
22
|
let batchCounter = 0;
|
|
23
|
+
let registeredWithDevtools = false;
|
|
8
24
|
|
|
9
25
|
function emit(event: TraceEventData<K>) {
|
|
10
|
-
|
|
26
|
+
const timestamp = performance.now();
|
|
11
27
|
|
|
12
28
|
const fullEvent = {
|
|
13
29
|
...event,
|
|
14
|
-
timestamp
|
|
30
|
+
timestamp,
|
|
15
31
|
} as TraceEvent<K>;
|
|
16
32
|
|
|
17
|
-
handler
|
|
33
|
+
if (handler) {
|
|
34
|
+
handler(fullEvent);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const devtools = getDevtools();
|
|
38
|
+
if (devtools && name) {
|
|
39
|
+
if (!registeredWithDevtools) {
|
|
40
|
+
devtools.register({ name, registeredAt: timestamp });
|
|
41
|
+
registeredWithDevtools = true;
|
|
42
|
+
}
|
|
43
|
+
devtools.emit(name, fullEvent);
|
|
44
|
+
}
|
|
18
45
|
}
|
|
19
46
|
|
|
20
47
|
function nextBatchId(): string {
|
package/dist/batch.d.ts
DELETED
package/dist/errors.d.ts
DELETED
package/dist/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { batch } from './batch';
|
|
2
|
-
export { BatchError } from './errors';
|
|
3
|
-
export { indexed } from './indexed';
|
|
4
|
-
export { onAnimationFrame, onIdle } from './schedulers';
|
|
5
|
-
export type { Batcher, BatchFn, BatchOptions, GetOptions, Match, MatchFn, Scheduler, TraceEvent, TraceHandler, } from './types';
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAExD,YAAY,EACV,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,KAAK,EACL,OAAO,EACP,SAAS,EACT,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC"}
|
package/dist/indexed.d.ts
DELETED
package/dist/indexed.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"indexed.d.ts","sourceRoot":"","sources":["../src/indexed.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,EAAE,OAAO,MAA0B,CAAC"}
|
package/dist/match.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { Match, MatchFn } from './types';
|
|
2
|
-
export declare function isIndexed<K, V>(match: Match<K, V>): match is symbol;
|
|
3
|
-
export declare function isKeyMatch<K, V>(match: Match<K, V>): match is keyof V;
|
|
4
|
-
export declare function normalizeMatch<K, V>(match: Match<K, V>): MatchFn<K, V> | null;
|
|
5
|
-
export declare function createIndexedMatcher<K, V>(): (results: Record<string, V>, key: K) => V | undefined;
|
|
6
|
-
//# sourceMappingURL=match.d.ts.map
|
package/dist/match.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAE9C,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,MAAM,CAEnE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,CAErE;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAkB7E;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,CAAC,KAAK,CAC5C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAC1B,GAAG,EAAE,CAAC,KACH,CAAC,GAAG,SAAS,CAEjB"}
|
package/dist/schedulers.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Scheduler } from './types';
|
|
2
|
-
export declare const microtask: Scheduler;
|
|
3
|
-
export declare function wait(ms: number): Scheduler;
|
|
4
|
-
export declare const onAnimationFrame: Scheduler;
|
|
5
|
-
export declare function onIdle(options?: {
|
|
6
|
-
timeout?: number;
|
|
7
|
-
}): Scheduler;
|
|
8
|
-
//# sourceMappingURL=schedulers.d.ts.map
|
package/dist/schedulers.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schedulers.d.ts","sourceRoot":"","sources":["../src/schedulers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,eAAO,MAAM,SAAS,EAAE,SAYvB,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAK1C;AAED,eAAO,MAAM,gBAAgB,EAAE,SAG9B,CAAC;AAEF,wBAAgB,MAAM,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAahE"}
|
package/dist/trace.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { TraceEventData, TraceHandler } from './types';
|
|
2
|
-
export declare function createTracer<K>(name: string | undefined, handler: TraceHandler<K> | undefined): {
|
|
3
|
-
emit: (event: TraceEventData<K>) => void;
|
|
4
|
-
nextBatchId: () => string;
|
|
5
|
-
};
|
|
6
|
-
//# sourceMappingURL=trace.d.ts.map
|
package/dist/trace.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../src/trace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAExE,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;kBAIf,eAAe,CAAC,CAAC;uBAWd,MAAM;EAK/B"}
|
package/dist/types.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
export type BatchFn<K, V> = (keys: K[], signal: AbortSignal) => Promise<V[] | Record<string, V>>;
|
|
2
|
-
export type Match<K, V> = keyof V | symbol | MatchFn<K, V>;
|
|
3
|
-
export type MatchFn<K, V> = (results: V[], key: K) => V | undefined;
|
|
4
|
-
export type IndexedMatchFn<K, V> = (results: Record<string, V>, key: K) => V | undefined;
|
|
5
|
-
export type Scheduler = (dispatch: () => void) => () => void;
|
|
6
|
-
export type TraceHandler<K = unknown> = (event: TraceEvent<K>) => void;
|
|
7
|
-
export type TraceEventData<K = unknown> = {
|
|
8
|
-
type: 'get';
|
|
9
|
-
key: K;
|
|
10
|
-
} | {
|
|
11
|
-
type: 'dedup';
|
|
12
|
-
key: K;
|
|
13
|
-
} | {
|
|
14
|
-
type: 'schedule';
|
|
15
|
-
batchId: string;
|
|
16
|
-
size: number;
|
|
17
|
-
} | {
|
|
18
|
-
type: 'dispatch';
|
|
19
|
-
batchId: string;
|
|
20
|
-
keys: K[];
|
|
21
|
-
} | {
|
|
22
|
-
type: 'resolve';
|
|
23
|
-
batchId: string;
|
|
24
|
-
duration: number;
|
|
25
|
-
} | {
|
|
26
|
-
type: 'error';
|
|
27
|
-
batchId: string;
|
|
28
|
-
error: Error;
|
|
29
|
-
} | {
|
|
30
|
-
type: 'abort';
|
|
31
|
-
batchId: string;
|
|
32
|
-
};
|
|
33
|
-
export type TraceEvent<K = unknown> = TraceEventData<K> & {
|
|
34
|
-
timestamp: number;
|
|
35
|
-
};
|
|
36
|
-
export interface BatchOptions<K = unknown> {
|
|
37
|
-
wait?: number;
|
|
38
|
-
schedule?: Scheduler;
|
|
39
|
-
max?: number;
|
|
40
|
-
key?: (k: K) => unknown;
|
|
41
|
-
name?: string;
|
|
42
|
-
trace?: TraceHandler<K>;
|
|
43
|
-
}
|
|
44
|
-
export interface GetOptions {
|
|
45
|
-
signal?: AbortSignal;
|
|
46
|
-
}
|
|
47
|
-
export interface Batcher<K, V> {
|
|
48
|
-
get(key: K, options?: GetOptions): Promise<V>;
|
|
49
|
-
get(keys: K[], options?: GetOptions): Promise<V[]>;
|
|
50
|
-
flush(): Promise<void>;
|
|
51
|
-
abort(): void;
|
|
52
|
-
readonly name?: string;
|
|
53
|
-
}
|
|
54
|
-
export interface PendingRequest<K, V> {
|
|
55
|
-
key: K;
|
|
56
|
-
resolve: (value: V) => void;
|
|
57
|
-
reject: (error: Error) => void;
|
|
58
|
-
signal?: AbortSignal;
|
|
59
|
-
aborted: boolean;
|
|
60
|
-
}
|
|
61
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|