@heavybit/shared-lib 1.3.2 → 2.7.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.
- package/README.md +261 -0
- package/dist/cjs/access/index.js +9 -1
- package/dist/cjs/access/index.js.map +1 -1
- package/dist/cjs/approvals/index.js +137 -0
- package/dist/cjs/approvals/index.js.map +1 -0
- package/dist/cjs/audit/index.js +74 -0
- package/dist/cjs/audit/index.js.map +1 -0
- package/dist/cjs/cache/index.js +90 -16
- package/dist/cjs/cache/index.js.map +1 -1
- package/dist/cjs/cache/keyspace.js +101 -0
- package/dist/cjs/cache/keyspace.js.map +1 -0
- package/dist/cjs/common/circuit-breaker.js +74 -0
- package/dist/cjs/common/circuit-breaker.js.map +1 -0
- package/dist/cjs/common/errors.js +44 -5
- package/dist/cjs/common/errors.js.map +1 -1
- package/dist/cjs/common/index.js +4 -0
- package/dist/cjs/common/index.js.map +1 -1
- package/dist/cjs/common/internal-client.js +177 -0
- package/dist/cjs/common/internal-client.js.map +1 -0
- package/dist/cjs/common/internal-constants.js +12 -0
- package/dist/cjs/common/internal-constants.js.map +1 -0
- package/dist/cjs/common/internal-service-auth.js +160 -0
- package/dist/cjs/common/internal-service-auth.js.map +1 -0
- package/dist/cjs/common/money.js +215 -0
- package/dist/cjs/common/money.js.map +1 -0
- package/dist/cjs/common/phone.js +63 -11
- package/dist/cjs/common/phone.js.map +1 -1
- package/dist/cjs/common/response.js +78 -5
- package/dist/cjs/common/response.js.map +1 -1
- package/dist/cjs/common/time.js +28 -2
- package/dist/cjs/common/time.js.map +1 -1
- package/dist/cjs/config/index.js +140 -20
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/context/index.js +49 -0
- package/dist/cjs/context/index.js.map +1 -0
- package/dist/cjs/contracts/index.js +0 -2
- package/dist/cjs/contracts/index.js.map +1 -1
- package/dist/cjs/contracts/notification-dispatch.js +87 -63
- package/dist/cjs/contracts/notification-dispatch.js.map +1 -1
- package/dist/cjs/database/db.js +37 -0
- package/dist/cjs/database/db.js.map +1 -0
- package/dist/cjs/database/index.js +22 -51
- package/dist/cjs/database/index.js.map +1 -1
- package/dist/cjs/database/pagination.js +88 -0
- package/dist/cjs/database/pagination.js.map +1 -0
- package/dist/cjs/database/pool.js +60 -0
- package/dist/cjs/database/pool.js.map +1 -0
- package/dist/cjs/database/scoped-repository.js +132 -0
- package/dist/cjs/database/scoped-repository.js.map +1 -0
- package/dist/cjs/database/scopes.js +166 -0
- package/dist/cjs/database/scopes.js.map +1 -0
- package/dist/cjs/database/table-names.js +14 -0
- package/dist/cjs/database/table-names.js.map +1 -0
- package/dist/cjs/database/tables.js +71 -0
- package/dist/cjs/database/tables.js.map +1 -0
- package/dist/cjs/express/auth.js +88 -41
- package/dist/cjs/express/auth.js.map +1 -1
- package/dist/cjs/express/index.js +3 -0
- package/dist/cjs/express/index.js.map +1 -1
- package/dist/cjs/express/internal-caller.js +52 -0
- package/dist/cjs/express/internal-caller.js.map +1 -0
- package/dist/cjs/express/middleware.js +154 -34
- package/dist/cjs/express/middleware.js.map +1 -1
- package/dist/cjs/express/respond.js +47 -0
- package/dist/cjs/express/respond.js.map +1 -0
- package/dist/cjs/express/step-up.js +41 -0
- package/dist/cjs/express/step-up.js.map +1 -0
- package/dist/cjs/http/index.js +3 -71
- package/dist/cjs/http/index.js.map +1 -1
- package/dist/cjs/identity/index.js +269 -67
- package/dist/cjs/identity/index.js.map +1 -1
- package/dist/cjs/identity/step-up.js +52 -0
- package/dist/cjs/identity/step-up.js.map +1 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/knex/columns.js +36 -0
- package/dist/cjs/knex/columns.js.map +1 -0
- package/dist/cjs/knex/index.js +26 -43
- package/dist/cjs/knex/index.js.map +1 -1
- package/dist/cjs/knex/migration-helpers.js +57 -0
- package/dist/cjs/knex/migration-helpers.js.map +1 -0
- package/dist/cjs/logging/index.js +76 -40
- package/dist/cjs/logging/index.js.map +1 -1
- package/dist/cjs/logging/redact.js +112 -0
- package/dist/cjs/logging/redact.js.map +1 -0
- package/dist/cjs/messaging/base-consumer.js +36 -0
- package/dist/cjs/messaging/base-consumer.js.map +1 -0
- package/dist/cjs/messaging/consumer.js +142 -73
- package/dist/cjs/messaging/consumer.js.map +1 -1
- package/dist/cjs/messaging/envelope.js +53 -10
- package/dist/cjs/messaging/envelope.js.map +1 -1
- package/dist/cjs/messaging/idempotency.js +95 -8
- package/dist/cjs/messaging/idempotency.js.map +1 -1
- package/dist/cjs/messaging/index.js +3 -1
- package/dist/cjs/messaging/index.js.map +1 -1
- package/dist/cjs/messaging/outbox.js +97 -55
- package/dist/cjs/messaging/outbox.js.map +1 -1
- package/dist/cjs/messaging/publisher.js +86 -38
- package/dist/cjs/messaging/publisher.js.map +1 -1
- package/dist/cjs/messaging/staff-notifier.js +36 -44
- package/dist/cjs/messaging/staff-notifier.js.map +1 -1
- package/dist/cjs/messaging/staff-recipients.js +57 -0
- package/dist/cjs/messaging/staff-recipients.js.map +1 -0
- package/dist/cjs/messaging/topology.js +41 -5
- package/dist/cjs/messaging/topology.js.map +1 -1
- package/dist/cjs/rate-limit/index.js +57 -6
- package/dist/cjs/rate-limit/index.js.map +1 -1
- package/dist/cjs/rate-limit/keys.js +47 -0
- package/dist/cjs/rate-limit/keys.js.map +1 -0
- package/dist/cjs/socket/index.js +127 -16
- package/dist/cjs/socket/index.js.map +1 -1
- package/dist/cjs/socket/ticket.js +124 -0
- package/dist/cjs/socket/ticket.js.map +1 -0
- package/dist/cjs/testing/index.js +23 -14
- package/dist/cjs/testing/index.js.map +1 -1
- package/dist/cjs/validation/index.js +27 -3
- package/dist/cjs/validation/index.js.map +1 -1
- package/dist/esm/access/index.js +9 -1
- package/dist/esm/access/index.js.map +1 -1
- package/dist/esm/approvals/index.js +127 -0
- package/dist/esm/approvals/index.js.map +1 -0
- package/dist/esm/audit/index.js +70 -0
- package/dist/esm/audit/index.js.map +1 -0
- package/dist/esm/cache/index.js +70 -13
- package/dist/esm/cache/index.js.map +1 -1
- package/dist/esm/cache/keyspace.js +95 -0
- package/dist/esm/cache/keyspace.js.map +1 -0
- package/dist/esm/common/circuit-breaker.js +70 -0
- package/dist/esm/common/circuit-breaker.js.map +1 -0
- package/dist/esm/common/errors.js +42 -4
- package/dist/esm/common/errors.js.map +1 -1
- package/dist/esm/common/index.js +4 -0
- package/dist/esm/common/index.js.map +1 -1
- package/dist/esm/common/internal-client.js +173 -0
- package/dist/esm/common/internal-client.js.map +1 -0
- package/dist/esm/common/internal-constants.js +9 -0
- package/dist/esm/common/internal-constants.js.map +1 -0
- package/dist/esm/common/internal-service-auth.js +150 -0
- package/dist/esm/common/internal-service-auth.js.map +1 -0
- package/dist/esm/common/money.js +207 -0
- package/dist/esm/common/money.js.map +1 -0
- package/dist/esm/common/phone.js +63 -11
- package/dist/esm/common/phone.js.map +1 -1
- package/dist/esm/common/response.js +75 -5
- package/dist/esm/common/response.js.map +1 -1
- package/dist/esm/common/time.js +27 -2
- package/dist/esm/common/time.js.map +1 -1
- package/dist/esm/config/index.js +136 -19
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/context/index.js +44 -0
- package/dist/esm/context/index.js.map +1 -0
- package/dist/esm/contracts/index.js +0 -2
- package/dist/esm/contracts/index.js.map +1 -1
- package/dist/esm/contracts/notification-dispatch.js +85 -62
- package/dist/esm/contracts/notification-dispatch.js.map +1 -1
- package/dist/esm/database/db.js +32 -0
- package/dist/esm/database/db.js.map +1 -0
- package/dist/esm/database/index.js +9 -45
- package/dist/esm/database/index.js.map +1 -1
- package/dist/esm/database/pagination.js +81 -0
- package/dist/esm/database/pagination.js.map +1 -0
- package/dist/esm/database/pool.js +51 -0
- package/dist/esm/database/pool.js.map +1 -0
- package/dist/esm/database/scoped-repository.js +128 -0
- package/dist/esm/database/scoped-repository.js.map +1 -0
- package/dist/esm/database/scopes.js +157 -0
- package/dist/esm/database/scopes.js.map +1 -0
- package/dist/esm/database/table-names.js +11 -0
- package/dist/esm/database/table-names.js.map +1 -0
- package/dist/esm/database/tables.js +61 -0
- package/dist/esm/database/tables.js.map +1 -0
- package/dist/esm/express/auth.js +87 -40
- package/dist/esm/express/auth.js.map +1 -1
- package/dist/esm/express/index.js +3 -0
- package/dist/esm/express/index.js.map +1 -1
- package/dist/esm/express/internal-caller.js +49 -0
- package/dist/esm/express/internal-caller.js.map +1 -0
- package/dist/esm/express/middleware.js +146 -27
- package/dist/esm/express/middleware.js.map +1 -1
- package/dist/esm/express/respond.js +42 -0
- package/dist/esm/express/respond.js.map +1 -0
- package/dist/esm/express/step-up.js +38 -0
- package/dist/esm/express/step-up.js.map +1 -0
- package/dist/esm/http/index.js +3 -70
- package/dist/esm/http/index.js.map +1 -1
- package/dist/esm/identity/index.js +246 -64
- package/dist/esm/identity/index.js.map +1 -1
- package/dist/esm/identity/step-up.js +47 -0
- package/dist/esm/identity/step-up.js.map +1 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/knex/columns.js +28 -0
- package/dist/esm/knex/columns.js.map +1 -0
- package/dist/esm/knex/index.js +8 -34
- package/dist/esm/knex/index.js.map +1 -1
- package/dist/esm/knex/migration-helpers.js +51 -0
- package/dist/esm/knex/migration-helpers.js.map +1 -0
- package/dist/esm/logging/index.js +68 -39
- package/dist/esm/logging/index.js.map +1 -1
- package/dist/esm/logging/redact.js +106 -0
- package/dist/esm/logging/redact.js.map +1 -0
- package/dist/esm/messaging/base-consumer.js +32 -0
- package/dist/esm/messaging/base-consumer.js.map +1 -0
- package/dist/esm/messaging/consumer.js +139 -71
- package/dist/esm/messaging/consumer.js.map +1 -1
- package/dist/esm/messaging/envelope.js +50 -10
- package/dist/esm/messaging/envelope.js.map +1 -1
- package/dist/esm/messaging/idempotency.js +91 -7
- package/dist/esm/messaging/idempotency.js.map +1 -1
- package/dist/esm/messaging/index.js +3 -1
- package/dist/esm/messaging/index.js.map +1 -1
- package/dist/esm/messaging/outbox.js +97 -54
- package/dist/esm/messaging/outbox.js.map +1 -1
- package/dist/esm/messaging/publisher.js +86 -38
- package/dist/esm/messaging/publisher.js.map +1 -1
- package/dist/esm/messaging/staff-notifier.js +36 -43
- package/dist/esm/messaging/staff-notifier.js.map +1 -1
- package/dist/esm/messaging/staff-recipients.js +53 -0
- package/dist/esm/messaging/staff-recipients.js.map +1 -0
- package/dist/esm/messaging/topology.js +39 -4
- package/dist/esm/messaging/topology.js.map +1 -1
- package/dist/esm/rate-limit/index.js +41 -6
- package/dist/esm/rate-limit/index.js.map +1 -1
- package/dist/esm/rate-limit/keys.js +43 -0
- package/dist/esm/rate-limit/keys.js.map +1 -0
- package/dist/esm/socket/index.js +112 -17
- package/dist/esm/socket/index.js.map +1 -1
- package/dist/esm/socket/ticket.js +117 -0
- package/dist/esm/socket/ticket.js.map +1 -0
- package/dist/esm/testing/index.js +24 -15
- package/dist/esm/testing/index.js.map +1 -1
- package/dist/esm/validation/index.js +27 -2
- package/dist/esm/validation/index.js.map +1 -1
- package/dist/types/access/index.d.ts +9 -3
- package/dist/types/access/index.d.ts.map +1 -1
- package/dist/types/alerting/index.d.ts +1 -1
- package/dist/types/alerting/index.d.ts.map +1 -1
- package/dist/types/approvals/index.d.ts +99 -0
- package/dist/types/approvals/index.d.ts.map +1 -0
- package/dist/types/audit/index.d.ts +82 -0
- package/dist/types/audit/index.d.ts.map +1 -0
- package/dist/types/cache/index.d.ts +64 -14
- package/dist/types/cache/index.d.ts.map +1 -1
- package/dist/types/cache/keyspace.d.ts +84 -0
- package/dist/types/cache/keyspace.d.ts.map +1 -0
- package/dist/types/common/circuit-breaker.d.ts +51 -0
- package/dist/types/common/circuit-breaker.d.ts.map +1 -0
- package/dist/types/common/errors.d.ts +48 -7
- package/dist/types/common/errors.d.ts.map +1 -1
- package/dist/types/common/index.d.ts +4 -0
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/internal-client.d.ts +116 -0
- package/dist/types/common/internal-client.d.ts.map +1 -0
- package/dist/types/common/internal-constants.d.ts +9 -0
- package/dist/types/common/internal-constants.d.ts.map +1 -0
- package/dist/types/common/internal-service-auth.d.ts +102 -0
- package/dist/types/common/internal-service-auth.d.ts.map +1 -0
- package/dist/types/common/money.d.ts +104 -0
- package/dist/types/common/money.d.ts.map +1 -0
- package/dist/types/common/phone.d.ts +45 -6
- package/dist/types/common/phone.d.ts.map +1 -1
- package/dist/types/common/response.d.ts +66 -5
- package/dist/types/common/response.d.ts.map +1 -1
- package/dist/types/common/time.d.ts +20 -2
- package/dist/types/common/time.d.ts.map +1 -1
- package/dist/types/config/index.d.ts +252 -28
- package/dist/types/config/index.d.ts.map +1 -1
- package/dist/types/context/index.d.ts +39 -0
- package/dist/types/context/index.d.ts.map +1 -0
- package/dist/types/contracts/index.d.ts +0 -2
- package/dist/types/contracts/index.d.ts.map +1 -1
- package/dist/types/contracts/notification-dispatch.d.ts +204 -86
- package/dist/types/contracts/notification-dispatch.d.ts.map +1 -1
- package/dist/types/database/db.d.ts +46 -0
- package/dist/types/database/db.d.ts.map +1 -0
- package/dist/types/database/index.d.ts +9 -22
- package/dist/types/database/index.d.ts.map +1 -1
- package/dist/types/database/pagination.d.ts +68 -0
- package/dist/types/database/pagination.d.ts.map +1 -0
- package/dist/types/database/pool.d.ts +39 -0
- package/dist/types/database/pool.d.ts.map +1 -0
- package/dist/types/database/scoped-repository.d.ts +92 -0
- package/dist/types/database/scoped-repository.d.ts.map +1 -0
- package/dist/types/database/scopes.d.ts +159 -0
- package/dist/types/database/scopes.d.ts.map +1 -0
- package/dist/types/database/table-names.d.ts +13 -0
- package/dist/types/database/table-names.d.ts.map +1 -0
- package/dist/types/database/tables.d.ts +748 -0
- package/dist/types/database/tables.d.ts.map +1 -0
- package/dist/types/express/auth.d.ts +63 -11
- package/dist/types/express/auth.d.ts.map +1 -1
- package/dist/types/express/index.d.ts +3 -0
- package/dist/types/express/index.d.ts.map +1 -1
- package/dist/types/express/internal-caller.d.ts +53 -0
- package/dist/types/express/internal-caller.d.ts.map +1 -0
- package/dist/types/express/middleware.d.ts +86 -7
- package/dist/types/express/middleware.d.ts.map +1 -1
- package/dist/types/express/respond.d.ts +41 -0
- package/dist/types/express/respond.d.ts.map +1 -0
- package/dist/types/express/step-up.d.ts +38 -0
- package/dist/types/express/step-up.d.ts.map +1 -0
- package/dist/types/http/index.d.ts +3 -31
- package/dist/types/http/index.d.ts.map +1 -1
- package/dist/types/identity/index.d.ts +159 -21
- package/dist/types/identity/index.d.ts.map +1 -1
- package/dist/types/identity/step-up.d.ts +41 -0
- package/dist/types/identity/step-up.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/knex/columns.d.ts +15 -0
- package/dist/types/knex/columns.d.ts.map +1 -0
- package/dist/types/knex/index.d.ts +3 -11
- package/dist/types/knex/index.d.ts.map +1 -1
- package/dist/types/knex/migration-helpers.d.ts +28 -0
- package/dist/types/knex/migration-helpers.d.ts.map +1 -0
- package/dist/types/logging/index.d.ts +30 -4
- package/dist/types/logging/index.d.ts.map +1 -1
- package/dist/types/logging/redact.d.ts +54 -0
- package/dist/types/logging/redact.d.ts.map +1 -0
- package/dist/types/messaging/base-consumer.d.ts +33 -0
- package/dist/types/messaging/base-consumer.d.ts.map +1 -0
- package/dist/types/messaging/consumer.d.ts +59 -21
- package/dist/types/messaging/consumer.d.ts.map +1 -1
- package/dist/types/messaging/envelope.d.ts +50 -11
- package/dist/types/messaging/envelope.d.ts.map +1 -1
- package/dist/types/messaging/idempotency.d.ts +60 -3
- package/dist/types/messaging/idempotency.d.ts.map +1 -1
- package/dist/types/messaging/index.d.ts +8 -0
- package/dist/types/messaging/index.d.ts.map +1 -1
- package/dist/types/messaging/outbox.d.ts +62 -22
- package/dist/types/messaging/outbox.d.ts.map +1 -1
- package/dist/types/messaging/publisher.d.ts +54 -21
- package/dist/types/messaging/publisher.d.ts.map +1 -1
- package/dist/types/messaging/staff-notifier.d.ts +69 -38
- package/dist/types/messaging/staff-notifier.d.ts.map +1 -1
- package/dist/types/messaging/staff-recipients.d.ts +50 -0
- package/dist/types/messaging/staff-recipients.d.ts.map +1 -0
- package/dist/types/messaging/topology.d.ts +40 -8
- package/dist/types/messaging/topology.d.ts.map +1 -1
- package/dist/types/rate-limit/index.d.ts +40 -4
- package/dist/types/rate-limit/index.d.ts.map +1 -1
- package/dist/types/rate-limit/keys.d.ts +52 -0
- package/dist/types/rate-limit/keys.d.ts.map +1 -0
- package/dist/types/socket/index.d.ts +86 -2
- package/dist/types/socket/index.d.ts.map +1 -1
- package/dist/types/socket/ticket.d.ts +90 -0
- package/dist/types/socket/ticket.d.ts.map +1 -0
- package/dist/types/testing/index.d.ts +31 -10
- package/dist/types/testing/index.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +62 -15
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/validation/index.d.ts +33 -2
- package/dist/types/validation/index.d.ts.map +1 -1
- package/package.json +3 -1
- package/dist/cjs/contracts/editorial-draft.js +0 -120
- package/dist/cjs/contracts/editorial-draft.js.map +0 -1
- package/dist/cjs/contracts/upload-import.js +0 -54
- package/dist/cjs/contracts/upload-import.js.map +0 -1
- package/dist/esm/contracts/editorial-draft.js +0 -117
- package/dist/esm/contracts/editorial-draft.js.map +0 -1
- package/dist/esm/contracts/upload-import.js +0 -51
- package/dist/esm/contracts/upload-import.js.map +0 -1
- package/dist/types/contracts/editorial-draft.d.ts +0 -610
- package/dist/types/contracts/editorial-draft.d.ts.map +0 -1
- package/dist/types/contracts/upload-import.d.ts +0 -96
- package/dist/types/contracts/upload-import.d.ts.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CORRELATION_ID_PATTERN = void 0;
|
|
3
4
|
exports.correlationMiddleware = correlationMiddleware;
|
|
4
5
|
exports.correlationId = correlationId;
|
|
5
6
|
exports.clientIp = clientIp;
|
|
@@ -12,84 +13,203 @@ exports.notFoundHandler = notFoundHandler;
|
|
|
12
13
|
const errors_js_1 = require("../common/errors.js");
|
|
13
14
|
const id_js_1 = require("../common/id.js");
|
|
14
15
|
const response_js_1 = require("../common/response.js");
|
|
15
|
-
const index_js_1 = require("../
|
|
16
|
-
const index_js_2 = require("../
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const index_js_1 = require("../context/index.js");
|
|
17
|
+
const index_js_2 = require("../identity/index.js");
|
|
18
|
+
const index_js_3 = require("../validation/index.js");
|
|
19
|
+
/** An incoming correlation id is trusted only if it is 8–64 chars of `[A-Za-z0-9-]` (no log injection). */
|
|
20
|
+
exports.CORRELATION_ID_PATTERN = /^[A-Za-z0-9-]{8,64}$/;
|
|
21
|
+
/**
|
|
22
|
+
* Gives every request one correlation id and runs the rest of the request inside a
|
|
23
|
+
* {@link RequestContext}. A valid incoming `x-correlation-id` (see {@link CORRELATION_ID_PATTERN}) is
|
|
24
|
+
* kept; anything else is replaced with a new ULID. The id is echoed on the response, written back to
|
|
25
|
+
* the request header (so outbound calls forward it) and becomes every error body's `requestId`.
|
|
26
|
+
* Mount it first: correlation → json → routes → notFoundHandler → errorHandler.
|
|
27
|
+
*
|
|
28
|
+
* @param serviceName Recorded in the context (and so in log lines written without a service).
|
|
29
|
+
* @returns Express middleware.
|
|
30
|
+
* @example app.use(correlationMiddleware('orders'));
|
|
31
|
+
*/
|
|
32
|
+
function correlationMiddleware(serviceName) {
|
|
19
33
|
return (req, res, next) => {
|
|
20
|
-
const incoming = req.headers[
|
|
21
|
-
const id = typeof incoming === 'string' && incoming
|
|
22
|
-
req.headers[
|
|
23
|
-
res.setHeader(
|
|
24
|
-
|
|
34
|
+
const incoming = req.headers[index_js_2.CONTEXT_HEADERS.CORRELATION_ID];
|
|
35
|
+
const id = typeof incoming === 'string' && exports.CORRELATION_ID_PATTERN.test(incoming) ? incoming : (0, id_js_1.newId)();
|
|
36
|
+
req.headers[index_js_2.CONTEXT_HEADERS.CORRELATION_ID] = id;
|
|
37
|
+
res.setHeader(index_js_2.CONTEXT_HEADERS.CORRELATION_ID, id);
|
|
38
|
+
(0, index_js_1.runWithContext)({ correlationId: id, service: serviceName }, next);
|
|
25
39
|
};
|
|
26
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The request's correlation id (the source of every error body's `requestId`): the active request
|
|
43
|
+
* context's id, else the `x-correlation-id` header.
|
|
44
|
+
*
|
|
45
|
+
* @param req Express request.
|
|
46
|
+
* @returns The id, or undefined when neither is present.
|
|
47
|
+
* @example logger.info('Order placed', { correlationId: correlationId(req) });
|
|
48
|
+
*/
|
|
27
49
|
function correlationId(req) {
|
|
28
|
-
const
|
|
50
|
+
const fromContext = (0, index_js_1.getRequestContext)()?.correlationId;
|
|
51
|
+
if (fromContext)
|
|
52
|
+
return fromContext;
|
|
53
|
+
const value = req.headers[index_js_2.CONTEXT_HEADERS.CORRELATION_ID];
|
|
29
54
|
return typeof value === 'string' ? value : undefined;
|
|
30
55
|
}
|
|
31
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Real client IP: gateway-forwarded header first, then Express's `req.ip`.
|
|
58
|
+
*
|
|
59
|
+
* @param req Express request.
|
|
60
|
+
* @returns The IP, or null when unknown.
|
|
61
|
+
* @example const ip = clientIp(req);
|
|
62
|
+
*/
|
|
32
63
|
function clientIp(req) {
|
|
33
|
-
const forwarded = req.headers[
|
|
64
|
+
const forwarded = req.headers[index_js_2.CONTEXT_HEADERS.CLIENT_IP];
|
|
34
65
|
if (typeof forwarded === 'string' && forwarded)
|
|
35
66
|
return forwarded;
|
|
36
67
|
return req.ip ?? null;
|
|
37
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* The caller's IANA time zone as forwarded by the gateway.
|
|
71
|
+
*
|
|
72
|
+
* @param req Express request.
|
|
73
|
+
* @returns e.g. `Europe/Paris`, or null when not sent.
|
|
74
|
+
* @example formatInTimeZone(date, clientTimezone(req) ?? 'UTC');
|
|
75
|
+
*/
|
|
38
76
|
function clientTimezone(req) {
|
|
39
|
-
const tz = req.headers[
|
|
77
|
+
const tz = req.headers[index_js_2.CONTEXT_HEADERS.TIMEZONE];
|
|
40
78
|
return typeof tz === 'string' && tz ? tz : null;
|
|
41
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* The anonymous visitor id forwarded by the gateway (for anonymous visitor state, rate limits and analytics).
|
|
82
|
+
*
|
|
83
|
+
* @param req Express request.
|
|
84
|
+
* @returns The id, or null when not sent.
|
|
85
|
+
* @example const visitor = req.user?.id ?? anonId(req);
|
|
86
|
+
*/
|
|
42
87
|
function anonId(req) {
|
|
43
|
-
const id = req.headers[
|
|
88
|
+
const id = req.headers[index_js_2.CONTEXT_HEADERS.ANON_ID];
|
|
44
89
|
return typeof id === 'string' && id ? id : null;
|
|
45
90
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
91
|
+
const PART_ORDER = ['params', 'query', 'body'];
|
|
92
|
+
/** Field-error keys: body fields keep their own path; params/query are prefixed (`query.limit`). */
|
|
93
|
+
function prefixErrors(part, errors) {
|
|
94
|
+
if (part === 'body')
|
|
95
|
+
return errors;
|
|
96
|
+
return Object.fromEntries(Object.entries(errors).map(([key, messages]) => [key === '_' ? part : `${part}.${key}`, messages]));
|
|
97
|
+
}
|
|
98
|
+
function isSchema(value) {
|
|
99
|
+
return typeof value?.safeParse === 'function';
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validates the request with Zod at the controller boundary. Each given part is parsed and
|
|
103
|
+
* `req[part]` is replaced with the parsed value, so unknown keys are stripped (or rejected with
|
|
104
|
+
* `.strict()`) and coercions/defaults apply. Every part is checked before failing, and the combined
|
|
105
|
+
* field errors are thrown as a 422 {@link ValidationError} for the error handler (body fields keep
|
|
106
|
+
* their path; params and query fields are prefixed, e.g. `params.id`).
|
|
107
|
+
*
|
|
108
|
+
* The older single-schema form `validate(schema, part = 'body')` still works.
|
|
109
|
+
*
|
|
110
|
+
* @param schemas `{ params?, query?, body? }`, or one schema.
|
|
111
|
+
* @param part With a single schema: the part it checks (default `body`).
|
|
112
|
+
* @returns Express middleware.
|
|
113
|
+
* @example router.patch('/:id', validate({ params: idParam, body: updateSchema }), controller.update);
|
|
114
|
+
*/
|
|
115
|
+
function validate(schemas, part = 'body') {
|
|
116
|
+
const parts = isSchema(schemas) ? { [part]: schemas } : schemas;
|
|
117
|
+
return (req, _res, next) => {
|
|
118
|
+
let errors = {};
|
|
119
|
+
const parsed = {};
|
|
120
|
+
for (const name of PART_ORDER) {
|
|
121
|
+
const schema = parts[name];
|
|
122
|
+
if (!schema)
|
|
123
|
+
continue;
|
|
124
|
+
const result = schema.safeParse(req[name]);
|
|
125
|
+
if (result.success)
|
|
126
|
+
parsed[name] = result.data;
|
|
127
|
+
else
|
|
128
|
+
errors = { ...errors, ...prefixErrors(name, (0, index_js_3.zodIssuesToErrors)(result.error)) };
|
|
129
|
+
}
|
|
130
|
+
if (Object.keys(errors).length > 0) {
|
|
131
|
+
next(new errors_js_1.ValidationError(errors));
|
|
52
132
|
return;
|
|
53
133
|
}
|
|
54
|
-
|
|
55
|
-
|
|
134
|
+
for (const [name, value] of Object.entries(parsed)) {
|
|
135
|
+
// Express 5 exposes req.query as a getter; redefine to store the parsed value.
|
|
136
|
+
Object.defineProperty(req, name, { value, writable: true, configurable: true, enumerable: true });
|
|
137
|
+
}
|
|
56
138
|
next();
|
|
57
139
|
};
|
|
58
140
|
}
|
|
59
|
-
/**
|
|
141
|
+
/**
|
|
142
|
+
* Wraps an async handler so rejections reach the error middleware (needed on Express 4; harmless on 5).
|
|
143
|
+
*
|
|
144
|
+
* @param fn Async route handler.
|
|
145
|
+
* @returns A handler that forwards rejections to `next(err)`.
|
|
146
|
+
* @example router.get('/:id', asyncHandler(controller.get));
|
|
147
|
+
*/
|
|
60
148
|
function asyncHandler(fn) {
|
|
61
149
|
return (req, res, next) => {
|
|
62
150
|
fn(req, res, next).catch(next);
|
|
63
151
|
};
|
|
64
152
|
}
|
|
65
|
-
/**
|
|
153
|
+
/** Zod's error, recognised structurally so a service on another zod copy/version still maps to 422. */
|
|
154
|
+
function isZodError(err) {
|
|
155
|
+
return err instanceof Error && err.name === 'ZodError' && Array.isArray(err.issues);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Last error middleware. Every body is `{ success: false, code, message, errors?, requestId }`:
|
|
159
|
+
* - body-parser failures → 400 BAD_REQUEST / 413 PAYLOAD_TOO_LARGE;
|
|
160
|
+
* - a thrown ZodError (e.g. from `schema.parse`) → 422 VALIDATION_FAILED with field errors;
|
|
161
|
+
* - AppError → its status, code and errors; 4xx keep their message, 5xx get a generic one; a
|
|
162
|
+
* `retryAfterSeconds` becomes the `Retry-After` header;
|
|
163
|
+
* - anything else → logged in full, answered 500 INTERNAL_ERROR with a generic message.
|
|
164
|
+
* `requestId` is the request context's correlation id (set by {@link correlationMiddleware}).
|
|
165
|
+
*
|
|
166
|
+
* @param logger Receives 5xx details (message, stack, path, correlation id); never sent to the client.
|
|
167
|
+
* @returns Express error middleware.
|
|
168
|
+
* @example app.use(notFoundHandler()); app.use(errorHandler(logger));
|
|
169
|
+
*/
|
|
66
170
|
function errorHandler(logger) {
|
|
67
|
-
return (err, req, res,
|
|
68
|
-
if (res.headersSent)
|
|
171
|
+
return (err, req, res, next) => {
|
|
172
|
+
if (res.headersSent) {
|
|
173
|
+
next(err);
|
|
69
174
|
return;
|
|
175
|
+
}
|
|
176
|
+
const requestId = correlationId(req);
|
|
70
177
|
const bodyError = err;
|
|
71
178
|
if (bodyError?.type === 'entity.parse.failed') {
|
|
72
|
-
res.status(400).json((0, response_js_1.
|
|
179
|
+
res.status(400).json((0, response_js_1.errorBody)('BAD_REQUEST', 'Malformed JSON body', { requestId }));
|
|
73
180
|
return;
|
|
74
181
|
}
|
|
75
182
|
if (bodyError?.type === 'entity.too.large') {
|
|
76
|
-
res.status(413).json((0, response_js_1.
|
|
183
|
+
res.status(413).json((0, response_js_1.errorBody)('PAYLOAD_TOO_LARGE', 'Request body too large', { requestId }));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (isZodError(err)) {
|
|
187
|
+
res.status(422).json((0, response_js_1.errorBody)('VALIDATION_FAILED', 'Validation failed', { errors: (0, index_js_3.zodIssuesToErrors)(err), requestId }));
|
|
77
188
|
return;
|
|
78
189
|
}
|
|
79
190
|
if ((0, errors_js_1.isAppError)(err)) {
|
|
80
191
|
if (err.statusCode >= 500)
|
|
81
|
-
logger?.error(err.message, { path: req.path,
|
|
82
|
-
|
|
192
|
+
logger?.error(err.message, { path: req.path, errorCode: err.code, stack: err.stack, correlationId: requestId });
|
|
193
|
+
if (err.retryAfterSeconds !== undefined)
|
|
194
|
+
res.setHeader('Retry-After', String(Math.max(0, Math.ceil(err.retryAfterSeconds))));
|
|
195
|
+
const errors = err.statusCode < 500 ? err.errors : undefined;
|
|
196
|
+
res.status(err.statusCode).json((0, response_js_1.errorBody)(err.code, (0, errors_js_1.publicMessage)(err), { errors, requestId }));
|
|
83
197
|
return;
|
|
84
198
|
}
|
|
85
199
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
86
|
-
logger?.error('Unhandled error', { error: error.message, stack: error.stack, path: req.path, correlationId:
|
|
87
|
-
res.status(500).json((0, response_js_1.
|
|
200
|
+
logger?.error('Unhandled error', { error: error.message, stack: error.stack, path: req.path, correlationId: requestId });
|
|
201
|
+
res.status(500).json((0, response_js_1.errorBody)('INTERNAL_ERROR', errors_js_1.GENERIC_ERROR_MESSAGE, { requestId }));
|
|
88
202
|
};
|
|
89
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Catch-all for unmatched routes: 404 NOT_FOUND with the request id. Mount after every router.
|
|
206
|
+
*
|
|
207
|
+
* @returns Express middleware.
|
|
208
|
+
* @example app.use(notFoundHandler()); app.use(errorHandler(logger));
|
|
209
|
+
*/
|
|
90
210
|
function notFoundHandler() {
|
|
91
|
-
return (
|
|
92
|
-
res.status(404).json((0, response_js_1.
|
|
211
|
+
return (req, res) => {
|
|
212
|
+
res.status(404).json((0, response_js_1.errorBody)('NOT_FOUND', 'Resource not found', { requestId: correlationId(req) }));
|
|
93
213
|
};
|
|
94
214
|
}
|
|
95
215
|
//# sourceMappingURL=middleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/express/middleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/express/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ok = ok;
|
|
4
|
+
exports.created = created;
|
|
5
|
+
exports.okPage = okPage;
|
|
6
|
+
const response_js_1 = require("../common/response.js");
|
|
7
|
+
/**
|
|
8
|
+
* 200 with the success envelope.
|
|
9
|
+
*
|
|
10
|
+
* @param res Express response.
|
|
11
|
+
* @param data The payload placed under `data`.
|
|
12
|
+
* @param message Optional human-readable message (default `Success`).
|
|
13
|
+
* @param meta Optional list metadata.
|
|
14
|
+
* @returns The Express response.
|
|
15
|
+
* @example ok(res, product, 'Product updated');
|
|
16
|
+
*/
|
|
17
|
+
function ok(res, data, message, meta) {
|
|
18
|
+
const body = (0, response_js_1.successResponse)(data, message);
|
|
19
|
+
return res.status(200).json(meta ? { ...body, meta } : body);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 201 with the success envelope, for a newly created resource.
|
|
23
|
+
*
|
|
24
|
+
* @param res Express response.
|
|
25
|
+
* @param data The created resource (or its id).
|
|
26
|
+
* @param message Optional message (default `Created`).
|
|
27
|
+
* @returns The Express response.
|
|
28
|
+
*
|
|
29
|
+
* @example created(res, { id }, 'Shop created');
|
|
30
|
+
*/
|
|
31
|
+
function created(res, data, message = 'Created') {
|
|
32
|
+
return res.status(201).json((0, response_js_1.successResponse)(data, message));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 200 with a cursor-paginated list: `data` is the items, `meta` is `{ limit, nextCursor, hasMore }`.
|
|
36
|
+
*
|
|
37
|
+
* @param res Express response.
|
|
38
|
+
* @param page The page from the service (see `buildCursorPageMeta`).
|
|
39
|
+
* @param message Optional message.
|
|
40
|
+
* @returns The Express response.
|
|
41
|
+
*
|
|
42
|
+
* @example okPage(res, await service.list(scope, { cursor, limit }));
|
|
43
|
+
*/
|
|
44
|
+
function okPage(res, page, message) {
|
|
45
|
+
return res.status(200).json((0, response_js_1.cursorPaginatedResponse)(page, message));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=respond.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"respond.js","sourceRoot":"","sources":["../../../src/express/respond.ts"],"names":[],"mappings":";;AAmBA,gBAGC;AAYD,0BAEC;AAYD,wBAEC;AA5CD,uDAAiF;AAGjF;;;;;;;;;GASG;AACH,SAAgB,EAAE,CAAI,GAAa,EAAE,IAAO,EAAE,OAAgB,EAAE,IAAsC;IACpG,MAAM,IAAI,GAAG,IAAA,6BAAe,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,OAAO,CAAI,GAAa,EAAE,IAAO,EAAE,OAAO,GAAG,SAAS;IACpE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAA,6BAAe,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,MAAM,CAAI,GAAa,EAAE,IAAmB,EAAE,OAAgB;IAC5E,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAA,qCAAuB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStepUpGuards = createStepUpGuards;
|
|
4
|
+
const response_js_1 = require("../common/response.js");
|
|
5
|
+
const step_up_js_1 = require("../identity/step-up.js");
|
|
6
|
+
const middleware_js_1 = require("./middleware.js");
|
|
7
|
+
/**
|
|
8
|
+
* Builds the step-up guard for an app's catalogue. Must run after `authenticateFromGateway`, which sets
|
|
9
|
+
* `req.user.stepUpAt` only from the signed `x-step-up-at` header. Single-use proofs are consumed by the
|
|
10
|
+
* gateway; the service sees only the verified time. Throws at startup for an unknown scope or a bad window.
|
|
11
|
+
*
|
|
12
|
+
* @param options Catalogue, freshness window and clock.
|
|
13
|
+
* @returns `requireStepUp(scope, route?)` and `declaredStepUpRoutes()`.
|
|
14
|
+
* @example
|
|
15
|
+
* const { requireStepUp } = createStepUpGuards({ catalogue: stepUpScopes });
|
|
16
|
+
* router.post('/refunds/:id', requirePermission('refunds.create'), requireStepUp('refund-large', 'POST /refunds/:id'), controller.refund);
|
|
17
|
+
*/
|
|
18
|
+
function createStepUpGuards(options) {
|
|
19
|
+
const windowMs = options.windowMs ?? step_up_js_1.DEFAULT_STEP_UP_WINDOW_MS;
|
|
20
|
+
if (!Number.isFinite(windowMs) || windowMs <= 0)
|
|
21
|
+
throw new Error(`createStepUpGuards: windowMs must be positive (got ${windowMs})`);
|
|
22
|
+
const now = options.now ?? Date.now;
|
|
23
|
+
const declared = [];
|
|
24
|
+
const requireStepUp = (scope, route) => {
|
|
25
|
+
const rules = options.catalogue[scope];
|
|
26
|
+
if (!rules)
|
|
27
|
+
throw new Error(`requireStepUp: unknown step-up scope "${scope}"`);
|
|
28
|
+
declared.push({ scope, singleUse: rules.singleUse === true, ...(route ? { route } : {}) });
|
|
29
|
+
return (req, res, next) => {
|
|
30
|
+
if (!req.user) {
|
|
31
|
+
res.status(401).json((0, response_js_1.errorBody)('UNAUTHENTICATED', 'Authentication required', { requestId: (0, middleware_js_1.correlationId)(req) }));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if ((0, step_up_js_1.stepUpStatus)(req.user.stepUpAt, windowMs, now()) === 'fresh')
|
|
35
|
+
return next();
|
|
36
|
+
res.status(403).json({ ...(0, response_js_1.errorBody)(step_up_js_1.STEP_UP_REQUIRED_CODE, 'Please confirm it is you to continue', { requestId: (0, middleware_js_1.correlationId)(req) }), scope });
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
return { requireStepUp, declaredStepUpRoutes: () => declared.map((entry) => ({ ...entry })) };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=step-up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-up.js","sourceRoot":"","sources":["../../../src/express/step-up.ts"],"names":[],"mappings":";;AA4CA,gDAqBC;AAhED,uDAAkD;AAClD,uDAEgC;AAChC,mDAAgD;AA4BhD;;;;;;;;;;GAUG;AACH,SAAgB,kBAAkB,CAAmB,OAA8B;IACjF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,sCAAyB,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,QAAQ,GAAG,CAAC,CAAC;IACpI,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,QAAQ,GAAkC,EAAE,CAAC;IAEnD,MAAM,aAAa,GAAG,CAAC,KAAQ,EAAE,KAAc,EAAkB,EAAE;QACjE,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,GAAG,CAAC,CAAC;QAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3F,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;YACzD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAA,uBAAS,EAAC,iBAAiB,EAAE,yBAAyB,EAAE,EAAE,SAAS,EAAE,IAAA,6BAAa,EAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBACjH,OAAO;YACT,CAAC;YACD,IAAI,IAAA,yBAAY,EAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO;gBAAE,OAAO,IAAI,EAAE,CAAC;YAChF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAA,uBAAS,EAAC,kCAAqB,EAAE,sCAAsC,EAAE,EAAE,SAAS,EAAE,IAAA,6BAAa,EAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAClJ,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;AAChG,CAAC"}
|
package/dist/cjs/http/index.js
CHANGED
|
@@ -14,77 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.createServiceClient = createServiceClient;
|
|
18
|
-
const errors_js_1 = require("../common/errors.js");
|
|
19
|
-
const async_js_1 = require("../common/async.js");
|
|
20
|
-
const index_js_1 = require("../identity/index.js");
|
|
21
|
-
const index_js_2 = require("../logging/index.js");
|
|
22
|
-
__exportStar(require("./safe-fetch.js"), exports);
|
|
23
|
-
const RETRYABLE_STATUS = new Set([502, 503, 504]);
|
|
24
|
-
const IDEMPOTENT = new Set(['GET', 'PUT', 'DELETE']);
|
|
25
17
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* and timeouts into 503s.
|
|
18
|
+
* Outbound HTTP helpers. Service-to-service calls use `createInternalClient` (root export); calls to
|
|
19
|
+
* tenant-supplied URLs go through the SSRF-guarded {@link createSafeFetcher}.
|
|
29
20
|
*/
|
|
30
|
-
|
|
31
|
-
const logger = options.logger ?? index_js_2.silentLogger;
|
|
32
|
-
const base = options.baseUrl.replace(/\/+$/, '');
|
|
33
|
-
async function request(method, path, opts = {}) {
|
|
34
|
-
const url = new URL(base + path);
|
|
35
|
-
for (const [key, value] of Object.entries(opts.query ?? {}))
|
|
36
|
-
if (value !== undefined)
|
|
37
|
-
url.searchParams.set(key, String(value));
|
|
38
|
-
const retries = IDEMPOTENT.has(method) ? options.retries ?? 2 : 0;
|
|
39
|
-
for (let attempt = 0;; attempt += 1) {
|
|
40
|
-
const controller = new AbortController();
|
|
41
|
-
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? options.timeoutMs ?? 5000);
|
|
42
|
-
try {
|
|
43
|
-
const response = await fetch(url, {
|
|
44
|
-
method,
|
|
45
|
-
signal: controller.signal,
|
|
46
|
-
headers: {
|
|
47
|
-
accept: 'application/json',
|
|
48
|
-
...(opts.body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
49
|
-
[index_js_1.CONTEXT_HEADERS.INTERNAL_SECRET]: options.internalSecret,
|
|
50
|
-
[index_js_1.CONTEXT_HEADERS.CALLER_SERVICE]: options.callerService,
|
|
51
|
-
...(opts.correlationId ? { [index_js_1.CONTEXT_HEADERS.CORRELATION_ID]: opts.correlationId } : {}),
|
|
52
|
-
...opts.headers,
|
|
53
|
-
},
|
|
54
|
-
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
55
|
-
});
|
|
56
|
-
if (RETRYABLE_STATUS.has(response.status) && attempt < retries) {
|
|
57
|
-
await (0, async_js_1.sleep)(200 * 2 ** attempt);
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
const text = await response.text();
|
|
61
|
-
const payload = text ? JSON.parse(text) : { success: response.ok, message: '' };
|
|
62
|
-
if (!response.ok) {
|
|
63
|
-
throw new errors_js_1.AppError(response.status, payload.message || `Upstream error ${response.status}`, { code: payload.code, errors: payload.errors });
|
|
64
|
-
}
|
|
65
|
-
return (payload.data ?? payload);
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
if (error instanceof errors_js_1.AppError)
|
|
69
|
-
throw error;
|
|
70
|
-
if (attempt < retries) {
|
|
71
|
-
await (0, async_js_1.sleep)(200 * 2 ** attempt);
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
logger.warn('Internal call failed', { method, url: url.pathname, error: error.message });
|
|
75
|
-
throw new errors_js_1.ServiceUnavailableError('Upstream service unavailable', { cause: error });
|
|
76
|
-
}
|
|
77
|
-
finally {
|
|
78
|
-
clearTimeout(timer);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
get: (path, opts) => request('GET', path, opts),
|
|
84
|
-
post: (path, opts) => request('POST', path, opts),
|
|
85
|
-
put: (path, opts) => request('PUT', path, opts),
|
|
86
|
-
patch: (path, opts) => request('PATCH', path, opts),
|
|
87
|
-
delete: (path, opts) => request('DELETE', path, opts),
|
|
88
|
-
};
|
|
89
|
-
}
|
|
21
|
+
__exportStar(require("./safe-fetch.js"), exports);
|
|
90
22
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/http/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/http/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;GAGG;AACH,kDAAgC"}
|