@lsdsoftware/utils 1.0.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # Useful JavaScript utilities
2
2
 
3
3
 
4
- ## State Machine
4
+ ### State Machine
5
5
  Make implementing state machines less error prone.
6
6
 
7
7
  ```typescript
@@ -48,12 +48,36 @@ sm.getState() //BUSY
48
48
 
49
49
 
50
50
 
51
- ## Message Dispatcher
52
- Dispatch messages to handlers. This utility assumes messages are one of three types: request, response, or notification, and follow a predefined format (see type definition below).
51
+ ### Message Dispatcher
52
+ Dispatch messages to handlers. This utility assumes messages are one of three types: request, response, or notification; and follow a predefined format (see type definition below).
53
53
 
54
- Requests and notifications are dispatched to provided request handlers, and responses are generated from their return values. Responses are dispatched to response listeners. The caller registers a response listener by calling the waitForResponse method, which returns a promise.
54
+ ```typescript
55
+ interface Request {
56
+ to: string
57
+ type: "request"
58
+ id: "string"
59
+ method: string
60
+ args: Record<string, unknown>
61
+ }
55
62
 
56
- When constructing a dispatcher, caller provides a _myAddress_ parameter used to filter messages. Only requests and notifications whose _to_ attribute matches _myAddress_ will be processed.
63
+ interface Notification {
64
+ to: string
65
+ type: "notification"
66
+ method: string
67
+ args: Record<string, unknown>
68
+ }
69
+
70
+ interface Response {
71
+ type: "response"
72
+ id: string
73
+ error: unknown
74
+ result: unknown
75
+ }
76
+ ```
77
+
78
+ Call `dispatch` to dispatch a message you received. Requests and notifications are dispatched to request handlers that you provide at construction. Responses are dispatched to response listeners; to listen for a response, call `waitForResponse` with the request ID.
79
+
80
+ A _myAddress_ parameter provided at construction is used to filter messages. Only requests and notifications whose _to_ attribute matches _myAddress_ will be processed.
57
81
 
58
82
  ```typescript
59
83
  import { makeMessageDispatcher } from "@lsdsoftware/utils"
@@ -91,7 +115,7 @@ dispatcher.waitForResponse(id)
91
115
 
92
116
 
93
117
 
94
- ## Rate Limiter
118
+ ### Rate Limiter
95
119
  Basic rate limiter using the token bucket algorithm.
96
120
 
97
121
  ```typescript
@@ -107,7 +131,7 @@ function handleRequest(userId, req) {
107
131
 
108
132
 
109
133
 
110
- ## Connection Manager
134
+ ### Connection Manager
111
135
  Takes a connect() method and:
112
136
  - Only call it to create a connection when needed
113
137
  - Automatically retry on failure
@@ -134,16 +158,11 @@ conMgr.shutdown()
134
158
 
135
159
 
136
160
 
137
- ## Line Split Stream
138
- A Transform stream that transforms a byte stream into lines of text (by GPT-4)
161
+ ### Line Reader
162
+ Split text into lines
139
163
 
140
164
  ```typescript
141
- import { makeLineSplitStream } from "@lsdsoftware/utils"
142
-
143
- const splitter = makeLineSplitStream()
144
- splitter.on('data', line => console.log('Received line:', line))
165
+ import { makeLineReader } from "@lsdsoftware/utils"
145
166
 
