@centralping/ergo 0.1.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/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/http/accepts.js +69 -0
- package/http/authorization.js +65 -0
- package/http/body.js +311 -0
- package/http/cache-control.js +123 -0
- package/http/compress.js +157 -0
- package/http/cookie.js +39 -0
- package/http/cors.js +79 -0
- package/http/csrf.js +76 -0
- package/http/handler.js +74 -0
- package/http/index.js +13 -0
- package/http/json-api-query.js +53 -0
- package/http/logger.js +167 -0
- package/http/main.js +140 -0
- package/http/precondition.js +53 -0
- package/http/prefer.js +36 -0
- package/http/rate-limit.js +66 -0
- package/http/security-headers.js +62 -0
- package/http/send.js +399 -0
- package/http/timeout.js +47 -0
- package/http/url.js +47 -0
- package/http/validate.js +84 -0
- package/lib/accepts.js +49 -0
- package/lib/attach-instance.js +23 -0
- package/lib/authorization.js +187 -0
- package/lib/body/multiparse.js +173 -0
- package/lib/body/multipart/headers.js +69 -0
- package/lib/body/writer.js +73 -0
- package/lib/cookie/cookie.js +192 -0
- package/lib/cookie/index.js +14 -0
- package/lib/cookie/jar.js +106 -0
- package/lib/cookie/parse.js +101 -0
- package/lib/cors.js +191 -0
- package/lib/csrf.js +96 -0
- package/lib/from-connect.js +69 -0
- package/lib/json-api-query/index.js +25 -0
- package/lib/json-api-query/schema.json +105 -0
- package/lib/json-api-query/validate.js +56 -0
- package/lib/link.js +96 -0
- package/lib/prefer.js +52 -0
- package/lib/query.js +113 -0
- package/lib/rate-limit.js +115 -0
- package/lib/sanitize-quoted-string.js +28 -0
- package/lib/security-headers.js +125 -0
- package/lib/validate.js +80 -0
- package/lib/vary.js +40 -0
- package/package.json +158 -0
- package/types/http/accepts.d.ts +8 -0
- package/types/http/authorization.d.ts +8 -0
- package/types/http/body.d.ts +20 -0
- package/types/http/cache-control.d.ts +16 -0
- package/types/http/compress.d.ts +5 -0
- package/types/http/cookie.d.ts +2 -0
- package/types/http/cors.d.ts +9 -0
- package/types/http/csrf.d.ts +9 -0
- package/types/http/handler.d.ts +2 -0
- package/types/http/index.d.ts +1 -0
- package/types/http/json-api-query.d.ts +2 -0
- package/types/http/logger.d.ts +9 -0
- package/types/http/main.d.ts +142 -0
- package/types/http/precondition.d.ts +44 -0
- package/types/http/prefer.d.ts +2 -0
- package/types/http/rate-limit.d.ts +17 -0
- package/types/http/security-headers.d.ts +10 -0
- package/types/http/send.d.ts +8 -0
- package/types/http/timeout.d.ts +5 -0
- package/types/http/url.d.ts +2 -0
- package/types/http/validate.d.ts +6 -0
- package/types/lib/accepts.d.ts +7 -0
- package/types/lib/attach-instance.d.ts +19 -0
- package/types/lib/authorization.d.ts +6 -0
- package/types/lib/body/multiparse.d.ts +9 -0
- package/types/lib/body/multipart/headers.d.ts +2 -0
- package/types/lib/body/writer.d.ts +2 -0
- package/types/lib/cookie/cookie.d.ts +32 -0
- package/types/lib/cookie/index.d.ts +2 -0
- package/types/lib/cookie/jar.d.ts +8 -0
- package/types/lib/cookie/parse.d.ts +19 -0
- package/types/lib/cors.d.ts +9 -0
- package/types/lib/csrf.d.ts +32 -0
- package/types/lib/from-connect.d.ts +47 -0
- package/types/lib/json-api-query/index.d.ts +123 -0
- package/types/lib/json-api-query/validate.d.ts +5 -0
- package/types/lib/link.d.ts +37 -0
- package/types/lib/prefer.d.ts +36 -0
- package/types/lib/query.d.ts +6 -0
- package/types/lib/rate-limit.d.ts +76 -0
- package/types/lib/sanitize-quoted-string.d.ts +19 -0
- package/types/lib/security-headers.d.ts +24 -0
- package/types/lib/validate.d.ts +16 -0
- package/types/lib/vary.d.ts +17 -0
- package/types/utils/attempt.d.ts +2 -0
- package/types/utils/buffers/index.d.ts +2 -0
- package/types/utils/buffers/match.d.ts +10 -0
- package/types/utils/buffers/split.d.ts +10 -0
- package/types/utils/compose-with.d.ts +40 -0
- package/types/utils/compose.d.ts +83 -0
- package/types/utils/flat-array.d.ts +2 -0
- package/types/utils/get.d.ts +5 -0
- package/types/utils/http-errors.d.ts +22 -0
- package/types/utils/iterables/buffer-split.d.ts +2 -0
- package/types/utils/iterables/chain.d.ts +2 -0
- package/types/utils/iterables/exec-all.d.ts +2 -0
- package/types/utils/iterables/filter.d.ts +2 -0
- package/types/utils/iterables/for-each.d.ts +2 -0
- package/types/utils/iterables/from-stream.d.ts +2 -0
- package/types/utils/iterables/index.d.ts +10 -0
- package/types/utils/iterables/map.d.ts +2 -0
- package/types/utils/iterables/range.d.ts +24 -0
- package/types/utils/iterables/reduce.d.ts +2 -0
- package/types/utils/iterables/take.d.ts +2 -0
- package/types/utils/observables/buffer-split.d.ts +2 -0
- package/types/utils/observables/chain.d.ts +2 -0
- package/types/utils/observables/index.d.ts +4 -0
- package/types/utils/observables/map.d.ts +2 -0
- package/types/utils/observables/take.d.ts +2 -0
- package/types/utils/pick.d.ts +2 -0
- package/types/utils/set.d.ts +2 -0
- package/types/utils/streams/index.d.ts +2 -0
- package/types/utils/streams/meter.d.ts +5 -0
- package/types/utils/streams/tee.d.ts +2 -0
- package/types/utils/type.d.ts +2 -0
- package/utils/attempt.js +37 -0
- package/utils/buffers/index.js +13 -0
- package/utils/buffers/match.js +96 -0
- package/utils/buffers/split.js +55 -0
- package/utils/compose-with.js +232 -0
- package/utils/compose.js +165 -0
- package/utils/flat-array.js +24 -0
- package/utils/get.js +39 -0
- package/utils/http-errors.js +113 -0
- package/utils/iterables/buffer-split.js +117 -0
- package/utils/iterables/chain.js +32 -0
- package/utils/iterables/exec-all.js +42 -0
- package/utils/iterables/filter.js +35 -0
- package/utils/iterables/for-each.js +33 -0
- package/utils/iterables/from-stream.js +29 -0
- package/utils/iterables/index.js +21 -0
- package/utils/iterables/map.js +47 -0
- package/utils/iterables/range.js +34 -0
- package/utils/iterables/reduce.js +43 -0
- package/utils/iterables/take.js +36 -0
- package/utils/observables/buffer-split.js +109 -0
- package/utils/observables/chain.js +33 -0
- package/utils/observables/index.js +19 -0
- package/utils/observables/map.js +34 -0
- package/utils/observables/take.js +40 -0
- package/utils/pick.js +41 -0
- package/utils/set.js +38 -0
- package/utils/streams/index.js +11 -0
- package/utils/streams/meter.js +98 -0
- package/utils/streams/tee.js +84 -0
- package/utils/type.js +47 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Streams utilities barrel export.
|
|
3
|
+
*
|
|
4
|
+
* @module utils/streams
|
|
5
|
+
* @version 0.1.0
|
|
6
|
+
* @since 0.1.0
|
|
7
|
+
* @requires ./meter.js
|
|
8
|
+
* @requires ./tee.js
|
|
9
|
+
*/
|
|
10
|
+
export {default as meter} from './meter.js';
|
|
11
|
+
export {default as tee} from './tee.js';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Byte-counting Transform stream.
|
|
3
|
+
*
|
|
4
|
+
* Passes all data through while counting received bytes. Emits an error if the
|
|
5
|
+
* byte count exceeds `limit` (TooLarge) or diverges from the expected `Content-Length`
|
|
6
|
+
* (InvalidLength). Used by `http/body.js` to enforce size constraints.
|
|
7
|
+
*
|
|
8
|
+
* @module utils/streams/meter
|
|
9
|
+
* @version 0.1.0
|
|
10
|
+
* @since 0.1.0
|
|
11
|
+
* @requires node:stream
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* import {pipeline} from 'node:stream';
|
|
15
|
+
* import meter from 'ergo/utils/streams/meter';
|
|
16
|
+
*
|
|
17
|
+
* const m = meter({limit: 1024 * 1024, expected: 512});
|
|
18
|
+
* pipeline(readable, m, writable, err => {
|
|
19
|
+
* if (!err) console.log('bytes received:', m.bytesRead);
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
import {Transform} from 'node:stream';
|
|
23
|
+
/**
|
|
24
|
+
* Creates a byte-metering Transform stream.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} [options] - Meter configuration
|
|
27
|
+
* @param {number} [options.expected] - Expected byte count (from Content-Length)
|
|
28
|
+
* @param {number} [options.limit=Infinity] - Maximum bytes allowed
|
|
29
|
+
* @returns {import('node:stream').Transform} - Transform with `bytesRead`, `limit`, `expected` properties
|
|
30
|
+
*/
|
|
31
|
+
export default ({expected, limit = Infinity} = {}) =>
|
|
32
|
+
Object.defineProperties(new Transform({transform, final}), {
|
|
33
|
+
limit: {
|
|
34
|
+
value: limit,
|
|
35
|
+
writable: true
|
|
36
|
+
},
|
|
37
|
+
bytesRead: {
|
|
38
|
+
value: 0,
|
|
39
|
+
writable: true
|
|
40
|
+
},
|
|
41
|
+
expected: {
|
|
42
|
+
value: expected,
|
|
43
|
+
writable: true
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Accumulates byte count and emits an error if limits are exceeded.
|
|
49
|
+
*
|
|
50
|
+
* @param {import('node:buffer').Buffer} chunk - Incoming data chunk
|
|
51
|
+
* @param {string} encoding - Encoding (unused for Buffer chunks)
|
|
52
|
+
* @param {function} cb - Node.js Transform callback
|
|
53
|
+
*/
|
|
54
|
+
function transform(chunk, encoding, cb) {
|
|
55
|
+
this.bytesRead += Buffer.byteLength(chunk);
|
|
56
|
+
const err =
|
|
57
|
+
this.bytesRead > this.limit
|
|
58
|
+
? Object.assign(
|
|
59
|
+
new Error(`Body exceeded size limit: [${this.limit}]; received: [${this.bytesRead}]`),
|
|
60
|
+
{
|
|
61
|
+
type: 'TooLarge',
|
|
62
|
+
limit: this.limit,
|
|
63
|
+
length: this.bytesRead
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
: this.expected !== undefined && this.bytesRead > this.expected
|
|
67
|
+
? Object.assign(
|
|
68
|
+
new Error(
|
|
69
|
+
`Body exceeds Content-Length: [${this.expected}]; received: [${this.bytesRead}]`
|
|
70
|
+
),
|
|
71
|
+
{
|
|
72
|
+
type: 'InvalidLength',
|
|
73
|
+
length: this.expected,
|
|
74
|
+
received: this.bytesRead
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
: null;
|
|
78
|
+
|
|
79
|
+
cb(err, chunk);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Validates final byte count against expected Content-Length.
|
|
84
|
+
*
|
|
85
|
+
* @param {function} cb - Node.js Transform callback
|
|
86
|
+
*/
|
|
87
|
+
function final(cb) {
|
|
88
|
+
const err =
|
|
89
|
+
this.expected !== undefined && this.bytesRead !== this.expected
|
|
90
|
+
? Object.assign(new Error('Body does not match Content-Length'), {
|
|
91
|
+
type: 'InvalidLength',
|
|
92
|
+
length: this.expected,
|
|
93
|
+
received: this.bytesRead
|
|
94
|
+
})
|
|
95
|
+
: null;
|
|
96
|
+
|
|
97
|
+
cb(err);
|
|
98
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tee Transform stream for sidecar generator pipelines.
|
|
3
|
+
*
|
|
4
|
+
* Forwards all chunks through a generator's `next()` call, then passes them
|
|
5
|
+
* unchanged to the next stream in the pipeline. Allows intercepting stream data
|
|
6
|
+
* for side-effect processing (hashing, logging, validation) without buffering.
|
|
7
|
+
*
|
|
8
|
+
* If no generator is provided, a no-op generator is used (pure passthrough).
|
|
9
|
+
*
|
|
10
|
+
* @module utils/streams/tee
|
|
11
|
+
* @version 0.1.0
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
* @requires node:stream
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import {pipeline} from 'node:stream';
|
|
17
|
+
* import tee from 'ergo/utils/streams/tee';
|
|
18
|
+
*
|
|
19
|
+
* async function* inspect(gen) {
|
|
20
|
+
* let chunk;
|
|
21
|
+
* while ((chunk = yield) !== undefined) {
|
|
22
|
+
* console.log('chunk size:', chunk.length);
|
|
23
|
+
* gen.next(chunk);
|
|
24
|
+
* }
|
|
25
|
+
* gen.return();
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* pipeline(readable, tee(inspect(sink)), writable, err => {});
|
|
29
|
+
*/
|
|
30
|
+
import {Transform} from 'node:stream';
|
|
31
|
+
|
|
32
|
+
const generatorSym = Symbol('generator');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates a Transform stream that forwards each chunk to a generator as a side channel.
|
|
36
|
+
*
|
|
37
|
+
* @param {Generator} generator - Initialized generator to receive chunks via `.next(chunk)`
|
|
38
|
+
* @returns {import('node:stream').Transform} - Transform stream that passes data through while teeing to the generator
|
|
39
|
+
*/
|
|
40
|
+
export default generator => {
|
|
41
|
+
if (generator === undefined) {
|
|
42
|
+
/* eslint-disable-next-line no-param-reassign */
|
|
43
|
+
generator = (function* () {})();
|
|
44
|
+
generator.next();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return Object.defineProperties(new Transform({transform, final}), {
|
|
48
|
+
[generatorSym]: {
|
|
49
|
+
value: generator
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {import('node:buffer').Buffer} chunk - Incoming data chunk
|
|
56
|
+
* @param {string} encoding - Chunk encoding
|
|
57
|
+
* @param {function} cb - Callback to signal transform completion
|
|
58
|
+
*/
|
|
59
|
+
async function transform(chunk, encoding, cb) {
|
|
60
|
+
let err = null;
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
await this[generatorSym].next(chunk);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
err = e;
|
|
66
|
+
} finally {
|
|
67
|
+
cb(err, chunk);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {function} cb - Callback to signal finalization is complete
|
|
73
|
+
*/
|
|
74
|
+
async function final(cb) {
|
|
75
|
+
let err = null;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
await this[generatorSym].return();
|
|
79
|
+
} catch (e) {
|
|
80
|
+
err = e;
|
|
81
|
+
} finally {
|
|
82
|
+
cb(err);
|
|
83
|
+
}
|
|
84
|
+
}
|
package/utils/type.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Constructor-name-based type detection utility.
|
|
3
|
+
*
|
|
4
|
+
* Returns the constructor name of any value, handling edge cases:
|
|
5
|
+
* - `NaN` — returns `'NaN'` (not `'Number'`)
|
|
6
|
+
* - Anonymous constructors (`name === ''`) — falls back to `Object.prototype.toString`
|
|
7
|
+
* - `null`, `undefined`, primitives without constructors — falls back to `toString`
|
|
8
|
+
*
|
|
9
|
+
* Used throughout Ergo for duck-typing checks (e.g. `type(x) === 'AsyncGeneratorFunction'`).
|
|
10
|
+
*
|
|
11
|
+
* @module utils/type
|
|
12
|
+
* @version 0.1.0
|
|
13
|
+
* @since 0.1.0
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import type from 'ergo/utils/type';
|
|
17
|
+
*
|
|
18
|
+
* type(42) // 'Number'
|
|
19
|
+
* type(NaN) // 'NaN'
|
|
20
|
+
* type(null) // 'Null'
|
|
21
|
+
* type([]) // 'Array'
|
|
22
|
+
* type(async function*(){}) // 'AsyncGeneratorFunction'
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {*} o - Value to inspect
|
|
27
|
+
* @returns {string} - Constructor name (e.g. 'String', 'Array', 'NaN')
|
|
28
|
+
*/
|
|
29
|
+
export default o => {
|
|
30
|
+
// Use a try in the case of `undefined`, `null` or any value that may
|
|
31
|
+
// not have a constructor property
|
|
32
|
+
try {
|
|
33
|
+
const type = o.constructor.name;
|
|
34
|
+
|
|
35
|
+
switch (type) {
|
|
36
|
+
case 'Number':
|
|
37
|
+
// Special Case for NaN
|
|
38
|
+
return Number.isNaN(o) ? 'NaN' : type;
|
|
39
|
+
case '':
|
|
40
|
+
return {}.toString.call(o).slice(8, -1);
|
|
41
|
+
default:
|
|
42
|
+
return type;
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
return {}.toString.call(o).slice(8, -1);
|
|
46
|
+
}
|
|
47
|
+
};
|