xindex 1.0.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.
Files changed (160) hide show
  1. package/.ai/research/2026-04-10-file-watching.md +79 -0
  2. package/.ai/research/2026-04-10-mcp-output-format.md +129 -0
  3. package/.ai/task/INDEX.md +12 -0
  4. package/.ai/task/done/INDEX.md +3 -0
  5. package/.ai/task/done/task.2026-04-09-local-ai-research-protos.log.md +98 -0
  6. package/.ai/task/done/task.2026-04-09-local-ai-research-protos.md +102 -0
  7. package/.ai/task/task.2026-04-10-cluster-config.log.md +19 -0
  8. package/.ai/task/task.2026-04-10-cluster-config.md +118 -0
  9. package/.ai/task/task.2026-04-10-dir-indexing.log.md +8 -0
  10. package/.ai/task/task.2026-04-10-dir-indexing.md +92 -0
  11. package/.ai/task/task.2026-04-10-line-clustering.log.md +50 -0
  12. package/.ai/task/task.2026-04-10-line-clustering.md +176 -0
  13. package/.ai/task/task.2026-04-10-object-store.log.md +7 -0
  14. package/.ai/task/task.2026-04-10-object-store.md +81 -0
  15. package/.ai/task/task.2026-04-10-search-config.log.md +46 -0
  16. package/.ai/task/task.2026-04-10-search-config.md +274 -0
  17. package/.ai/task/task.2026-04-10-watch-indexing.log.md +32 -0
  18. package/.ai/task/task.2026-04-10-watch-indexing.md +101 -0
  19. package/.ai/task/task.2026-04-10-xindex-mcp.log.md +5 -0
  20. package/.ai/task/task.2026-04-10-xindex-mcp.md +92 -0
  21. package/.ai/task/task.2026-04-10-xindex-mcp.report.md +113 -0
  22. package/.claude/settings.local.json +73 -0
  23. package/.claude/skills/make-hof/SKILL.md +8 -0
  24. package/.claude/skills/make-hof/playbook.md +38 -0
  25. package/.cursor/mcp.json +8 -0
  26. package/.mcp.json +8 -0
  27. package/.xindex.json +22 -0
  28. package/CLAUDE.md +54 -0
  29. package/README.md +206 -0
  30. package/apps/indexApp.ts +31 -0
  31. package/apps/mcpApp.ts +119 -0
  32. package/apps/run.index.ts +19 -0
  33. package/apps/run.mcp.ts +49 -0
  34. package/apps/run.reset.ts +10 -0
  35. package/apps/run.search.ts +21 -0
  36. package/apps/run.watch.ts +44 -0
  37. package/apps/searchApp.ts +9 -0
  38. package/apps/watchApp.ts +53 -0
  39. package/apps/watchFileEventsApp.ts +39 -0
  40. package/bin/xindex-index +2 -0
  41. package/bin/xindex-mcp +2 -0
  42. package/bin/xindex-reset +2 -0
  43. package/bin/xindex-search +2 -0
  44. package/bin/xindex-watch +2 -0
  45. package/componets/IType.ts +1 -0
  46. package/componets/appId.ts +3 -0
  47. package/componets/buildComponents.ts +27 -0
  48. package/componets/config/loadConfig.ts +43 -0
  49. package/componets/config/xindexConfig.ts +4 -0
  50. package/componets/index/contentIndexDriver.ts +39 -0
  51. package/componets/index/formatSearchResults.ts +18 -0
  52. package/componets/index/getIndexStats.ts +11 -0
  53. package/componets/index/handleFileEvent.ts +25 -0
  54. package/componets/index/indexApi.ts +45 -0
  55. package/componets/index/vectraIndex.ts +11 -0
  56. package/componets/index/watcherLock.ts +107 -0
  57. package/componets/keywords/cleanUpKeywords.ts +38 -0
  58. package/componets/keywords/extractKeywords.ts +14 -0
  59. package/componets/keywords/refineKeywords.ts +16 -0
  60. package/componets/llm/embed.ts +18 -0
  61. package/componets/llm/queryLLM.ts +20 -0
  62. package/componets/logger.ts +34 -0
  63. package/componets/walkFiles.ts +51 -0
  64. package/componets/watchFiles.ts +106 -0
  65. package/features/indexContent.ts +16 -0
  66. package/features/removeContent.ts +9 -0
  67. package/features/resetIndex.ts +9 -0
  68. package/features/searchIndex.ts +33 -0
  69. package/package.json +32 -0
  70. package/packages/fun/src/IType.ts +5 -0
  71. package/packages/fun/src/array-finder.ts +55 -0
  72. package/packages/fun/src/array-index.ts +35 -0
  73. package/packages/fun/src/array.ts +112 -0
  74. package/packages/fun/src/assert.ts +5 -0
  75. package/packages/fun/src/asyncRequest.ts +35 -0
  76. package/packages/fun/src/callsites.ts +18 -0
  77. package/packages/fun/src/case-never.ts +9 -0
  78. package/packages/fun/src/casting.ts +41 -0
  79. package/packages/fun/src/collect.ts +13 -0
  80. package/packages/fun/src/concurrency.ts +186 -0
  81. package/packages/fun/src/container.ts +86 -0
  82. package/packages/fun/src/counter.ts +45 -0
  83. package/packages/fun/src/create-map.ts +2 -0
  84. package/packages/fun/src/dedupe.ts +2 -0
  85. package/packages/fun/src/defer.ts +55 -0
  86. package/packages/fun/src/delay.ts +5 -0
  87. package/packages/fun/src/discriminate.ts +34 -0
  88. package/packages/fun/src/enum-values.ts +12 -0
  89. package/packages/fun/src/exponential-backoff.ts +20 -0
  90. package/packages/fun/src/flatten.ts +11 -0
  91. package/packages/fun/src/hash.ts +67 -0
  92. package/packages/fun/src/hash128.ts +6 -0
  93. package/packages/fun/src/hash256.ts +6 -0
  94. package/packages/fun/src/hub.ts +53 -0
  95. package/packages/fun/src/id.ts +10 -0
  96. package/packages/fun/src/interval.ts +76 -0
  97. package/packages/fun/src/is-non-nullable.ts +2 -0
  98. package/packages/fun/src/isIterable.ts +3 -0
  99. package/packages/fun/src/mailbox.ts +13 -0
  100. package/packages/fun/src/map-record.ts +19 -0
  101. package/packages/fun/src/match-collections.ts +57 -0
  102. package/packages/fun/src/match-left-and-right-arrays.ts +78 -0
  103. package/packages/fun/src/mem.ts +26 -0
  104. package/packages/fun/src/memos.ts +28 -0
  105. package/packages/fun/src/normalizeError.ts +25 -0
  106. package/packages/fun/src/nothing.ts +3 -0
  107. package/packages/fun/src/pipe.ts +18 -0
  108. package/packages/fun/src/prettyJson.ts +3 -0
  109. package/packages/fun/src/project.ts +8 -0
  110. package/packages/fun/src/promise.ts +27 -0
  111. package/packages/fun/src/pubsub.ts +128 -0
  112. package/packages/fun/src/randomId.ts +14 -0
  113. package/packages/fun/src/regexp-escape.ts +13 -0
  114. package/packages/fun/src/retry.ts +15 -0
  115. package/packages/fun/src/serial.test.ts +107 -0
  116. package/packages/fun/src/serial.ts +17 -0
  117. package/packages/fun/src/sleep.ts +3 -0
  118. package/packages/fun/src/sort-object.ts +46 -0
  119. package/packages/fun/src/speed-test.ts +56 -0
  120. package/packages/fun/src/tick.ts +37 -0
  121. package/packages/fun/src/time-behavior.ts +50 -0
  122. package/packages/fun/src/time.ts +22 -0
  123. package/packages/fun/src/timedFallback.ts +37 -0
  124. package/packages/fun/src/timer.ts +30 -0
  125. package/packages/fun/src/value.ts +33 -0
  126. package/packages/fun/src/waitForCounter.ts +15 -0
  127. package/packages/streamx/src/batch.ts +23 -0
  128. package/packages/streamx/src/batchTimed.ts +113 -0
  129. package/packages/streamx/src/buffer.ts +72 -0
  130. package/packages/streamx/src/concatenate.ts +33 -0
  131. package/packages/streamx/src/filter.ts +14 -0
  132. package/packages/streamx/src/flat.ts +19 -0
  133. package/packages/streamx/src/flatMap.ts +9 -0
  134. package/packages/streamx/src/from.ts +30 -0
  135. package/packages/streamx/src/index.ts +49 -0
  136. package/packages/streamx/src/interval.ts +58 -0
  137. package/packages/streamx/src/loop.ts +8 -0
  138. package/packages/streamx/src/map.ts +12 -0
  139. package/packages/streamx/src/merge.ts +89 -0
  140. package/packages/streamx/src/nodeReadable.ts +6 -0
  141. package/packages/streamx/src/nodeTransform.ts +9 -0
  142. package/packages/streamx/src/nodeWritable.ts +38 -0
  143. package/packages/streamx/src/objectReader.ts +16 -0
  144. package/packages/streamx/src/polyfill.ts +20 -0
  145. package/packages/streamx/src/reader.ts +38 -0
  146. package/packages/streamx/src/reduce.ts +15 -0
  147. package/packages/streamx/src/scale.ts +93 -0
  148. package/packages/streamx/src/scaleSync.ts +13 -0
  149. package/packages/streamx/src/sequence.ts +7 -0
  150. package/packages/streamx/src/tap.ts +9 -0
  151. package/packages/streamx/src/toArray.ts +9 -0
  152. package/packages/streamx/src/writer.ts +96 -0
  153. package/rnd/hf.ts +14 -0
  154. package/rnd/keywords-compromise.ts +18 -0
  155. package/rnd/keywords-pipeline.ts +79 -0
  156. package/rnd/keywords.ts +38 -0
  157. package/rnd/test-vectra-memory.ts +63 -0
  158. package/rnd/vectra-keywords.ts +95 -0
  159. package/rnd/vectra.ts +50 -0
  160. package/tsconfig.json +14 -0