146
- // Simulating input
147
- splitter.write('This is a line\nThis is another line\nAnd this is a line as well')
148
- splitter.end() // End the stream to see the _flush effect.
167
+ myStream.pipe(makeLineReader(line => console.log(line)))
149
168
  ```
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { makeLineSplitStream } from "./line-split-stream";
1
+ import { makeLineReader } from "./line-reader";
2
2
  import { makeStateMachine } from "./state-machine";
3
3
  import { makeConnectionManager } from "./connection-manager";
4
4
  import { makeMessageDispatcher } from "./message-dispatcher";
5
5
  import { makeRateLimiter } from "./rate-limiter";
6
- export { makeLineSplitStream, makeStateMachine, makeConnectionManager, makeMessageDispatcher, makeRateLimiter, };
6
+ export { makeLineReader, makeStateMachine, makeConnectionManager, makeMessageDispatcher, makeRateLimiter, };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeRateLimiter = exports.makeMessageDispatcher = exports.makeConnectionManager = exports.makeStateMachine = exports.makeLineSplitStream = void 0;
4
- const line_split_stream_1 = require("./line-split-stream");
5
- Object.defineProperty(exports, "makeLineSplitStream", { enumerable: true, get: function () { return line_split_stream_1.makeLineSplitStream; } });
3
+ exports.makeRateLimiter = exports.makeMessageDispatcher = exports.makeConnectionManager = exports.makeStateMachine = exports.makeLineReader = void 0;
4
+ const line_reader_1 = require("./line-reader");
5
+ Object.defineProperty(exports, "makeLineReader", { enumerable: true, get: function () { return line_reader_1.makeLineReader; } });
6
6
  const state_machine_1 = require("./state-machine");
7
7
  Object.defineProperty(exports, "makeStateMachine", { enumerable: true, get: function () { return state_machine_1.makeStateMachine; } });
8
8
  const connection_manager_1 = require("./connection-manager");
@@ -9,10 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const line_split_stream_test_1 = require("./line-split-stream.test");
12
+ const line_reader_test_1 = require("./line-reader.test");
13
13
  const rate_limiter_test_1 = require("./rate-limiter.test");
14
14
  const state_machine_test_1 = require("./state-machine.test");
15
- run(Object.assign(Object.assign(Object.assign({}, line_split_stream_test_1.default), rate_limiter_test_1.default), state_machine_test_1.default))
15
+ run(Object.assign(Object.assign(Object.assign({}, line_reader_test_1.default), rate_limiter_test_1.default), state_machine_test_1.default))
16
16
  .catch(console.error);
17
17
  function run(tests) {
18
18
  return __awaiter(this, void 0, void 0, function* () {
@@ -0,0 +1,3 @@
1
+ /// <reference types="node" />
2
+ import { Writable } from "stream";
3
+ export declare function makeLineReader(lineCallback: (line: string) => void): Writable;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeLineReader = void 0;
4
+ const stream_1 = require("stream");
5
+ const string_decoder_1 = require("string_decoder");
6
+ function makeLineReader(lineCallback) {
7
+ // Buffer for the part of the chunk that doesn't form a complete line.
8
+ let remainder = '';
9
+ const decoder = new string_decoder_1.StringDecoder();
10
+ return new stream_1.Writable({
11
+ //prevent auto-decoding string to Buffer, so processed chunk could be either string or Buffer
12
+ decodeStrings: false,
13
+ write(chunk, encoding, callback) {
14
+ // encoding param here is irrelevant because it applies only to string chunks
15
+ const chunkStr = remainder + decoder.write(chunk);
16
+ const lines = chunkStr.split('\n');
17
+ // Keep the last line in remainder if it doesn't end with a newline character.
18
+ remainder = lines.pop();
19
+ // Push each complete line.
20
+ for (const line of lines)
21
+ lineCallback(line);
22
+ callback();
23
+ },
24
+ final(callback) {
25
+ // When the stream is ending, push any remainder as a line if it's not empty.
26
+ if (remainder)
27
+ lineCallback(remainder);
28
+ callback();
29
+ }
30
+ });
31
+ }
32
+ exports.makeLineReader = makeLineReader;
@@ -9,50 +9,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const line_split_stream_1 = require("./line-split-stream");
12
+ const line_reader_1 = require("./line-reader");
13
13
  const assert = require("assert");
14
14
  exports.default = {
15
15
  lineSplitStream1() {
16
16
  return __awaiter(this, void 0, void 0, function* () {
17
- const splitter = (0, line_split_stream_1.makeLineSplitStream)();
17
+ const lines = [];
18
+ const splitter = (0, line_reader_1.makeLineReader)(line => lines.push(line));
18
19
  splitter.write('This is a line\nThis is another line\nAnd this is a line as well');
19
20
  splitter.end();
20
- const lines = yield new Promise(fulfill => {
21
- let accum = [];
22
- splitter.on('data', line => accum.push(line));
23
- splitter.on('end', () => fulfill(accum));
24
- });
25
- assert(lines[0] == "This is a line\n" &&
26
- lines[1] == "This is another line\n" &&
27
- lines[2] == "And this is a line as well\n");
21
+ assert(lines[0] == "This is a line" &&
22
+ lines[1] == "This is another line" &&
23
+ lines[2] == "And this is a line as well");
28
24
  });
29
25
  },
30
26
  lineSplitStream2() {
31
27
  return __awaiter(this, void 0, void 0, function* () {
32
- const splitter = (0, line_split_stream_1.makeLineSplitStream)();
28
+ const lines = [];
29
+ const splitter = (0, line_reader_1.makeLineReader)(line => lines.push(line));
33
30
  splitter.write('\nThis is a line\n');
34
31
  splitter.end();
35
- const lines = yield new Promise(fulfill => {
36
- let accum = [];
37
- splitter.on('data', line => accum.push(line));
38
- splitter.on('end', () => fulfill(accum));
39
- });
40
- assert(lines[0] == "\n" &&
41
- lines[1] == "This is a line\n");
32
+ assert(lines[0] == "" &&
33
+ lines[1] == "This is a line");
42
34
  });
43
35
  },
44
36
  lineSplitStream3() {
45
37
  return __awaiter(this, void 0, void 0, function* () {
46
- const splitter = (0, line_split_stream_1.makeLineSplitStream)();
38
+ const lines = [];
39
+ const splitter = (0, line_reader_1.makeLineReader)(line => lines.push(line));
47
40
  splitter.write('\n\n');
48
41
  splitter.end();
49
- const lines = yield new Promise(fulfill => {
50
- let accum = [];
51
- splitter.on('data', line => accum.push(line));
52
- splitter.on('end', () => fulfill(accum));
53
- });
54
- assert(lines[0] == "\n" &&
55
- lines[1] == "\n");
42
+ assert(lines[0] == "" &&
43
+ lines[1] == "");
56
44
  });
57
45
  },
58
46
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsdsoftware/utils",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Useful JavaScript utilities",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -1,3 +0,0 @@
1
- /// <reference types="node" />
2
- import { Transform } from "stream";
3
- export declare function makeLineSplitStream(): Transform;
@@ -1,28 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeLineSplitStream = void 0;
4
- const stream_1 = require("stream");
5
- function makeLineSplitStream() {
6
- // Buffer for the part of the chunk that doesn't form a complete line.
7
- let remainder = '';
8
- return new stream_1.Transform({
9
- transform(chunk, encoding, callback) {
10
- // Convert chunk to string and add it to the remainder.
11
- const chunkStr = remainder + chunk.toString();
12
- const lines = chunkStr.split('\n');
13
- // Keep the last line in remainder if it doesn't end with a newline character.
14
- remainder = lines.pop();
15
- // Push each complete line.
16
- for (const line of lines)
17
- this.push(line + '\n');
18
- callback();
19
- },
20
- flush(callback) {
21
- // When the stream is ending, push any remainder as a line if it's not empty.
22
- if (remainder)
23
- this.push(remainder + '\n');
24
- callback();
25
- },
26
- });
27
- }
28
- exports.makeLineSplitStream = makeLineSplitStream;