@centralping/ergo 0.1.0-beta.1 → 0.1.0-beta.3

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 (93) hide show
  1. package/README.md +14 -15
  2. package/http/accepts.js +1 -2
  3. package/http/authorization.js +1 -2
  4. package/http/body.js +1 -2
  5. package/http/cache-control.js +1 -2
  6. package/http/compress.js +1 -2
  7. package/http/cookie.js +1 -2
  8. package/http/cors.js +1 -2
  9. package/http/csrf.js +1 -2
  10. package/http/handler.js +1 -2
  11. package/http/idempotency.js +110 -0
  12. package/http/index.js +37 -4
  13. package/http/json-api-query.js +1 -2
  14. package/http/logger.js +1 -2
  15. package/http/main.js +5 -3
  16. package/http/precondition.js +1 -2
  17. package/http/prefer.js +1 -2
  18. package/http/rate-limit.js +1 -2
  19. package/http/security-headers.js +1 -2
  20. package/http/send.js +1 -2
  21. package/http/timeout.js +1 -2
  22. package/http/url.js +1 -2
  23. package/http/validate.js +1 -2
  24. package/lib/accepts.js +1 -2
  25. package/lib/attach-instance.js +0 -1
  26. package/lib/authorization.js +1 -2
  27. package/lib/body/multiparse.js +1 -2
  28. package/lib/body/multipart/headers.js +1 -2
  29. package/lib/body/writer.js +1 -2
  30. package/lib/cookie/cookie.js +1 -2
  31. package/lib/cookie/index.js +0 -1
  32. package/lib/cookie/jar.js +16 -12
  33. package/lib/cookie/parse.js +1 -2
  34. package/lib/cors.js +1 -2
  35. package/lib/csrf.js +1 -2
  36. package/lib/from-connect.js +2 -3
  37. package/lib/idempotency.js +139 -0
  38. package/lib/json-api-query/index.js +0 -1
  39. package/lib/json-api-query/validate.js +1 -2
  40. package/lib/link.js +57 -5
  41. package/lib/prefer.js +1 -2
  42. package/lib/query.js +1 -2
  43. package/lib/rate-limit.js +1 -2
  44. package/lib/sanitize-quoted-string.js +0 -1
  45. package/lib/security-headers.js +1 -2
  46. package/lib/validate.js +1 -2
  47. package/lib/vary.js +0 -1
  48. package/package.json +2 -2
  49. package/types/http/idempotency.d.ts +20 -0
  50. package/types/http/main.d.ts +3 -1
  51. package/types/http/precondition.d.ts +1 -2
  52. package/types/lib/attach-instance.d.ts +0 -1
  53. package/types/lib/cookie/jar.d.ts +4 -0
  54. package/types/lib/from-connect.d.ts +2 -3
  55. package/types/lib/idempotency.d.ts +64 -0
  56. package/types/lib/link.d.ts +28 -0
  57. package/types/lib/prefer.d.ts +1 -2
  58. package/types/lib/rate-limit.d.ts +1 -2
  59. package/types/lib/sanitize-quoted-string.d.ts +0 -1
  60. package/types/lib/vary.d.ts +0 -1
  61. package/types/utils/compose.d.ts +1 -2
  62. package/types/utils/iterables/range.d.ts +1 -2
  63. package/utils/attempt.js +1 -2
  64. package/utils/buffers/index.js +0 -1
  65. package/utils/buffers/match.js +1 -2
  66. package/utils/buffers/split.js +1 -2
  67. package/utils/compose-with.js +1 -2
  68. package/utils/compose.js +1 -2
  69. package/utils/flat-array.js +1 -2
  70. package/utils/get.js +1 -2
  71. package/utils/http-errors.js +1 -2
  72. package/utils/iterables/buffer-split.js +1 -2
  73. package/utils/iterables/chain.js +1 -2
  74. package/utils/iterables/exec-all.js +1 -2
  75. package/utils/iterables/filter.js +1 -2
  76. package/utils/iterables/for-each.js +1 -2
  77. package/utils/iterables/from-stream.js +1 -2
  78. package/utils/iterables/index.js +0 -1
  79. package/utils/iterables/map.js +1 -2
  80. package/utils/iterables/range.js +1 -2
  81. package/utils/iterables/reduce.js +1 -2
  82. package/utils/iterables/take.js +1 -2
  83. package/utils/observables/buffer-split.js +0 -1
  84. package/utils/observables/chain.js +0 -1
  85. package/utils/observables/index.js +0 -1
  86. package/utils/observables/map.js +0 -1
  87. package/utils/observables/take.js +0 -1
  88. package/utils/pick.js +1 -2
  89. package/utils/set.js +1 -2
  90. package/utils/streams/index.js +0 -1
  91. package/utils/streams/meter.js +1 -2
  92. package/utils/streams/tee.js +1 -2
  93. package/utils/type.js +1 -2
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <p align="center">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="assets/logo-wordmark-dark.svg">
4
- <source media="(prefers-color-scheme: light)" srcset="assets/logo-wordmark-light.svg">
5
- <img alt="ergo" src="assets/logo-wordmark-light.svg" width="240">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/CentralPing/ergo/main/assets/logo-wordmark-dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/CentralPing/ergo/main/assets/logo-wordmark-light.svg">
5
+ <img alt="ergo" src="https://raw.githubusercontent.com/CentralPing/ergo/main/assets/logo-wordmark-light.svg" width="240">
6
6
  </picture>