@@ -0,0 +1,56 @@
1
+ function uiTime(startedAt: number) {
2
+ return new Date(startedAt).toISOString();
3
+ }
4
+
5
+ export function SpeedTest({
6
+ name = '',
7
+ every = 1000,
8
+ }: Partial<{ name: string; every: number | null }> = {}) {
9
+ let counter = 0;
10
+ let startedAt: number | null = null;
11
+ let trackedAt: number | null = null;
12
+
13
+ const log = (text: string) => console.log(text);
14
+
15
+ function textReport(finishedAt: number | null = null) {
16
+ const started = startedAt ? uiTime(startedAt) : null;
17
+ const elapsed = startedAt && trackedAt ? trackedAt - startedAt : null;
18
+
19
+ const RPM = counter && elapsed ? Math.round(counter / (elapsed / 60_000)) : null;
20
+
21
+ const RPS = counter && elapsed ? Math.round(counter / (elapsed / 1000)) : null;
22
+
23
+ const finished = finishedAt ? uiTime(finishedAt) : null;
24
+ const tracked = trackedAt ? uiTime(trackedAt) : null;
25
+
26
+ const named = `${name ? `SpeedTest: ${name}; ` : ''}`;
27
+
28
+ return `${named}RPS: ${RPS ?? 'N/A'}; RPM: ${RPM ?? 'N/A'}; Counter: ${counter ?? 'N/A'}; Started: ${started ?? 'N/A'}; Elapsed: ${elapsed ?? 'N/A'}; Tracked: ${tracked ?? 'N/A'}; Finished: ${finished ?? 'N/A'}`;
29
+ }
30
+
31
+ const speedTest = {
32
+ track: (n: number = 1) => {
33
+ if (!startedAt) {
34
+ startedAt = Date.now();
35
+ }
36
+
37
+ trackedAt = Date.now();
38
+
39
+ counter += n;
40
+
41
+ if (every !== null) {
42
+ if (counter % every === 0) {
43
+ log(textReport());
44
+ }
45
+ }
46
+ },
47
+ report: () => {
48
+ log(textReport(Date.now()));
49
+ },
50
+ toString: () => {
51
+ return textReport(Date.now());
52
+ },
53
+ };
54
+
55
+ return speedTest;
56
+ }
@@ -0,0 +1,37 @@
1
+ import { Defer } from './defer';
2
+
3
+ type ITickSyncRunner = () => any;
4
+ type ITickRunner = () => Promise<any> | any;
5
+
6
+ export type ITick = (fn: ITickSyncRunner) => void;
7
+
8
+ function isObject(x: any) {
9
+ return x instanceof Object;
10
+ }
11
+
12
+ function isFunction(x: any) {
13
+ return x instanceof Function;
14
+ }
15
+
16
+ export function SyncTick(): ITick {
17
+ return (fn: ITickSyncRunner) => {
18
+ setTimeout(fn, 0);
19
+ };
20
+ }
21
+
22
+ export const syncTick = SyncTick();
23
+
24
+ export async function tick(fn: ITickRunner) {
25
+ const defer = Defer();
26
+
27
+ syncTick(async () => {
28
+ try {
29
+ await fn();
30
+ defer.resolve();
31
+ } catch (e) {
32
+ defer.reject(e);
33
+ }
34
+ });
35
+
36
+ await defer.promise;
37
+ }
@@ -0,0 +1,50 @@
1
+ import { IValue, Value } from './value';
2
+
3
+ export function throttleTrailing<T>(fn: Function, ms: IValue<number>): () => void {
4
+ let scheduled = false;
5
+ let calledAfterScheduling = false;
6
+ const delayMs = Value<number>(ms);
7
+
8
+ const aThrottle = () => {
9
+ if (scheduled) {
10
+ calledAfterScheduling = true;
11
+ return;
12
+ }
13
+
14
+ scheduled = true;
15
+
16
+ setTimeout(() => {
17
+ try {
18
+ fn();
19
+ } catch {
20
+ } finally {
21
+ scheduled = false;
22
+
23
+ if (calledAfterScheduling) {
24
+ calledAfterScheduling = false;
25
+ aThrottle();
26
+ }
27
+ }
28
+ }, delayMs());
29
+ };
30
+
31
+ return aThrottle;
32
+ }
33
+
34
+ export function debounceTrailing<T>(fn: () => any, ms: IValue<number>): () => void {
35
+ const delayMs = Value<number>(ms);
36
+
37
+ let timer: any;
38
+
39
+ return () => {
40
+ if (timer) {
41
+ clearTimeout(timer);
42
+ timer = undefined;
43
+ }
44
+
45
+ timer = setTimeout(() => {
46
+ timer = undefined;
47
+ fn();
48
+ }, delayMs());
49
+ };
50
+ }
@@ -0,0 +1,22 @@
1
+ export function UTCDate() {
2
+ const date = new Date();
3
+
4
+ const utc = Date.UTC(
5
+ date.getUTCFullYear(),
6
+ date.getUTCMonth(),
7
+ date.getUTCDate(),
8
+ date.getUTCHours(),
9
+ date.getUTCMinutes(),
10
+ date.getUTCSeconds()
11
+ );
12
+
13
+ return new Date(utc);
14
+ }
15
+
16
+ export function UTCTime() {
17
+ return UTCDate().getTime();
18
+ }
19
+
20
+ export function offsetDate(now: Date, offsetMs: number): Date {
21
+ return new Date(now.getTime() + offsetMs);
22
+ }
@@ -0,0 +1,37 @@
1
+ import { Defer } from './defer';
2
+
3
+ export type MayBeAsync<Type = any> = Type | Promise<Type>;
4
+
5
+ type ITimedFallback<Target = any, Fallback = any> = (
6
+ resolver: () => MayBeAsync<Target>
7
+ ) => Promise<Target | Fallback>;
8
+
9
+ export function TimedFallback<Target, Fallback = Target>(
10
+ timeout: number,
11
+ fallback: () => MayBeAsync<Fallback>
12
+ ): ITimedFallback<Target, Fallback> {
13
+ return async (resolver: () => MayBeAsync<Target>) => {
14
+ const defer = Defer<Target | Fallback>();
15
+
16
+ const timerRef = setTimeout(async function () {
17
+ try {
18
+ defer.resolve(await fallback());
19
+ } catch (error) {
20
+ defer.reject(error);
21
+ }
22
+ }, timeout);
23
+
24
+ setTimeout(async () => {
25
+ try {
26
+ const result = await resolver();
27
+ clearTimeout(timerRef);
28
+ defer.resolve(result);
29
+ } catch (error) {
30
+ clearTimeout(timerRef);
31
+ defer.reject(error);
32
+ }
33
+ }, 0);
34
+
35
+ return defer.promise;
36
+ };
37
+ }
@@ -0,0 +1,30 @@
1
+ export type ITimerInterface = {
2
+ start(fn: () => any): void;
3
+ stop(): void;
4
+ };
5
+
6
+ export function Timer(timeout: number | undefined | null): ITimerInterface {
7
+ let ref: any;
8
+
9
+ function start(fn: () => any) {
10
+ if (ref) {
11
+ stop();
12
+ }
13
+
14
+ if (Number.isInteger(timeout)) {
15
+ ref = setTimeout(fn, timeout!);
16
+ }
17
+ }
18
+
19
+ function stop() {
20
+ if (ref) {
21
+ clearTimeout(ref);
22
+ }
23
+ ref = null;
24
+ }
25
+
26
+ return {
27
+ start,
28
+ stop,
29
+ };
30
+ }
@@ -0,0 +1,33 @@
1
+ import { ISyncPubSub, SyncPubSub } from './pubsub';
2
+
3
+ const ValueSymbol = Symbol('ValueSymbol');
4
+ type IValueSymbol = typeof ValueSymbol;
5
+
6
+ export type IValueInstance<T> = ((value?: T | IValueSymbol) => T) & {
7
+ subscribe: ISyncPubSub<T>['subscribe'];
8
+ };
9
+
10
+ export type IValue<T> = T | IValueInstance<T>;
11
+
12
+ export function Value<T>(defaults: T | Function | IValueInstance<T>): IValueInstance<T> {
13
+ if (defaults instanceof Function) {
14
+ return defaults as IValueInstance<T>;
15
+ }
16
+
17
+ let value: T = defaults as T;
18
+
19
+ const topic = SyncPubSub<T>();
20
+
21
+ const valueInstance = (_value: T | IValueSymbol = ValueSymbol) => {
22
+ if (_value !== ValueSymbol) {
23
+ value = _value;
24
+ topic.publish(value);
25
+ }
26
+
27
+ return value;
28
+ };
29
+
30
+ valueInstance.subscribe = topic.subscribe;
31
+
32
+ return valueInstance;
33
+ }
@@ -0,0 +1,15 @@
1
+ import { ICounter } from './counter';
2
+ import { waitForMessage } from './pubsub';
3
+
4
+ export async function waitForCounter(
5
+ counter: ICounter,
6
+ isTrue: (counter: ICounter) => boolean
7
+ ): Promise<void> {
8
+ if (!isTrue(counter)) {
9
+ await waitForMessage(counter.subscribe, () => isTrue(counter));
10
+ }
11
+ }
12
+
13
+ export async function waitForZeroCounter(counter: ICounter) {
14
+ return waitForCounter(counter, counter => counter.value() <= 0);
15
+ }
@@ -0,0 +1,23 @@
1
+ import { StreamX, StreamXMapper } from './index';
2
+
3
+ export function batch<Input>(size: number): StreamXMapper<Input, Input[]> {
4
+ let batched: Input[] = [];
5
+ return inputStream =>
6
+ (async function* batchedStream(): StreamX<Input[]> {
7
+ for await (const record of inputStream) {
8
+ batched.push(record);
9
+
10
+ if (batched.length >= size) {
11
+ const toEmit = batched;
12
+ batched = [];
13
+ yield toEmit;
14
+ }
15
+ }
16
+
17
+ if (batched.length) {
18
+ const toEmit = batched;
19
+ batched = [];
20
+ yield toEmit;
21
+ }
22
+ })();
23
+ }
@@ -0,0 +1,113 @@
1
+ import { StreamXMapper } from './index';
2
+ import { IRead, read } from './reader';
3
+ import { IWriter, Writer } from './writer';
4
+ import { syncTick } from '@handy/fun/tick';
5
+ import { clearTimeout } from 'timers';
6
+
7
+ type Milliseconds = number;
8
+
9
+ export function batchTimed<Input>(
10
+ size: number,
11
+ maxTimeout: Milliseconds
12
+ ): StreamXMapper<Input, Input[]> {
13
+ let outputBuffer: IWriter<Input[]>;
14
+ let readInput: IRead<Input>;
15
+ let readOutput: IRead<Input[]>;
16
+ let _error: Error | undefined = undefined;
17
+ let batch: Input[] = [];
18
+ let flushTimeout: any;
19
+
20
+ async function finish() {
21
+ await flush();
22
+ if (outputBuffer) {
23
+ await outputBuffer.finish();
24
+ }
25
+ }
26
+
27
+ async function flush() {
28
+ if (outputBuffer) {
29
+ if (batch.length) {
30
+ const currentBatch: Input[] = [...batch];
31
+ batch = [];
32
+ await outputBuffer.write(currentBatch);
33
+ }
34
+ }
35
+ }
36
+
37
+ function clearFlushTimeout() {
38
+ if (flushTimeout) {
39
+ clearTimeout(flushTimeout);
40
+ flushTimeout = null;
41
+ }
42
+ }
43
+
44
+ return inputStream => {
45
+ return {
46
+ [Symbol.asyncIterator](): AsyncIterator<Input[]> {
47
+ return {
48
+ async next(): Promise<IteratorResult<Input[]>> {
49
+ if (_error) {
50
+ throw _error;
51
+ }
52
+
53
+ if (!readInput) {
54
+ readInput = read<Input>(inputStream);
55
+ }
56
+
57
+ if (!outputBuffer) {
58
+ outputBuffer = Writer<Input[]>();
59
+ syncTick(async () => {
60
+ while (true) {
61
+ try {
62
+ const inputValue = await readInput();
63
+ if (inputValue === read.DONE) {
64
+ // process finished
65
+ await finish();
66
+ break;
67
+ } else {
68
+ // new incoming data
69
+ batch.push(inputValue);
70
+
71
+ clearFlushTimeout();
72
+
73
+ flushTimeout = setTimeout(async () => {
74
+ try {
75
+ await flush();
76
+ } catch (error) {
77
+ _error = error as Error;
78
+ }
79
+ }, maxTimeout);
80
+
81
+ if (batch.length >= size) {
82
+ await flush();
83
+ }
84
+ }
85
+ } catch (error) {
86
+ _error = error as Error;
87
+ await finish();
88
+ }
89
+ }
90
+ });
91
+ }
92
+
93
+ if (!readOutput) {
94
+ readOutput = read<Input[]>(outputBuffer.stream);
95
+ }
96
+
97
+ const output = await readOutput();
98
+
99
+ if (_error) {
100
+ throw _error;
101
+ }
102
+
103
+ if (output === read.DONE) {
104
+ return { done: true, value: undefined };
105
+ } else {
106
+ return { done: false, value: output };
107
+ }
108
+ },
109
+ };
110
+ },
111
+ };
112
+ };
113
+ }
@@ -0,0 +1,72 @@
1
+ import { StreamX, StreamXMapper } from './index';
2
+ import { IRead, read } from './reader';
3
+ import { IWriter, Writer } from './writer';
4
+ import { syncTick } from '@handy/fun/tick';
5
+
6
+ export function buffer<Input>(size: number): StreamXMapper<Input, Input> {
7
+ let outputBuffer: IWriter<Input>;
8
+ let readInput: IRead<Input>;
9
+ let readOutput: IRead<Input>;
10
+ let _error: Error | undefined = undefined;
11
+
12
+ async function finish() {
13
+ if (outputBuffer) {
14
+ await outputBuffer.finish();
15
+ }
16
+ }
17
+
18
+ return (inputStream: StreamX<Input>) => {
19
+ return {
20
+ [Symbol.asyncIterator](): AsyncIterator<Input> {
21
+ return {
22
+ async next(): Promise<IteratorResult<Input>> {
23
+ if (_error) {
24
+ throw _error;
25
+ }
26
+
27
+ if (!readInput) {
28
+ readInput = read<Input>(inputStream);
29
+ }
30
+
31
+ if (!outputBuffer) {
32
+ outputBuffer = Writer<Input>(size);
33
+
34
+ syncTick(async () => {
35
+ while (true) {
36
+ try {
37
+ const inputValue = await readInput();
38
+ if (inputValue === read.DONE) {
39
+ await finish();
40
+ break;
41
+ } else {
42
+ await outputBuffer.write(inputValue);
43
+ }
44
+ } catch (error) {
45
+ _error = error as Error;
46
+ await finish();
47
+ }
48
+ }
49
+ });
50
+ }
51
+
52
+ if (!readOutput) {
53
+ readOutput = read<Input>(outputBuffer.stream);
54
+ }
55
+
56
+ const output = await readOutput();
57
+
58
+ if (_error) {
59
+ throw _error;
60
+ }
61
+
62
+ if (output === read.DONE) {
63
+ return { done: true, value: undefined };
64
+ } else {
65
+ return { done: false, value: output };
66
+ }
67
+ },
68
+ };
69
+ },
70
+ };
71
+ };
72
+ }
@@ -0,0 +1,33 @@
1
+ import { StreamX } from './index';
2
+
3
+ export function concatenate<T>(...streams: StreamX<T>[]): StreamX<T>;
4
+
5
+ export function concatenate<T1, T2, T3, T4, T5>(
6
+ stream1: StreamX<T1>,
7
+ stream2: StreamX<T2>,
8
+ stream3: StreamX<T3>,
9
+ stream4: StreamX<T4>,
10
+ stream5: StreamX<T5>
11
+ ): StreamX<T1 | T2 | T3 | T4 | T5>;
12
+ export function concatenate<T1, T2, T3, T4>(
13
+ stream1: StreamX<T1>,
14
+ stream2: StreamX<T2>,
15
+ stream3: StreamX<T3>,
16
+ stream4: StreamX<T4>
17
+ ): StreamX<T1 | T2 | T3 | T4>;
18
+ export function concatenate<T1, T2, T3>(
19
+ stream1: StreamX<T1>,
20
+ stream2: StreamX<T2>,
21
+ stream3: StreamX<T3>
22
+ ): StreamX<T1 | T2 | T3>;
23
+ export function concatenate<T1, T2>(
24
+ stream1: StreamX<T1>,
25
+ stream2: StreamX<T2>
26
+ ): StreamX<T1 | T2>;
27
+ export function concatenate<T>(...streams: StreamX<any>[]): StreamX<T> {
28
+ return (async function* concatenateStreams(): StreamX<T> {
29
+ for await (const stream of streams) {
30
+ yield* stream;
31
+ }
32
+ })();
33
+ }
@@ -0,0 +1,14 @@
1
+ import { Promised, StreamX, StreamXMapper } from './index';
2
+
3
+ export function filter<Input>(
4
+ condition: (input: Input) => Promised<boolean | undefined | null>
5
+ ): StreamXMapper<Input, Input> {
6
+ return inputStream =>
7
+ (async function* filtered(): StreamX<Input> {
8
+ for await (const record of inputStream) {
9
+ if (await condition(record)) {
10
+ yield record;
11
+ }
12
+ }
13
+ })();
14
+ }
@@ -0,0 +1,19 @@
1
+ import { StreamX, StreamXLike, StreamXMapper } from './index';
2
+
3
+ export function flat<Type>(): StreamXMapper<Type | StreamXLike<Type>, Type> {
4
+ return inputStream =>
5
+ (async function* flatStream(): StreamX<Type> {
6
+ for await (const record of inputStream) {
7
+ if (
8
+ record instanceof Object &&
9
+ (Array.isArray(record) || Symbol.iterator in record || Symbol.asyncIterator in record)
10
+ ) {
11
+ for await (const element of record) {
12
+ yield element;
13
+ }
14
+ } else {
15
+ yield record;
16
+ }
17
+ }
18
+ })();
19
+ }
@@ -0,0 +1,9 @@
1
+ import { flat } from './flat';
2
+ import { map } from './map';
3
+ import { pipe, Promised, StreamXLike, StreamXMapper } from './index';
4
+
5
+ export function flatMap<Input, Output>(
6
+ mapper: (input: Input) => Promised<Output | StreamXLike<Output>>
7
+ ): StreamXMapper<Input, Output> {
8
+ return pipe(map(mapper)).pipe(flat());
9
+ }
@@ -0,0 +1,30 @@
1
+ import { of, StreamX, StreamXLike, StreamXOf } from './index';
2
+
3
+ export function isStreamXLike(stream: any): stream is StreamXLike<any> {
4
+ return (
5
+ stream != null &&
6
+ ((stream instanceof Object && Symbol.asyncIterator in stream) ||
7
+ (stream instanceof Object && Symbol.iterator in stream))
8
+ );
9
+ }
10
+
11
+ export function toStreamX<Input>(stream: StreamXLike<Input>): StreamX<Input> {
12
+ if (stream instanceof Object && Symbol.asyncIterator in stream) {
13
+ return stream;
14
+ } else if (stream instanceof Object && Symbol.iterator in stream) {
15
+ return {
16
+ [Symbol.asyncIterator]: () => {
17
+ const syncIterator = stream[Symbol.iterator]();
18
+ return {
19
+ next: async () => syncIterator.next(),
20
+ };
21
+ },
22
+ };
23
+ } else {
24
+ throw new Error(`${typeof stream}, is not iterable`);
25
+ }
26
+ }
27
+
28
+ export function from<Input>(streamLike: StreamXLike<Input>): StreamXOf<Input> {
29
+ return of(toStreamX<Input>(streamLike));
30
+ }
@@ -0,0 +1,49 @@
1
+ // types
2
+
3
+ export type StreamX<Type> = AsyncIterable<Type>;
4
+ export type StreamXOf<Input> = StreamX<Input> & {
5
+ pipe<Output>(mapper: StreamXMapper<Input, Output>): StreamXOf<Output>;
6
+ };
7
+ export type StreamXLike<Type> = AsyncIterable<Type> | Iterable<Type> | Type[];
8
+ export type StreamXMapper<Input, Output> = (
9
+ stream: StreamX<Input>
10
+ ) => StreamX<Output>;
11
+ export type Promised<Type> = Type | Promise<Type>;
12
+
13
+ export type StreamXPlumber<In, Out> = StreamXMapper<In, Out> & {
14
+ pipe<Output>(mapper: StreamXMapper<Out, Output>): StreamXPlumber<In, Output>;
15
+ };
16
+
17
+ // of
18
+ export function of<Input>(inputStream: StreamX<Input>): StreamXOf<Input> {
19
+ return {
20
+ [Symbol.asyncIterator]: () => inputStream[Symbol.asyncIterator](),
21
+ pipe<Output>(mapper: StreamXMapper<Input, Output>): StreamXOf<Output> {
22
+ return of(mapper(inputStream));
23
+ },
24
+ };
25
+ }
26
+
27
+ export function pipe<In, Out>(mapper: StreamXMapper<In, Out>): StreamXPlumber<In, Out> {
28
+ const streamMapper: StreamXMapper<In, Out> = (input: StreamX<In>) => mapper(input);
29
+
30
+ // @ts-ignore
31
+ streamMapper.pipe = <Output>(mapper: StreamXMapper<Out, Output>) => {
32
+ return pipe<In, Output>((input: StreamX<In>) => {
33
+ const nextStream = streamMapper(input);
34
+ return mapper(nextStream);
35
+ });
36
+ };
37
+ return streamMapper as StreamXPlumber<In, Out>;
38
+ }
39
+
40
+ export async function run<Type, Default = undefined>(
41
+ stream: StreamX<Type>,
42
+ defaultValue = undefined as Default
43
+ ): Promise<Type | Default> {
44
+ let value: Type | Default = defaultValue;
45
+ for await (const record of stream) {
46
+ value = record;
47
+ }
48
+ return value;
49
+ }