@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.
Files changed (155) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +21 -0
  3. package/README.md +139 -0
  4. package/http/accepts.js +69 -0
  5. package/http/authorization.js +65 -0
  6. package/http/body.js +311 -0
  7. package/http/cache-control.js +123 -0
  8. package/http/compress.js +157 -0
  9. package/http/cookie.js +39 -0
  10. package/http/cors.js +79 -0
  11. package/http/csrf.js +76 -0
  12. package/http/handler.js +74 -0
  13. package/http/index.js +13 -0
  14. package/http/json-api-query.js +53 -0
  15. package/http/logger.js +167 -0
  16. package/http/main.js +140 -0
  17. package/http/precondition.js +53 -0
  18. package/http/prefer.js +36 -0
  19. package/http/rate-limit.js +66 -0
  20. package/http/security-headers.js +62 -0
  21. package/http/send.js +399 -0
  22. package/http/timeout.js +47 -0
  23. package/http/url.js +47 -0
  24. package/http/validate.js +84 -0
  25. package/lib/accepts.js +49 -0
  26. package/lib/attach-instance.js +23 -0
  27. package/lib/authorization.js +187 -0
  28. package/lib/body/multiparse.js +173 -0
  29. package/lib/body/multipart/headers.js +69 -0
  30. package/lib/body/writer.js +73 -0
  31. package/lib/cookie/cookie.js +192 -0
  32. package/lib/cookie/index.js +14 -0
  33. package/lib/cookie/jar.js +106 -0
  34. package/lib/cookie/parse.js +101 -0
  35. package/lib/cors.js +191 -0
  36. package/lib/csrf.js +96 -0
  37. package/lib/from-connect.js +69 -0
  38. package/lib/json-api-query/index.js +25 -0
  39. package/lib/json-api-query/schema.json +105 -0
  40. package/lib/json-api-query/validate.js +56 -0
  41. package/lib/link.js +96 -0
  42. package/lib/prefer.js +52 -0
  43. package/lib/query.js +113 -0
  44. package/lib/rate-limit.js +115 -0
  45. package/lib/sanitize-quoted-string.js +28 -0
  46. package/lib/security-headers.js +125 -0
  47. package/lib/validate.js +80 -0
  48. package/lib/vary.js +40 -0
  49. package/package.json +158 -0
  50. package/types/http/accepts.d.ts +8 -0
  51. package/types/http/authorization.d.ts +8 -0
  52. package/types/http/body.d.ts +20 -0
  53. package/types/http/cache-control.d.ts +16 -0
  54. package/types/http/compress.d.ts +5 -0
  55. package/types/http/cookie.d.ts +2 -0
  56. package/types/http/cors.d.ts +9 -0
  57. package/types/http/csrf.d.ts +9 -0
  58. package/types/http/handler.d.ts +2 -0
  59. package/types/http/index.d.ts +1 -0
  60. package/types/http/json-api-query.d.ts +2 -0
  61. package/types/http/logger.d.ts +9 -0
  62. package/types/http/main.d.ts +142 -0
  63. package/types/http/precondition.d.ts +44 -0
  64. package/types/http/prefer.d.ts +2 -0
  65. package/types/http/rate-limit.d.ts +17 -0
  66. package/types/http/security-headers.d.ts +10 -0
  67. package/types/http/send.d.ts +8 -0
  68. package/types/http/timeout.d.ts +5 -0
  69. package/types/http/url.d.ts +2 -0
  70. package/types/http/validate.d.ts +6 -0
  71. package/types/lib/accepts.d.ts +7 -0
  72. package/types/lib/attach-instance.d.ts +19 -0
  73. package/types/lib/authorization.d.ts +6 -0
  74. package/types/lib/body/multiparse.d.ts +9 -0
  75. package/types/lib/body/multipart/headers.d.ts +2 -0
  76. package/types/lib/body/writer.d.ts +2 -0
  77. package/types/lib/cookie/cookie.d.ts +32 -0
  78. package/types/lib/cookie/index.d.ts +2 -0
  79. package/types/lib/cookie/jar.d.ts +8 -0
  80. package/types/lib/cookie/parse.d.ts +19 -0
  81. package/types/lib/cors.d.ts +9 -0
  82. package/types/lib/csrf.d.ts +32 -0
  83. package/types/lib/from-connect.d.ts +47 -0
  84. package/types/lib/json-api-query/index.d.ts +123 -0
  85. package/types/lib/json-api-query/validate.d.ts +5 -0
  86. package/types/lib/link.d.ts +37 -0
  87. package/types/lib/prefer.d.ts +36 -0
  88. package/types/lib/query.d.ts +6 -0
  89. package/types/lib/rate-limit.d.ts +76 -0
  90. package/types/lib/sanitize-quoted-string.d.ts +19 -0
  91. package/types/lib/security-headers.d.ts +24 -0
  92. package/types/lib/validate.d.ts +16 -0
  93. package/types/lib/vary.d.ts +17 -0
  94. package/types/utils/attempt.d.ts +2 -0
  95. package/types/utils/buffers/index.d.ts +2 -0
  96. package/types/utils/buffers/match.d.ts +10 -0
  97. package/types/utils/buffers/split.d.ts +10 -0
  98. package/types/utils/compose-with.d.ts +40 -0
  99. package/types/utils/compose.d.ts +83 -0
  100. package/types/utils/flat-array.d.ts +2 -0
  101. package/types/utils/get.d.ts +5 -0
  102. package/types/utils/http-errors.d.ts +22 -0
  103. package/types/utils/iterables/buffer-split.d.ts +2 -0
  104. package/types/utils/iterables/chain.d.ts +2 -0
  105. package/types/utils/iterables/exec-all.d.ts +2 -0
  106. package/types/utils/iterables/filter.d.ts +2 -0
  107. package/types/utils/iterables/for-each.d.ts +2 -0
  108. package/types/utils/iterables/from-stream.d.ts +2 -0
  109. package/types/utils/iterables/index.d.ts +10 -0
  110. package/types/utils/iterables/map.d.ts +2 -0
  111. package/types/utils/iterables/range.d.ts +24 -0
  112. package/types/utils/iterables/reduce.d.ts +2 -0
  113. package/types/utils/iterables/take.d.ts +2 -0
  114. package/types/utils/observables/buffer-split.d.ts +2 -0
  115. package/types/utils/observables/chain.d.ts +2 -0
  116. package/types/utils/observables/index.d.ts +4 -0
  117. package/types/utils/observables/map.d.ts +2 -0
  118. package/types/utils/observables/take.d.ts +2 -0
  119. package/types/utils/pick.d.ts +2 -0
  120. package/types/utils/set.d.ts +2 -0
  121. package/types/utils/streams/index.d.ts +2 -0
  122. package/types/utils/streams/meter.d.ts +5 -0
  123. package/types/utils/streams/tee.d.ts +2 -0
  124. package/types/utils/type.d.ts +2 -0
  125. package/utils/attempt.js +37 -0
  126. package/utils/buffers/index.js +13 -0
  127. package/utils/buffers/match.js +96 -0
  128. package/utils/buffers/split.js +55 -0
  129. package/utils/compose-with.js +232 -0
  130. package/utils/compose.js +165 -0
  131. package/utils/flat-array.js +24 -0
  132. package/utils/get.js +39 -0
  133. package/utils/http-errors.js +113 -0
  134. package/utils/iterables/buffer-split.js +117 -0
  135. package/utils/iterables/chain.js +32 -0
  136. package/utils/iterables/exec-all.js +42 -0
  137. package/utils/iterables/filter.js +35 -0
  138. package/utils/iterables/for-each.js +33 -0
  139. package/utils/iterables/from-stream.js +29 -0
  140. package/utils/iterables/index.js +21 -0
  141. package/utils/iterables/map.js +47 -0
  142. package/utils/iterables/range.js +34 -0
  143. package/utils/iterables/reduce.js +43 -0
  144. package/utils/iterables/take.js +36 -0
  145. package/utils/observables/buffer-split.js +109 -0
  146. package/utils/observables/chain.js +33 -0
  147. package/utils/observables/index.js +19 -0
  148. package/utils/observables/map.js +34 -0
  149. package/utils/observables/take.js +40 -0
  150. package/utils/pick.js +41 -0
  151. package/utils/set.js +38 -0
  152. package/utils/streams/index.js +11 -0
  153. package/utils/streams/meter.js +98 -0
  154. package/utils/streams/tee.js +84 -0
  155. 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
+ };