7
7
  </p>
8
8
 
@@ -11,7 +11,7 @@
11
11
  [![npm version](https://img.shields.io/npm/v/@centralping/ergo.svg)](https://www.npmjs.com/package/@centralping/ergo)
12
12
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/CentralPing/ergo/badge)](https://scorecard.dev/viewer/?uri=github.com/CentralPing/ergo)
13
13
  [![Node.js >=22](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org)
14
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
14
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/CentralPing/ergo/blob/main/LICENSE)
15
15
 
16
16
  A **Fast Fail** REST API toolkit for Node.js. _ergo_ (error or go) provides composable, stream-native middleware organized around the principle that a server should fail as early as possible -- before doing any expensive work -- through four ordered stages: **Negotiation, Authorization, Validation, and Execution**. Every behavior is backed by an IETF RFC or industry standard, not invented conventions.
17
17
 
@@ -57,20 +57,19 @@ Requires **Node.js >= 22**.
57
57
 
58
58
  ```js
59
59
  import {createServer} from 'node:http';
60
- import {compose, handler, logger, cors, authorization, body, send} from '@centralping/ergo';
60
+ import {compose, handler, logger, cors, authorization, body} from '@centralping/ergo';
61
61
 
62
62
  const pipeline = compose(
63
- [logger(), [], 'log'],
64
- [cors(), [], 'cors'],
63
+ [logger(), 'log'],
64
+ [cors(), 'cors'],
65
65
  [authorization({strategies: [{type: 'Bearer', authorizer: (_, token) =>
66
66
  token === 'my-token' ? {authorized: true, info: {uid: 1}} : {}
67
- }]}), [], 'auth'],
68
- [body(), [], 'body'],
69
- (req, res, {auth, body}) => ({body: {user: auth, data: body.parsed}}),
70
- send()
67
+ }]}), 'auth'],
68
+ [body(), 'body'],
69
+ (req, res, acc) => ({response: {body: {user: acc.auth, data: acc.body.parsed}}})
71
70
  );
72
71
 
73
- createServer(handler(pipeline, send())).listen(3000);
72
+ createServer(handler(pipeline)).listen(3000);
74
73
  ```
75
74
 
76
75
  ## Middleware Overview
@@ -96,7 +95,7 @@ createServer(handler(pipeline, send())).listen(3000);
96
95
  | `cacheControl()` | Cache-Control header management | [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111) |
97
96
  | `jsonApiQuery()` | JSON:API query parameter validation | [JSON:API](https://jsonapi.org/) |
98
97
 
99
- See the [full API reference](https://centralping.github.io/api/ergo/) for detailed options and examples.
98
+ See the [full API reference](https://centralping.github.io/packages/ergo/) for detailed options and examples.
100
99
 
101
100
  ## Standards Compliance
102
101
 
@@ -120,8 +119,8 @@ See the [full API reference](https://centralping.github.io/api/ergo/) for detail
120
119
  ## Documentation
121
120
 
122
121
  - [Getting Started](https://centralping.github.io/getting-started/)
123
- - [API Reference](https://centralping.github.io/api/ergo/)
124
- - [Architecture & Design](https://centralping.github.io/architecture/)
122
+ - [API Reference](https://centralping.github.io/packages/ergo/)
123
+ - [Fast Fail Pipeline](https://centralping.github.io/concepts/fast-fail/)
125
124
  - [Benchmarks](https://centralping.github.io/benchmarks/)
126
125
 
127
126
  ## Development
package/http/accepts.js CHANGED
@@ -10,13 +10,12 @@
10
10
  * Fast Fail pipeline.
11
11
  *
12
12
  * @module http/accepts
13
- * @version 0.1.0
14
13
  * @since 0.1.0
15
14
  * @requires ../lib/accepts.js
16
15
  * @requires ../utils/http-errors.js
17
16
  *
18
17
  * @example
19
- * import {compose, accepts} from 'ergo';
18
+ * import {compose, accepts} from '@centralping/ergo';
20
19
  *
21
20
  * const pipeline = compose(
22
21
  * [accepts({types: ['application/json']}), 'accepts'],
@@ -10,13 +10,12 @@
10
10
  * response header (RFC 7235).
11
11
  *
12
12
  * @module http/authorization
13
- * @version 0.1.0
14
13
  * @since 0.1.0
15
14
  * @requires ../lib/authorization.js
16
15
  * @requires ../utils/http-errors.js
17
16
  *
18
17
  * @example
19
- * import {compose, authorization} from 'ergo';
18
+ * import {compose, authorization} from '@centralping/ergo';
20
19
  *
21
20
  * const pipeline = compose(
22
21
  * [authorization({
package/http/body.js CHANGED
@@ -17,7 +17,6 @@
17
17
  * 3-stream pipeline for reduced per-request overhead.
18
18
  *
19
19
  * @module http/body
20
- * @version 0.1.0
21
20
  * @since 0.1.0
22
21
  * @requires node:stream
23
22
  * @requires node:zlib
@@ -29,7 +28,7 @@
29
28
  * @requires ../utils/http-errors.js
30
29
  *
31
30
  * @example
32
- * import {compose, body} from 'ergo';
31
+ * import {compose, body} from '@centralping/ergo';
33
32
  *
34
33
  * const pipeline = compose(
35
34
  * [body({limit: 2 * 1024 * 1024}), 'body'],
@@ -6,11 +6,10 @@
6
6
  * a raw directive string or structured options that are assembled into a directive.
7
7
  *
8
8
  * @module http/cache-control
9
- * @version 0.1.0
10
9
  * @since 0.1.0
11
10
  *
12
11
  * @example
13
- * import {compose, cacheControl} from 'ergo';
12
+ * import {compose, cacheControl} from '@centralping/ergo';
14
13
  *
15
14
  * // String shorthand
16
15
  * const pipeline = compose(
package/http/compress.js CHANGED
@@ -13,13 +13,12 @@
13
13
  * - Bodies below the configurable `threshold` byte count (default 1 KiB)
14
14
  *
15
15
  * @module http/compress
16
- * @version 0.1.0
17
16
  * @since 0.1.0
18
17
  * @requires node:zlib
19
18
  * @requires negotiator
20
19
  *
21
20
  * @example
22
- * import {compose, compress} from 'ergo';
21
+ * import {compose, compress} from '@centralping/ergo';
23
22
  *
24
23
  * const pipeline = compose(
25
24
  * compress({threshold: 1024, encodings: ['br', 'gzip', 'deflate']}),
package/http/cookie.js CHANGED
@@ -12,12 +12,11 @@
12
12
  * and other cookie-based workflows.
13
13
  *
14
14
  * @module http/cookie
15
- * @version 0.1.0
16
15
  * @since 0.1.0
17
16
  * @requires ../lib/cookie/index.js
18
17
  *
19
18
  * @example
20
- * import {compose, cookie} from 'ergo';
19
+ * import {compose, cookie} from '@centralping/ergo';
21
20
  *
22
21
  * const pipeline = compose(
23
22
  * [cookie(), 'cookies'],
package/http/cors.js CHANGED
@@ -10,13 +10,12 @@
10
10
  * Pre-flight `OPTIONS` requests should be handled at the router level using `ergo-router`.
11
11
  *
12
12
  * @module http/cors
13
- * @version 0.1.0
14
13
  * @since 0.1.0
15
14
  * @requires ../lib/cors.js
16
15
  * @requires ../utils/http-errors.js
17
16
  *
18
17
  * @example
19
- * import {compose, cors} from 'ergo';
18
+ * import {compose, cors} from '@centralping/ergo';
20
19
  *
21
20
  * const pipeline = compose(
22
21
  * [cors({
package/http/csrf.js CHANGED
@@ -11,13 +11,12 @@
11
11
  * The CSRF UUID is stored in a separate cookie so the token can be regenerated independently.
12
12
  *
13
13
  * @module http/csrf
14
- * @version 0.1.0
15
14
  * @since 0.1.0
16
15
  * @requires ../lib/csrf.js
17
16
  * @requires ../utils/http-errors.js
18
17
  *
19
18
  * @example
20
- * import {compose, cookie, csrf} from 'ergo';
19
+ * import {compose, cookie, csrf} from '@centralping/ergo';
21
20
  *
22
21
  * const csrfMiddleware = csrf({secret: process.env.CSRF_SECRET});
23
22
  *
package/http/handler.js CHANGED
@@ -13,11 +13,10 @@
13
13
  * compose middleware directly without the router.
14
14
  *
15
15
  * @module http/handler
16
- * @version 0.2.0
17
16
  * @since 0.1.0
18
17
  *
19
18
  * @example
20
- * import {handler, compose, send, logger, authorization, body} from 'ergo';
19
+ * import {handler, compose, logger, authorization, body} from '@centralping/ergo';
21
20
  *
22
21
  * const pipeline = compose(
23
22
  * [logger(), 'log'],
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @fileoverview Idempotency-Key pipeline middleware.
3
+ *
4
+ * Detects duplicate requests by `Idempotency-Key` header value per
5
+ * draft-ietf-httpapi-idempotency-key-header-07. When a matching key with
6
+ * the same request fingerprint is found, the stored response is replayed.
7
+ * When a key matches but the fingerprint differs, a 409 Conflict is returned.
8
+ *
9
+ * Placed in Stage 3 (Validation) after body parsing so the request body
10
+ * fingerprint can be computed from the parsed body.
11
+ *
12
+ * @module http/idempotency
13
+ * @since 0.1.0-beta.2
14
+ * @requires ../lib/idempotency.js
15
+ *
16
+ * @example
17
+ * import {compose, body, idempotency} from '@centralping/ergo';
18
+ *
19
+ * const pipeline = compose(
20
+ * [body(), 'body'],
21
+ * [idempotency({required: true}), 'idempotency'],
22
+ * (req, res, acc) => ({response: {statusCode: 201, body: {created: true}}})
23
+ * );
24
+ *
25
+ * @see {@link https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/ Idempotency-Key Header (IETF Draft)}
26
+ */
27
+ import {IdempotencyStore, parseIdempotencyKey, generateFingerprint} from '../lib/idempotency.js';
28
+
29
+ const DEFAULT_METHODS = new Set(['POST', 'PATCH']);
30
+
31
+ /**
32
+ * Create an idempotency middleware.
33
+ *
34
+ * @param {object} [options]
35
+ * @param {object} [options.store] - Pluggable store (must implement get/set/complete/delete).
36
+ * Defaults to an in-memory store with 24h TTL.
37
+ * @param {number} [options.ttlMs=86400000] - TTL for stored entries in milliseconds (default: 24h).
38
+ * Only used when creating the default in-memory store.
39
+ * @param {boolean} [options.required=false] - When true, returns 400 if the header is missing
40
+ * on applicable methods
41
+ * @param {Set<string>|string[]} [options.methods] - HTTP methods to apply idempotency to
42
+ * (default: POST, PATCH)
43
+ * @returns {function} - Middleware `(req, res, domainAcc) => {value?, response?}`
44
+ */
45
+ export default function idempotency({store, ttlMs, required = false, methods} = {}) {
46
+ const _store = store ?? new IdempotencyStore(ttlMs ? {ttlMs} : undefined);
47
+ const _methods = methods instanceof Set ? methods : new Set(methods ?? DEFAULT_METHODS);
48
+
49
+ return (req, _res, domainAcc) => {
50
+ if (!_methods.has(req.method)) return {};
51
+
52
+ const key = parseIdempotencyKey(req.headers?.['idempotency-key']);
53
+
54
+ if (!key) {
55
+ if (required) {
56
+ return {
57
+ response: {
58
+ statusCode: 400,
59
+ detail: 'Idempotency-Key header is required'
60
+ }
61
+ };
62
+ }
63
+ return {};
64
+ }
65
+
66
+ const rawBody = domainAcc?.body?.raw ?? domainAcc?.body?.parsed ?? '';
67
+ const fingerprint = generateFingerprint(
68
+ typeof rawBody === 'string' ? rawBody : JSON.stringify(rawBody)
69
+ );
70
+
71
+ const existing = _store.get(key);
72
+
73
+ if (existing) {
74
+ if (existing.fingerprint !== fingerprint) {
75
+ return {
76
+ response: {
77
+ statusCode: 409,
78
+ detail: 'Idempotency key already used with a different request'
79
+ }
80
+ };
81
+ }
82
+
83
+ if (existing.status === 'complete' && existing.response) {
84
+ return {
85
+ value: {replayed: true},
86
+ response: existing.response
87
+ };
88
+ }
89
+
90
+ // Still processing — concurrent duplicate
91
+ return {
92
+ response: {
93
+ statusCode: 409,
94
+ detail: 'A request with this idempotency key is already being processed'
95
+ }
96
+ };
97
+ }
98
+
99
+ _store.set(key, fingerprint);
100
+
101
+ return {
102
+ value: {
103
+ key,
104
+ fingerprint,
105
+ complete: response => _store.complete(key, response),
106
+ discard: () => _store.delete(key)
107
+ }
108
+ };
109
+ };
110
+ }
package/http/index.js CHANGED
@@ -1,13 +1,46 @@
1
1
  /**
2
- * @fileoverview Entry point for the @centralping/ergo package.
2
+ * @fileoverview Fast Fail REST API toolkit for Node.js.
3
3
  *
4
- * Re-exports the main module for ESM consumers:
5
- * `import { handler, send } from '@centralping/ergo'`
4
+ * Composable middleware organized into four ordered pipeline stages — a failure
5
+ * at any stage immediately returns a standards-compliant error response so no
6
+ * downstream work is wasted:
7
+ *
8
+ * | Stage | Middleware | Purpose |
9
+ * | --- | --- | --- |
10
+ * | **Negotiation** | {@link logger}, {@link cors}, {@link accepts}, {@link cookie}, {@link url} | Parse/inspect request headers and URL |
11
+ * | **Authorization** | {@link authorization}, {@link csrf} | Authenticate and verify request integrity |
12
+ * | **Validation** | {@link body}, {@link jsonApiQuery}, {@link validate} | Parse and validate the request body |
13
+ * | **Execution** | {@link timeout}, {@link compress}, {@link handler}, {@link send} | Run the handler and serialize the response |
14
+ *
15
+ * Cross-cutting middleware available at any stage:
16
+ * {@link cacheControl}, {@link prefer}, {@link precondition},
17
+ * {@link rateLimit}, {@link securityHeaders}
18
+ *
19
+ * **Composition utilities:** {@link compose}, {@link createResponseAcc},
20
+ * {@link mergeResponse}, {@link httpErrors}, {@link fromConnect}
6
21
  *
7
22
  * @module @centralping/ergo
8
- * @version 0.1.0-beta.1
9
23
  * @since 0.1.0
10
24
  * @requires ./main.js
25
+ *
26
+ * @example
27
+ * import {compose, handler, logger, cors, accepts, authorization,
28
+ * body, send} from '@centralping/ergo';
29
+ *
30
+ * const pipeline = compose(
31
+ * [logger(), 'log'],
32
+ * [cors(), 'cors'],
33
+ * [accepts({types: ['application/json']}), 'accepts'],
34
+ * [authorization({strategies: [...]}), 'auth'],
35
+ * [body(), 'body'],
36
+ * (req, res, acc) => ({response: {body: acc.body.parsed}}),
37
+ * );
38
+ *
39
+ * const server = http.createServer(handler(pipeline));
40
+ *
41
+ * @see {@link https://centralping.github.io/concepts/fast-fail/ Fast Fail Pipeline}
42
+ * @see {@link https://centralping.github.io/concepts/security/ Security}
43
+ * @see {@link https://centralping.github.io/concepts/standards/ Standards Compliance}
11
44
  */
12
45
 
13
46
  export * from './main.js';
@@ -11,13 +11,12 @@
11
11
  * Must be placed after `url()` in the pipeline so that `acc.url` is populated.
12
12
  *
13
13
  * @module http/json-api-query
14
- * @version 0.1.0
15
14
  * @since 0.1.0
16
15
  * @requires ../lib/json-api-query/index.js
17
16
  * @requires ../utils/http-errors.js
18
17
  *
19
18
  * @example
20
- * import {compose, url, jsonApiQuery} from 'ergo';
19
+ * import {compose, url, jsonApiQuery} from '@centralping/ergo';
21
20
  *
22
21
  * const pipeline = compose(
23
22
  * [url(), 'url'],
package/http/logger.js CHANGED
@@ -23,13 +23,12 @@
23
23
  * accidental secret leakage.
24
24
  *
25
25
  * @module http/logger
26
- * @version 0.1.0
27
26
  * @since 0.1.0
28
27
  * @requires node:os
29
28
  * @requires node:crypto
30
29
  *
31
30
  * @example
32
- * import {compose, logger} from 'ergo';
31
+ * import {compose, logger} from '@centralping/ergo';
33
32
  *
34
33
  * const pipeline = compose(
35
34
  * [logger(), 'log'],
package/http/main.js CHANGED
@@ -14,8 +14,7 @@
14
14
  * accumulated under named keys in `domainAcc`; response properties merge
15
15
  * into `responseAcc`. `send()` is called post-pipeline by `handler()`.
16
16
  *
17
- * @module ergo
18
- * @version 0.1.0
17
+ * @module @centralping/ergo
19
18
  * @since 0.1.0
20
19
  * @requires ./handler.js
21
20
  * @requires ./accepts.js
@@ -42,7 +41,7 @@
42
41
  *
43
42
  * @example
44
43
  * import {compose, handler, logger, cors, authorization, accepts,
45
- * cookie, url, body} from 'ergo';
44
+ * cookie, url, body} from '@centralping/ergo';
46
45
  *
47
46
  * const pipeline = compose(
48
47
  * // Stage 1: Negotiation
@@ -81,6 +80,7 @@ import rateLimit from './rate-limit.js';
81
80
  import securityHeaders from './security-headers.js';
82
81
  import send from './send.js';
83
82
  import timeout from './timeout.js';
83
+ import idempotency from './idempotency.js';
84
84
  import validate from './validate.js';
85
85
  import httpErrors from '../utils/http-errors.js';
86
86
  import fromConnect from '../lib/from-connect.js';
@@ -100,6 +100,7 @@ export {
100
100
  csrf,
101
101
  fromConnect,
102
102
  httpErrors,
103
+ idempotency,
103
104
  jsonApiQuery,
104
105
  logger,
105
106
  prefer,
@@ -127,6 +128,7 @@ export default {
127
128
  csrf,
128
129
  fromConnect,
129
130
  httpErrors,
131
+ idempotency,
130
132
  jsonApiQuery,
131
133
  logger,
132
134
  prefer,
@@ -10,11 +10,10 @@
10
10
  * inspection that short-circuits before authorization, body parsing, or execution.
11
11
  *
12
12
  * @module http/precondition
13
- * @version 0.1.0
14
13
  * @since 0.1.0
15
14
  *
16
15
  * @example
17
- * import {compose, precondition} from 'ergo';
16
+ * import {compose, precondition} from '@centralping/ergo';
18
17
  *
19
18
  * // Enforce on all requests (method scoping handled by pipeline builder)
20
19
  * const pipeline = compose(
package/http/prefer.js CHANGED
@@ -8,12 +8,11 @@
8
8
  * Placed in Stage 1 (Negotiation) — cheap header parse with no I/O.
9
9
  *
10
10
  * @module http/prefer
11
- * @version 0.1.0
12
11
  * @since 0.1.0
13
12
  * @requires ../lib/prefer.js
14
13
  *
15
14
  * @example
16
- * import {compose, prefer} from 'ergo';
15
+ * import {compose, prefer} from '@centralping/ergo';
17
16
  *
18
17
  * const pipeline = compose(
19
18
  * [prefer(), 'prefer'],
@@ -10,12 +10,11 @@
10
10
  * or execution.
11
11
  *
12
12
  * @module http/rate-limit
13
- * @version 0.1.0
14
13
  * @since 0.1.0
15
14
  * @requires ../lib/rate-limit.js
16
15
  *
17
16
  * @example
18
- * import {compose, rateLimit} from 'ergo';
17
+ * import {compose, rateLimit} from '@centralping/ergo';
19
18
  *
20
19
  * const pipeline = compose(
21
20
  * [rateLimit({max: 100, windowMs: 60000}), 'rateLimit'],
@@ -8,12 +8,11 @@
8
8
  * Delegates tuple construction to `lib/security-headers.js` (the shared primitive).
9
9
  *
10
10
  * @module http/security-headers
11
- * @version 0.1.0
12
11
  * @since 0.1.0
13
12
  * @requires ../lib/security-headers.js
14
13
  *
15
14
  * @example
16
- * import {compose, securityHeaders} from 'ergo';
15
+ * import {compose, securityHeaders} from '@centralping/ergo';
17
16
  *
18
17
  * // Use defaults
19
18
  * const pipeline = compose(
package/http/send.js CHANGED
@@ -29,7 +29,6 @@
29
29
  * - Optional response envelope for 2xx Object bodies
30
30
  *
31
31
  * @module http/send
32
- * @version 0.2.0
33
32
  * @since 0.1.0
34
33
  * @requires node:stream
35
34
  * @requires node:http
@@ -38,7 +37,7 @@
38
37
  * @requires ../lib/vary.js
39
38
  *
40
39
  * @example
41
- * import {send, createResponseAcc} from 'ergo';
40
+ * import {send, createResponseAcc} from '@centralping/ergo';
42
41
  *
43
42
  * const writer = send({etag: true});
44
43
  * // After pipeline completes:
package/http/timeout.js CHANGED
@@ -12,11 +12,10 @@
12
12
  * can be GC'd.
13
13
  *
14
14
  * @module http/timeout
15
- * @version 0.2.0
16
15
  * @since 0.1.0
17
16
  *
18
17
  * @example
19
- * import {compose, timeout} from 'ergo';
18
+ * import {compose, timeout} from '@centralping/ergo';
20
19
  *
21
20
  * const pipeline = compose(
22
21
  * [timeout({ms: 10000, statusCode: 504}), 'timeout'],
package/http/url.js CHANGED
@@ -11,12 +11,11 @@
11
11
  * - `search` is the raw query string including the `?` prefix, or `undefined`
12
12
  *
13
13
  * @module http/url
14
- * @version 0.1.0
15
14
  * @since 0.1.0
16
15
  * @requires ../lib/query.js
17
16
  *
18
17
  * @example
19
- * import {compose, url} from 'ergo';
18
+ * import {compose, url} from '@centralping/ergo';
20
19
  *
21
20
  * const pipeline = compose(
22
21
  * [url(), 'url'],
package/http/validate.js CHANGED
@@ -9,12 +9,11 @@
9
9
  * are populated before validation runs.
10
10
  *
11
11
  * @module http/validate
12
- * @version 0.1.0
13
12
  * @since 0.1.0
14
13
  * @requires ../lib/validate.js
15
14
  *
16
15
  * @example
17
- * import {compose, body, url, validate} from 'ergo';
16
+ * import {compose, body, url, validate} from '@centralping/ergo';
18
17
  *
19
18
  * const pipeline = compose(
20
19
  * [body(), 'body'],
package/lib/accepts.js CHANGED
@@ -6,13 +6,12 @@
6
6
  * as the pure-logic backing implementation.
7
7
  *
8
8
  * @module lib/accepts
9
- * @version 0.1.0
10
9
  * @since 0.1.0
11
10
  * @requires negotiator
12
11
  * @requires ../utils/flat-array.js
13
12
  *
14
13
  * @example
15
- * import accepts from 'ergo/lib/accepts';
14
+ * import accepts from '@centralping/ergo/lib/accepts';
16
15
  *
17
16
  * const negotiate = accepts({types: ['application/json', 'text/html']});
18
17
  * const result = negotiate({'accept': 'text/html,application/json;q=0.9'});
@@ -5,7 +5,6 @@
5
5
  * `x-request-id` header, formatted as a `urn:uuid:` URI.
6
6
  *
7
7
  * @module lib/attach-instance
8
- * @version 0.1.0
9
8
  * @since 0.1.0
10
9
  */
11
10
 
@@ -11,11 +11,10 @@
11
11
  * 401 for known schemes (with a `WWW-Authenticate` challenge) or 403 for unrecognized schemes.
12
12
  *
13
13
  * @module lib/authorization
14
- * @version 0.1.0
15
14
  * @since 0.1.0
16
15
  *
17
16
  * @example
18
- * import authorize from 'ergo/lib/authorization';
17
+ * import authorize from '@centralping/ergo/lib/authorization';
19
18
  *
20
19
  * const authorizer = authorize([{
21
20
  * type: 'Bearer',
@@ -12,7 +12,6 @@
12
12
  * `Content-Disposition`, `Content-Type`, `Content-Transfer-Encoding`.
13
13
  *
14
14
  * @module lib/body/multiparse
15
- * @version 0.1.0
16
15
  * @since 0.1.0
17
16
  * @requires ./multipart/headers.js
18
17
  * @requires ../../utils/iterables/buffer-split.js
@@ -21,7 +20,7 @@
21
20
  * @see {@link https://www.rfc-editor.org/rfc/rfc7578}
22
21
  *
23
22
  * @example
24
- * import multiparse from 'ergo/lib/body/multiparse';
23
+ * import multiparse from '@centralping/ergo/lib/body/multiparse';
25
24
  *
26
25
  * const parts = multiparse(rawBodyBuffer, 'boundary-string');
27
26
  * // parts => [{headers: {...}, name: 'file', filename: 'upload.txt', body: Buffer}]
@@ -11,14 +11,13 @@
11
11
  * - `content-transfer-encoding` (deprecated but present in legacy clients)
12
12
  *
13
13
  * @module lib/body/multipart/headers
14
- * @version 0.1.0
15
14
  * @since 0.1.0
16
15
  * @requires ../../../utils/iterables/exec-all.js
17
16
  *
18
17
  * @see {@link https://www.rfc-editor.org/rfc/rfc7578 RFC 7578 - Returning Values from Forms: multipart/form-data}
19
18
  *
20
19
  * @example
21
- * import parseHeaders from 'ergo/lib/body/multipart/headers';
20
+ * import parseHeaders from '@centralping/ergo/lib/body/multipart/headers';
22
21
  *
23
22
  * parseHeaders(['Content-Disposition: form-data; name="field1"']);
24
23
  * // => {'content-disposition': {type: 'form-data', parameters: {name: 'field1'}}}
@@ -8,13 +8,12 @@
8
8
  * `pipeline(req, meter, decompressor, writer())`
9
9
  *
10
10
  * @module lib/body/writer
11
- * @version 0.1.0
12
11
  * @since 0.1.0
13
12
  * @requires node:stream
14
13
  *
15
14
  * @example
16
15
  * import {pipeline} from 'node:stream';
17
- * import writer from 'ergo/lib/body/writer';
16
+ * import writer from '@centralping/ergo/lib/body/writer';
18
17
  *
19
18
  * const w = writer();
20
19
  * pipeline(readable, w, err => {