@sawa-siemens/socket.io-stream 0.10.1 → 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.
@@ -0,0 +1,34 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [master, main]
6
+ pull_request:
7
+ branches: [master, main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [18.x, 20.x, 22.x]
16
+
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js ${{ matrix.node-version }}
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: ${{ matrix.node-version }}
25
+ cache: 'npm'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci
29
+
30
+ - name: Run tests
31
+ run: npm test
32
+
33
+ - name: Build
34
+ run: npm run build
package/README.md CHANGED
@@ -1,13 +1,17 @@
1
- # Socket.IO stream
1
+ # @sawa-siemens/socket.io-stream
2
2
 
3
- [![Build Status](https://travis-ci.org/nkzawa/socket.io-stream.png?branch=master)](https://travis-ci.org/nkzawa/socket.io-stream)
4
- [![NPM version](https://badge.fury.io/js/socket.io-stream.png)](http://badge.fury.io/js/socket.io-stream)
3
+ [![Tests](https://github.com/sawa-siemens/socket.io-stream/actions/workflows/test.yml/badge.svg)](https://github.com/sawa-siemens/socket.io-stream/actions/workflows/test.yml)
4
+ [![NPM version](https://img.shields.io/npm/v/%40sawa-siemens%2Fsocket.io-stream?style=flat-square&color=%23099)](https://www.npmjs.com/package/@sawa-siemens/socket.io-stream)
5
5
 
6
- This is the module for bidirectional binary data transfer with Stream API through [Socket.IO](https://github.com/socketio/socket.io).
6
+ This is the module for bidirectional binary data transfer with Stream API through [Socket.IO](https://github.com/socketio/socket.io).
7
+ 🚨 The purpose of fork @sawa-siemens/socket-io.stream:
8
+
9
+ 1. Add support for Typescript type interface
10
+ 2. Original package is lack of maintenance in security auditing. Aim at free npm audit vulnerabilities for it's dependency.
7
11
 
8
12
  ## Installation
9
13
 
10
- npm install socket.io-stream
14
+ npm install @sawa-siemens/socket.io-stream
11
15
 
12
16
  ## Usage
13
17
 
@@ -20,12 +24,12 @@ To receive streams, you just wrap `socket` with `socket.io-stream`, then listen
20
24
  Server:
21
25
 
22
26
  ```js
23
- var io = require('socket.io').listen(80);
24
- var ss = require('socket.io-stream');
25
- var path = require('path');
27
+ var io = require("socket.io").listen(80);
28
+ var ss = require("@sawa-siemens/socket.io-stream");
29
+ var path = require("path");
26
30
 
27
- io.of('/user').on('connection', function(socket) {
28
- ss(socket).on('profile-image', function(stream, data) {
31
+ io.of("/user").on("connection", function (socket) {
32
+ ss(socket).on("profile-image", function (stream, data) {
29
33
  var filename = path.basename(data.name);
30
34
  stream.pipe(fs.createWriteStream(filename));
31
35
  });
@@ -37,14 +41,14 @@ io.of('/user').on('connection', function(socket) {
37
41
  Client:
38
42
 
39
43
  ```js
40
- var io = require('socket.io-client');
41
- var ss = require('socket.io-stream');
44
+ var io = require("socket.io-client");
45
+ var ss = require("@sawa-siemens/socket.io-stream");
42
46
 
43
- var socket = io.connect('http://example.com/user');
47
+ var socket = io.connect("http://example.com/user");
44
48
  var stream = ss.createStream();
45
- var filename = 'profile.jpg';
49
+ var filename = "profile.jpg";
46
50
 
47
- ss(socket).emit('profile-image', stream, {name: filename});
51
+ ss(socket).emit("profile-image", stream, { name: filename });
48
52
  fs.createReadStream(filename).pipe(stream);
49
53
  ```
50
54
 
@@ -52,25 +56,34 @@ You can stream data from a client to server, and vice versa.
52
56
 
53
57
  ```js
54
58
  // send data
55
- ss(socket).on('file', function(stream) {
56
- fs.createReadStream('/path/to/file').pipe(stream);
59
+ ss(socket).on("file", function (stream) {
60
+ fs.createReadStream("/path/to/file").pipe(stream);
57
61
  });
58
62
 
59
63
  // receive data
60
- ss(socket).emit('file', stream);
61
- stream.pipe(fs.createWriteStream('file.txt'));
64
+ ss(socket).emit("file", stream);
65
+ stream.pipe(fs.createWriteStream("file.txt"));
66
+ ```
67
+
68
+ ## Support ESM import style
69
+
70
+ ```js
71
+ import ss from "@sawa-siemens/socket.io-stream";
72
+ // ...
73
+ const stream = ss.createStream({ highWaterMark: 512 * 1024 });
74
+ //...
62
75
  ```
63
76
 
64
77
  ### Browser
65
78
 
66
79
  This module can be used on the browser. To do so, just copy a file to a public directory.
67
80
 
68
- $ cp node_modules/socket.io-stream/socket.io-stream.js somewhere/public/
81
+ $ cp node_modules/@sawa-siemens/socket.io-stream/socket.io-stream.js somewhere/public/
69
82
 
70
83
  You can also use [browserify](http://github.com/substack/node-browserify) to create your own bundle.
71
84
 
72
85
  $ npm install browserify -g
73
- $ cd node_modules/socket.io-stream
86
+ $ cd node_modules/@sawa-siemens/socket.io-stream
74
87
  $ browserify index.js -s ss > socket.io-stream.js
75
88
 
76
89
  ```html
@@ -80,18 +93,18 @@ You can also use [browserify](http://github.com/substack/node-browserify) to cre
80
93
  <script src="/js/socket.io-stream.js"></script>
81
94
  <script src="/js/jquery.js"></script>
82
95
  <script>
83
- $(function() {
84
- var socket = io.connect('/foo');
96
+ $(function () {
97
+ var socket = io.connect("/foo");
85
98
 
86
- $('#file').change(function(e) {
87
- var file = e.target.files[0];
88
- var stream = ss.createStream();
99
+ $("#file").change(function (e) {
100
+ var file = e.target.files[0];
101
+ var stream = ss.createStream();
89
102
 
90
- // upload a file to the server.
91
- ss(socket).emit('file', stream, {size: file.size});
92
- ss.createBlobReadStream(file).pipe(stream);
103
+ // upload a file to the server.
104
+ ss(socket).emit("file", stream, { size: file.size });
105
+ ss.createBlobReadStream(file).pipe(stream);
106
+ });
93
107
  });
94
- });
95
108
  </script>
96
109
  ```
97
110
 
@@ -103,9 +116,9 @@ You can track upload progress like the following:
103
116
  var blobStream = ss.createBlobReadStream(file);
104
117
  var size = 0;
105
118
 
106
- blobStream.on('data', function(chunk) {
119
+ blobStream.on("data", function (chunk) {
107
120
  size += chunk.length;
108
- console.log(Math.floor(size / file.size * 100) + '%');
121
+ console.log(Math.floor((size / file.size) * 100) + "%");
109
122
  // -> e.g. '42%'
110
123
  });
111
124
 
@@ -120,7 +133,6 @@ You have to set `forceBase64` option `true` when using the library with socket.i
120
133
  ss.forceBase64 = true;
121
134
  ```
122
135
 
123
-
124
136
  ## Documentation
125
137
 
126
138
  ### ss(sio)
@@ -171,11 +183,11 @@ ss(socket).on('foo', function(stream) {
171
183
  ### ss.createStream([options])
172
184
 
173
185
  - options `Object`
174
- - highWaterMark `Number`
175
- - encoding `String`
176
- - decodeStrings `Boolean`
177
- - objectMode `Boolean`
178
- - allowHalfOpen `Boolean` if `true`, then the stream won't automatically close when the other endpoint ends. Default to `false`.
186
+ - highWaterMark `Number`
187
+ - encoding `String`
188
+ - decodeStrings `Boolean`
189
+ - objectMode `Boolean`
190
+ - allowHalfOpen `Boolean` if `true`, then the stream won't automatically close when the other endpoint ends. Default to `false`.
179
191
  - return `Duplex Stream`
180
192
 
181
193
  Create a new duplex stream. See [the docs](http://nodejs.org/api/stream.html) for the details of stream and `options`.
@@ -187,16 +199,16 @@ var stream = ss.createStream();
187
199
  var stream = ss.createStream({
188
200
  highWaterMark: 1024,
189
201
  objectMode: true,
190
- allowHalfOpen: true
202
+ allowHalfOpen: true,
191
203
  });
192
204
  ```
193
205
 
194
206
  ### ss.createBlobReadStream(blob, [options])
195
207
 
196
208
  - options `Object`
197
- - highWaterMark `Number`
198
- - encoding `String`
199
- - objectMode `Boolean`
209
+ - highWaterMark `Number`
210
+ - encoding `String`
211
+ - objectMode `Boolean`
200
212
  - return `Readable Stream`
201
213
 
202
214
  Create a new readable stream for [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [File](https://developer.mozilla.org/en-US/docs/Web/API/File) on browser. See [the docs](http://nodejs.org/api/stream.html) for the details of stream and `options`.
@@ -0,0 +1,29 @@
1
+ const esbuild = require('esbuild');
2
+ const { polyfillNode } = require('esbuild-plugin-polyfill-node');
3
+
4
+ esbuild.build({
5
+ entryPoints: ['index.js'],
6
+ bundle: true,
7
+ minify: true,
8
+ globalName: 'ss',
9
+ platform: 'browser',
10
+ target: 'es2018',
11
+ outfile: 'socket.io-stream.js',
12
+ plugins: [
13
+ polyfillNode({
14
+ // Polyfills needed for this library
15
+ polyfills: {
16
+ util: true,
17
+ events: true,
18
+ buffer: true,
19
+ stream: true,
20
+ crypto: true,
21
+ },
22
+ }),
23
+ ],
24
+ }).then(() => {
25
+ console.log('Build complete: socket.io-stream.js');
26
+ }).catch((err) => {
27
+ console.error('Build failed:', err);
28
+ process.exit(1);
29
+ });
package/lib/iostream.js CHANGED
@@ -184,6 +184,39 @@ IOStream.prototype._done = function() {
184
184
  return this.push(null);
185
185
  };
186
186
 
187
+ /**
188
+ * Helper to check if readable side has ended.
189
+ * Uses public API (readableEnded) with fallback to internal state for compatibility.
190
+ *
191
+ * @api private
192
+ */
193
+ IOStream.prototype._isReadableEnded = function() {
194
+ // Use public API if available (readable-stream v3.6+, v4.x, Node.js 12.9+)
195
+ if (typeof this.readableEnded === 'boolean') {
196
+ return this.readableEnded;
197
+ }
198
+ // Fallback to internal state
199
+ return this._readableState && this._readableState.ended;
200
+ };
201
+
202
+ /**
203
+ * Helper to check if writable side has finished.
204
+ * Uses public API (writableFinished/writableEnded) with fallback to internal state.
205
+ *
206
+ * @api private
207
+ */
208
+ IOStream.prototype._isWritableFinished = function() {
209
+ // Use public API if available (readable-stream v3.6+, v4.x, Node.js 12.9+)
210
+ if (typeof this.writableFinished === 'boolean') {
211
+ return this.writableFinished;
212
+ }
213
+ if (typeof this.writableEnded === 'boolean') {
214
+ return this.writableEnded;
215
+ }
216
+ // Fallback to internal state
217
+ return this._writableState && this._writableState.finished;
218
+ };
219
+
187
220
  /**
188
221
  * the user has called .end(), and all the bytes have been
189
222
  * sent out to the other side.
@@ -203,10 +236,12 @@ IOStream.prototype._onfinish = function() {
203
236
  }
204
237
 
205
238
  this.writable = false;
206
- this._writableState.ended = true;
239
+ if (this._writableState) {
240
+ this._writableState.ended = true;
241
+ }
207
242
 
208
- if (!this.readable || this._readableState.ended) {
209
- debug('_onfinish: ended, destroy %s', this._readableState);
243
+ if (!this.readable || this._isReadableEnded()) {
244
+ debug('_onfinish: ended, destroy');
210
245
  return this.destroy();
211
246
  }
212
247
 
@@ -216,7 +251,8 @@ IOStream.prototype._onfinish = function() {
216
251
  this.push(null);
217
252
 
218
253
  // just in case we're waiting for an EOF.
219
- if (this.readable && !this._readableState.endEmitted) {
254
+ var endEmitted = this._readableState && this._readableState.endEmitted;
255
+ if (this.readable && !endEmitted) {
220
256
  this.read(0);
221
257
  }
222
258
  }
@@ -232,17 +268,24 @@ IOStream.prototype._onfinish = function() {
232
268
  IOStream.prototype._onend = function() {
233
269
  debug('_onend');
234
270
  this.readable = false;
235
- this._readableState.ended = true;
271
+ if (this._readableState) {
272
+ this._readableState.ended = true;
273
+ }
236
274
 
237
- if (!this.writable || this._writableState.finished) {
238
- debug('_onend: %s', this._writableState);
275
+ if (!this.writable || this._isWritableFinished()) {
276
+ debug('_onend: finished, destroy');
239
277
  return this.destroy();
240
278
  }
241
279
 
242
280
  debug('_onend: not finished');
243
281
 
244
282
  if (!this.allowHalfOpen) {
283
+ // When allowHalfOpen is false, we should clean up immediately
284
+ // after the readable side ends. Call end() to signal writable end,
285
+ // then destroy to clean up. This ensures synchronous cleanup
286
+ // which is expected by the tests and maintains v3.x behavior.
245
287
  this.end();
288
+ return this.destroy();
246
289
  }
247
290
  };
248
291
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sawa-siemens/socket.io-stream",
3
- "version": "0.10.1",
3
+ "version": "1.0.0",
4
4
  "description": "stream for socket.io",
5
5
  "author": "Naoyuki Kanezawa <naoyuki.kanezawa@gmail.com>",
6
6
  "contributors": [
@@ -37,24 +37,28 @@
37
37
  "./package.json": "./package.json"
38
38
  },
39
39
  "engines": {
40
- "node": ">=0.10.0"
40
+ "node": ">=18.0.0"
41
41
  },
42
42
  "repository": {
43
43
  "type": "git",
44
- "url": "https://github.com/sawa-siemens/socket.io-stream.git"
44
+ "url": "git+https://github.com/sawa-siemens/socket.io-stream.git"
45
45
  },
46
46
  "scripts": {
47
- "prepublish": "make build",
48
- "test": "make test"
47
+ "build": "node esbuild.config.js",
48
+ "prepare": "npm run build",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest"
49
51
  },
50
52
  "dependencies": {
51
53
  "component-bind": "~1.0.0",
52
- "debug": "^4.3.4"
54
+ "debug": "^4.3.4",
55
+ "readable-stream": "^4.5.2"
53
56
  },
54
57
  "devDependencies": {
55
- "browserify": "^17.0.0",
56
- "expect.js": "~0.3.1",
58
+ "esbuild": "^0.27.2",
59
+ "esbuild-plugin-polyfill-node": "^0.3.0",
57
60
  "socket.io": "^4.8.3",
58
- "socket.io-client": "^4.8.3"
61
+ "socket.io-client": "^4.8.3",
62
+ "vitest": "^3.0.4"
59
63
  }
60
64
  }