@adriangalilea/utils 0.3.0 → 0.4.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/README.md +10 -5
- package/dist/platform/unseen.d.ts +19 -16
- package/dist/platform/unseen.d.ts.map +1 -1
- package/dist/platform/unseen.js +23 -20
- package/dist/platform/unseen.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,17 +186,22 @@ dir.create(xdg.state('notify'))
|
|
|
186
186
|
|
|
187
187
|
### Unseen
|
|
188
188
|
|
|
189
|
-
Persistent dedup filter
|
|
189
|
+
Persistent dedup filter for arrays of objects. Remembers which IDs it has seen across runs, returns only the new ones.
|
|
190
190
|
|
|
191
191
|
```typescript
|
|
192
192
|
import { unseen } from '@adriangalilea/utils'
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
type Message = { id: string, text: string }
|
|
195
|
+
|
|
196
|
+
const messages: Message[] = await fetchMessages()
|
|
197
|
+
const newMessages = await unseen('messages', messages, 'id')
|
|
198
|
+
// 1st run: 3 messages → returns 3. 2nd run: same 3 → returns []. 3rd run: 5 → returns 2 new.
|
|
199
|
+
|
|
200
|
+
for (const m of newMessages) console.log(m.text)
|
|
198
201
|
```
|
|
199
202
|
|
|
203
|
+
The third argument is the field name that uniquely identifies each item (e.g. `'id'`, `'messageId'`, `'bdnsCode'`). Type-safe — autocompletes valid fields, catches typos at compile time.
|
|
204
|
+
|
|
200
205
|
State persists at `~/.local/state/unseen/{namespace}.json`.
|
|
201
206
|
|
|
202
207
|
## Release
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Persistent dedup filter
|
|
2
|
+
* Persistent dedup filter for arrays of objects.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* manual `tsx check.ts`, a fish loop, a cron job, whatever.
|
|
7
|
-
* Can't double-notify, can't miss items, can't corrupt state.
|
|
8
|
-
*
|
|
9
|
-
* 1st run: 5 orders exist → returns 5
|
|
10
|
-
* 2nd run: same 5 orders → returns 0
|
|
11
|
-
* 3rd run: 7 orders exist → returns 2
|
|
4
|
+
* You have objects with IDs. `unseen` remembers which IDs it has
|
|
5
|
+
* seen across runs and returns only the new ones.
|
|
12
6
|
*
|
|
13
7
|
* ```ts
|
|
14
|
-
*
|
|
15
|
-
*
|
|
8
|
+
* type Message = { id: string, text: string }
|
|
9
|
+
*
|
|
10
|
+
* const messages: Message[] = await fetchMessages()
|
|
11
|
+
* const newMessages = await unseen('messages', messages, 'id')
|
|
12
|
+
*
|
|
13
|
+
* // 1st run: 3 messages exist → returns all 3
|
|
14
|
+
* // 2nd run: same 3 messages → returns []
|
|
15
|
+
* // 3rd run: 5 messages exist → returns the 2 new ones
|
|
16
16
|
* ```
|
|
17
17
|
*
|
|
18
|
+
* Makes any script idempotent — run it once or a thousand times,
|
|
19
|
+
* you only process each item once. Any scheduling works.
|
|
20
|
+
*
|
|
18
21
|
* State persists at `~/.local/state/unseen/{namespace}.json`
|
|
19
22
|
*
|
|
20
|
-
* @param namespace -
|
|
21
|
-
* @param items -
|
|
22
|
-
* @param key -
|
|
23
|
-
* @returns Only items
|
|
23
|
+
* @param namespace - Name for this seen-set (e.g. 'messages', 'orders')
|
|
24
|
+
* @param items - Array of objects to filter
|
|
25
|
+
* @param key - Which field is the unique ID (e.g. 'id', 'messageId', 'bdnsCode')
|
|
26
|
+
* @returns Only items not seen in previous runs
|
|
24
27
|
*/
|
|
25
|
-
export declare function unseen<T>(namespace: string, items: T[], key:
|
|
28
|
+
export declare function unseen<T>(namespace: string, items: T[], key: keyof T & string): Promise<T[]>;
|
|
26
29
|
//# sourceMappingURL=unseen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unseen.d.ts","sourceRoot":"","sources":["../../src/platform/unseen.ts"],"names":[],"mappings":"AAOA
|
|
1
|
+
{"version":3,"file":"unseen.d.ts","sourceRoot":"","sources":["../../src/platform/unseen.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAmBlG"}
|
package/dist/platform/unseen.js
CHANGED
|
@@ -1,41 +1,44 @@
|
|
|
1
1
|
import { xdg } from './xdg.js';
|
|
2
2
|
import { dir } from './dir.js';
|
|
3
3
|
import { file } from './file.js';
|
|
4
|
-
import { join } from 'node:path';
|
|
4
|
+
import { join, dirname } from 'node:path';
|
|
5
5
|
const STORE_DIR = xdg.state('unseen');
|
|
6
6
|
/**
|
|
7
|
-
* Persistent dedup filter
|
|
7
|
+
* Persistent dedup filter for arrays of objects.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* manual `tsx check.ts`, a fish loop, a cron job, whatever.
|
|
12
|
-
* Can't double-notify, can't miss items, can't corrupt state.
|
|
13
|
-
*
|
|
14
|
-
* 1st run: 5 orders exist → returns 5
|
|
15
|
-
* 2nd run: same 5 orders → returns 0
|
|
16
|
-
* 3rd run: 7 orders exist → returns 2
|
|
9
|
+
* You have objects with IDs. `unseen` remembers which IDs it has
|
|
10
|
+
* seen across runs and returns only the new ones.
|
|
17
11
|
*
|
|
18
12
|
* ```ts
|
|
19
|
-
*
|
|
20
|
-
*
|
|
13
|
+
* type Message = { id: string, text: string }
|
|
14
|
+
*
|
|
15
|
+
* const messages: Message[] = await fetchMessages()
|
|
16
|
+
* const newMessages = await unseen('messages', messages, 'id')
|
|
17
|
+
*
|
|
18
|
+
* // 1st run: 3 messages exist → returns all 3
|
|
19
|
+
* // 2nd run: same 3 messages → returns []
|
|
20
|
+
* // 3rd run: 5 messages exist → returns the 2 new ones
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
|
+
* Makes any script idempotent — run it once or a thousand times,
|
|
24
|
+
* you only process each item once. Any scheduling works.
|
|
25
|
+
*
|
|
23
26
|
* State persists at `~/.local/state/unseen/{namespace}.json`
|
|
24
27
|
*
|
|
25
|
-
* @param namespace -
|
|
26
|
-
* @param items -
|
|
27
|
-
* @param key -
|
|
28
|
-
* @returns Only items
|
|
28
|
+
* @param namespace - Name for this seen-set (e.g. 'messages', 'orders')
|
|
29
|
+
* @param items - Array of objects to filter
|
|
30
|
+
* @param key - Which field is the unique ID (e.g. 'id', 'messageId', 'bdnsCode')
|
|
31
|
+
* @returns Only items not seen in previous runs
|
|
29
32
|
*/
|
|
30
33
|
export async function unseen(namespace, items, key) {
|
|
31
|
-
dir.create(STORE_DIR);
|
|
32
34
|
const storePath = join(STORE_DIR, `${namespace}.json`);
|
|
35
|
+
dir.create(dirname(storePath));
|
|
33
36
|
const seen = new Set(file.exists(storePath) ? JSON.parse(file.readText(storePath)) : []);
|
|
34
37
|
const result = [];
|
|
35
38
|
for (const item of items) {
|
|
36
|
-
const
|
|
37
|
-
if (!seen.has(
|
|
38
|
-
seen.add(
|
|
39
|
+
const id = String(item[key]);
|
|
40
|
+
if (!seen.has(id)) {
|
|
41
|
+
seen.add(id);
|
|
39
42
|
result.push(item);
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unseen.js","sourceRoot":"","sources":["../../src/platform/unseen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"unseen.js","sourceRoot":"","sources":["../../src/platform/unseen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAI,SAAiB,EAAE,KAAU,EAAE,GAAqB;IAClF,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,SAAS,OAAO,CAAC,CAAA;IACtD,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAA;IAE9B,MAAM,IAAI,GAAgB,IAAI,GAAG,CAC/B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAa,CAAC,CAAC,CAAC,EAAE,CAC/E,CAAA;IAED,MAAM,MAAM,GAAQ,EAAE,CAAA;IACtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACZ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IAChD,OAAO,MAAM,CAAA;AACf,CAAC"}
|