@heavybit/shared-lib 0.0.0-stage → 1.1.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/dist/cjs/access/index.js +118 -0
- package/dist/cjs/access/index.js.map +1 -0
- package/dist/cjs/alerting/index.js +56 -0
- package/dist/cjs/alerting/index.js.map +1 -0
- package/dist/cjs/cache/index.js +167 -0
- package/dist/cjs/cache/index.js.map +1 -0
- package/dist/cjs/common/async.js +40 -0
- package/dist/cjs/common/async.js.map +1 -0
- package/dist/cjs/common/audit.js +21 -0
- package/dist/cjs/common/audit.js.map +1 -0
- package/dist/cjs/common/crypto.js +75 -0
- package/dist/cjs/common/crypto.js.map +1 -0
- package/dist/cjs/common/errors.js +90 -0
- package/dist/cjs/common/errors.js.map +1 -0
- package/dist/cjs/common/id.js +40 -0
- package/dist/cjs/common/id.js.map +1 -0
- package/dist/cjs/common/index.js +28 -0
- package/dist/cjs/common/index.js.map +1 -0
- package/dist/cjs/common/jwt.js +59 -0
- package/dist/cjs/common/jwt.js.map +1 -0
- package/dist/cjs/common/password.js +38 -0
- package/dist/cjs/common/password.js.map +1 -0
- package/dist/cjs/common/phone.js +42 -0
- package/dist/cjs/common/phone.js.map +1 -0
- package/dist/cjs/common/response.js +32 -0
- package/dist/cjs/common/response.js.map +1 -0
- package/dist/cjs/common/text.js +46 -0
- package/dist/cjs/common/text.js.map +1 -0
- package/dist/cjs/common/time.js +109 -0
- package/dist/cjs/common/time.js.map +1 -0
- package/dist/cjs/config/index.js +96 -0
- package/dist/cjs/config/index.js.map +1 -0
- package/dist/cjs/contracts/editorial-draft.js +111 -0
- package/dist/cjs/contracts/editorial-draft.js.map +1 -0
- package/dist/cjs/contracts/index.js +20 -0
- package/dist/cjs/contracts/index.js.map +1 -0
- package/dist/cjs/contracts/notification-dispatch.js +92 -0
- package/dist/cjs/contracts/notification-dispatch.js.map +1 -0
- package/dist/cjs/contracts/upload-import.js +54 -0
- package/dist/cjs/contracts/upload-import.js.map +1 -0
- package/dist/cjs/database/index.js +57 -0
- package/dist/cjs/database/index.js.map +1 -0
- package/dist/cjs/express/auth.js +72 -0
- package/dist/cjs/express/auth.js.map +1 -0
- package/dist/cjs/express/health.js +31 -0
- package/dist/cjs/express/health.js.map +1 -0
- package/dist/cjs/express/index.js +20 -0
- package/dist/cjs/express/index.js.map +1 -0
- package/dist/cjs/express/middleware.js +95 -0
- package/dist/cjs/express/middleware.js.map +1 -0
- package/dist/cjs/http/index.js +90 -0
- package/dist/cjs/http/index.js.map +1 -0
- package/dist/cjs/http/safe-fetch.js +199 -0
- package/dist/cjs/http/safe-fetch.js.map +1 -0
- package/dist/cjs/identity/index.js +117 -0
- package/dist/cjs/identity/index.js.map +1 -0
- package/dist/cjs/index.js +29 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/knex/index.js +76 -0
- package/dist/cjs/knex/index.js.map +1 -0
- package/dist/cjs/logging/index.js +75 -0
- package/dist/cjs/logging/index.js.map +1 -0
- package/dist/cjs/messaging/connection.js +115 -0
- package/dist/cjs/messaging/connection.js.map +1 -0
- package/dist/cjs/messaging/consumer.js +134 -0
- package/dist/cjs/messaging/consumer.js.map +1 -0
- package/dist/cjs/messaging/envelope.js +23 -0
- package/dist/cjs/messaging/envelope.js.map +1 -0
- package/dist/cjs/messaging/idempotency.js +57 -0
- package/dist/cjs/messaging/idempotency.js.map +1 -0
- package/dist/cjs/messaging/index.js +62 -0
- package/dist/cjs/messaging/index.js.map +1 -0
- package/dist/cjs/messaging/monitor.js +48 -0
- package/dist/cjs/messaging/monitor.js.map +1 -0
- package/dist/cjs/messaging/outbox.js +135 -0
- package/dist/cjs/messaging/outbox.js.map +1 -0
- package/dist/cjs/messaging/publisher.js +149 -0
- package/dist/cjs/messaging/publisher.js.map +1 -0
- package/dist/cjs/messaging/rpc.js +125 -0
- package/dist/cjs/messaging/rpc.js.map +1 -0
- package/dist/cjs/messaging/staff-notifier.js +78 -0
- package/dist/cjs/messaging/staff-notifier.js.map +1 -0
- package/dist/cjs/messaging/topology.js +22 -0
- package/dist/cjs/messaging/topology.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/rate-limit/index.js +61 -0
- package/dist/cjs/rate-limit/index.js.map +1 -0
- package/dist/cjs/scheduling/index.js +88 -0
- package/dist/cjs/scheduling/index.js.map +1 -0
- package/dist/cjs/security/index.js +39 -0
- package/dist/cjs/security/index.js.map +1 -0
- package/dist/cjs/socket/index.js +53 -0
- package/dist/cjs/socket/index.js.map +1 -0
- package/dist/cjs/testing/index.js +73 -0
- package/dist/cjs/testing/index.js.map +1 -0
- package/dist/cjs/types/index.js +3 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/validation/index.js +41 -0
- package/dist/cjs/validation/index.js.map +1 -0
- package/dist/esm/access/index.js +104 -0
- package/dist/esm/access/index.js.map +1 -0
- package/dist/esm/alerting/index.js +52 -0
- package/dist/esm/alerting/index.js.map +1 -0
- package/dist/esm/cache/index.js +163 -0
- package/dist/esm/cache/index.js.map +1 -0
- package/dist/esm/common/async.js +33 -0
- package/dist/esm/common/async.js.map +1 -0
- package/dist/esm/common/audit.js +18 -0
- package/dist/esm/common/audit.js.map +1 -0
- package/dist/esm/common/crypto.js +64 -0
- package/dist/esm/common/crypto.js.map +1 -0
- package/dist/esm/common/errors.js +75 -0
- package/dist/esm/common/errors.js.map +1 -0
- package/dist/esm/common/id.js +33 -0
- package/dist/esm/common/id.js.map +1 -0
- package/dist/esm/common/index.js +12 -0
- package/dist/esm/common/index.js.map +1 -0
- package/dist/esm/common/jwt.js +49 -0
- package/dist/esm/common/jwt.js.map +1 -0
- package/dist/esm/common/password.js +30 -0
- package/dist/esm/common/password.js.map +1 -0
- package/dist/esm/common/phone.js +33 -0
- package/dist/esm/common/phone.js.map +1 -0
- package/dist/esm/common/response.js +24 -0
- package/dist/esm/common/response.js.map +1 -0
- package/dist/esm/common/text.js +39 -0
- package/dist/esm/common/text.js.map +1 -0
- package/dist/esm/common/time.js +96 -0
- package/dist/esm/common/time.js.map +1 -0
- package/dist/esm/config/index.js +88 -0
- package/dist/esm/config/index.js.map +1 -0
- package/dist/esm/contracts/editorial-draft.js +108 -0
- package/dist/esm/contracts/editorial-draft.js.map +1 -0
- package/dist/esm/contracts/index.js +4 -0
- package/dist/esm/contracts/index.js.map +1 -0
- package/dist/esm/contracts/notification-dispatch.js +89 -0
- package/dist/esm/contracts/notification-dispatch.js.map +1 -0
- package/dist/esm/contracts/upload-import.js +51 -0
- package/dist/esm/contracts/upload-import.js.map +1 -0
- package/dist/esm/database/index.js +48 -0
- package/dist/esm/database/index.js.map +1 -0
- package/dist/esm/express/auth.js +63 -0
- package/dist/esm/express/auth.js.map +1 -0
- package/dist/esm/express/health.js +27 -0
- package/dist/esm/express/health.js.map +1 -0
- package/dist/esm/express/index.js +4 -0
- package/dist/esm/express/index.js.map +1 -0
- package/dist/esm/express/middleware.js +84 -0
- package/dist/esm/express/middleware.js.map +1 -0
- package/dist/esm/http/index.js +73 -0
- package/dist/esm/http/index.js.map +1 -0
- package/dist/esm/http/safe-fetch.js +193 -0
- package/dist/esm/http/safe-fetch.js.map +1 -0
- package/dist/esm/identity/index.js +111 -0
- package/dist/esm/identity/index.js.map +1 -0
- package/dist/esm/index.js +13 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/knex/index.js +66 -0
- package/dist/esm/knex/index.js.map +1 -0
- package/dist/esm/logging/index.js +67 -0
- package/dist/esm/logging/index.js.map +1 -0
- package/dist/esm/messaging/connection.js +108 -0
- package/dist/esm/messaging/connection.js.map +1 -0
- package/dist/esm/messaging/consumer.js +130 -0
- package/dist/esm/messaging/consumer.js.map +1 -0
- package/dist/esm/messaging/envelope.js +19 -0
- package/dist/esm/messaging/envelope.js.map +1 -0
- package/dist/esm/messaging/idempotency.js +52 -0
- package/dist/esm/messaging/idempotency.js.map +1 -0
- package/dist/esm/messaging/index.js +45 -0
- package/dist/esm/messaging/index.js.map +1 -0
- package/dist/esm/messaging/monitor.js +44 -0
- package/dist/esm/messaging/monitor.js.map +1 -0
- package/dist/esm/messaging/outbox.js +129 -0
- package/dist/esm/messaging/outbox.js.map +1 -0
- package/dist/esm/messaging/publisher.js +142 -0
- package/dist/esm/messaging/publisher.js.map +1 -0
- package/dist/esm/messaging/rpc.js +120 -0
- package/dist/esm/messaging/rpc.js.map +1 -0
- package/dist/esm/messaging/staff-notifier.js +73 -0
- package/dist/esm/messaging/staff-notifier.js.map +1 -0
- package/dist/esm/messaging/topology.js +16 -0
- package/dist/esm/messaging/topology.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/rate-limit/index.js +56 -0
- package/dist/esm/rate-limit/index.js.map +1 -0
- package/dist/esm/scheduling/index.js +83 -0
- package/dist/esm/scheduling/index.js.map +1 -0
- package/dist/esm/security/index.js +36 -0
- package/dist/esm/security/index.js.map +1 -0
- package/dist/esm/socket/index.js +47 -0
- package/dist/esm/socket/index.js.map +1 -0
- package/dist/esm/testing/index.js +66 -0
- package/dist/esm/testing/index.js.map +1 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/validation/index.js +36 -0
- package/dist/esm/validation/index.js.map +1 -0
- package/dist/types/access/index.d.ts +50 -0
- package/dist/types/access/index.d.ts.map +1 -0
- package/dist/types/alerting/index.d.ts +43 -0
- package/dist/types/alerting/index.d.ts.map +1 -0
- package/dist/types/cache/index.d.ts +45 -0
- package/dist/types/cache/index.d.ts.map +1 -0
- package/dist/types/common/async.d.ts +14 -0
- package/dist/types/common/async.d.ts.map +1 -0
- package/dist/types/common/audit.d.ts +17 -0
- package/dist/types/common/audit.d.ts.map +1 -0
- package/dist/types/common/crypto.d.ts +18 -0
- package/dist/types/common/crypto.d.ts.map +1 -0
- package/dist/types/common/errors.d.ts +71 -0
- package/dist/types/common/errors.d.ts.map +1 -0
- package/dist/types/common/id.d.ts +14 -0
- package/dist/types/common/id.d.ts.map +1 -0
- package/dist/types/common/index.d.ts +12 -0
- package/dist/types/common/index.d.ts.map +1 -0
- package/dist/types/common/jwt.d.ts +28 -0
- package/dist/types/common/jwt.d.ts.map +1 -0
- package/dist/types/common/password.d.ts +4 -0
- package/dist/types/common/password.d.ts.map +1 -0
- package/dist/types/common/phone.d.ts +10 -0
- package/dist/types/common/phone.d.ts.map +1 -0
- package/dist/types/common/response.d.ts +12 -0
- package/dist/types/common/response.d.ts.map +1 -0
- package/dist/types/common/text.d.ts +10 -0
- package/dist/types/common/text.d.ts.map +1 -0
- package/dist/types/common/time.d.ts +40 -0
- package/dist/types/common/time.d.ts.map +1 -0
- package/dist/types/config/index.d.ts +115 -0
- package/dist/types/config/index.d.ts.map +1 -0
- package/dist/types/contracts/editorial-draft.d.ts +577 -0
- package/dist/types/contracts/editorial-draft.d.ts.map +1 -0
- package/dist/types/contracts/index.d.ts +4 -0
- package/dist/types/contracts/index.d.ts.map +1 -0
- package/dist/types/contracts/notification-dispatch.d.ts +175 -0
- package/dist/types/contracts/notification-dispatch.d.ts.map +1 -0
- package/dist/types/contracts/upload-import.d.ts +96 -0
- package/dist/types/contracts/upload-import.d.ts.map +1 -0
- package/dist/types/database/index.d.ts +25 -0
- package/dist/types/database/index.d.ts.map +1 -0
- package/dist/types/express/auth.d.ts +27 -0
- package/dist/types/express/auth.d.ts.map +1 -0
- package/dist/types/express/health.d.ts +14 -0
- package/dist/types/express/health.d.ts.map +1 -0
- package/dist/types/express/index.d.ts +4 -0
- package/dist/types/express/index.d.ts.map +1 -0
- package/dist/types/express/middleware.d.ts +20 -0
- package/dist/types/express/middleware.d.ts.map +1 -0
- package/dist/types/http/index.d.ts +34 -0
- package/dist/types/http/index.d.ts.map +1 -0
- package/dist/types/http/safe-fetch.d.ts +58 -0
- package/dist/types/http/safe-fetch.d.ts.map +1 -0
- package/dist/types/identity/index.d.ts +51 -0
- package/dist/types/identity/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/knex/index.d.ts +25 -0
- package/dist/types/knex/index.d.ts.map +1 -0
- package/dist/types/logging/index.d.ts +22 -0
- package/dist/types/logging/index.d.ts.map +1 -0
- package/dist/types/messaging/connection.d.ts +48 -0
- package/dist/types/messaging/connection.d.ts.map +1 -0
- package/dist/types/messaging/consumer.d.ts +56 -0
- package/dist/types/messaging/consumer.d.ts.map +1 -0
- package/dist/types/messaging/envelope.d.ts +16 -0
- package/dist/types/messaging/envelope.d.ts.map +1 -0
- package/dist/types/messaging/idempotency.d.ts +29 -0
- package/dist/types/messaging/idempotency.d.ts.map +1 -0
- package/dist/types/messaging/index.d.ts +39 -0
- package/dist/types/messaging/index.d.ts.map +1 -0
- package/dist/types/messaging/monitor.d.ts +23 -0
- package/dist/types/messaging/monitor.d.ts.map +1 -0
- package/dist/types/messaging/outbox.d.ts +51 -0
- package/dist/types/messaging/outbox.d.ts.map +1 -0
- package/dist/types/messaging/publisher.d.ts +84 -0
- package/dist/types/messaging/publisher.d.ts.map +1 -0
- package/dist/types/messaging/rpc.d.ts +46 -0
- package/dist/types/messaging/rpc.d.ts.map +1 -0
- package/dist/types/messaging/staff-notifier.d.ts +56 -0
- package/dist/types/messaging/staff-notifier.d.ts.map +1 -0
- package/dist/types/messaging/topology.d.ts +23 -0
- package/dist/types/messaging/topology.d.ts.map +1 -0
- package/dist/types/rate-limit/index.d.ts +28 -0
- package/dist/types/rate-limit/index.d.ts.map +1 -0
- package/dist/types/scheduling/index.d.ts +33 -0
- package/dist/types/scheduling/index.d.ts.map +1 -0
- package/dist/types/security/index.d.ts +20 -0
- package/dist/types/security/index.d.ts.map +1 -0
- package/dist/types/socket/index.d.ts +30 -0
- package/dist/types/socket/index.d.ts.map +1 -0
- package/dist/types/testing/index.d.ts +41 -0
- package/dist/types/testing/index.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +65 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/validation/index.d.ts +34 -0
- package/dist/types/validation/index.d.ts.map +1 -0
- package/package.json +189 -4
- package/README.md +0 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ID_PATTERN = exports.ID_LENGTH = void 0;
|
|
4
|
+
exports.newId = newId;
|
|
5
|
+
exports.isId = isId;
|
|
6
|
+
exports.idTimestamp = idTimestamp;
|
|
7
|
+
exports.fixtureId = fixtureId;
|
|
8
|
+
const ulid_1 = require("ulid");
|
|
9
|
+
/**
|
|
10
|
+
* Primary keys are ULIDs: 26-char Crockford base32, lexicographically sortable by creation
|
|
11
|
+
* time, so B-tree inserts stay append-only (unlike random UUIDv4) and IDs double as a coarse
|
|
12
|
+
* creation timestamp. Store them in `CHAR(26)` columns.
|
|
13
|
+
*/
|
|
14
|
+
const nextUlid = (0, ulid_1.monotonicFactory)();
|
|
15
|
+
exports.ID_LENGTH = 26;
|
|
16
|
+
exports.ID_PATTERN = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
17
|
+
/** A new time-ordered, monotonic ULID. */
|
|
18
|
+
function newId() {
|
|
19
|
+
return nextUlid();
|
|
20
|
+
}
|
|
21
|
+
function isId(value) {
|
|
22
|
+
return typeof value === 'string' && exports.ID_PATTERN.test(value);
|
|
23
|
+
}
|
|
24
|
+
/** Creation time encoded in a ULID. */
|
|
25
|
+
function idTimestamp(id) {
|
|
26
|
+
return new Date((0, ulid_1.decodeTime)(id));
|
|
27
|
+
}
|
|
28
|
+
const FIXTURE_PREFIX = '01K6SEED';
|
|
29
|
+
/**
|
|
30
|
+
* A stable, valid ID for seed/fixture rows: the same `(namespace, n)` always yields the same ID, so
|
|
31
|
+
* seeds in different services can reference each other's rows without sharing a database.
|
|
32
|
+
* `namespace` is two Crockford characters (e.g. `PR` for profiles).
|
|
33
|
+
*/
|
|
34
|
+
function fixtureId(namespace, n) {
|
|
35
|
+
const id = `${FIXTURE_PREFIX}${namespace.toUpperCase()}${String(n).padStart(exports.ID_LENGTH - FIXTURE_PREFIX.length - namespace.length, '0')}`;
|
|
36
|
+
if (!exports.ID_PATTERN.test(id))
|
|
37
|
+
throw new Error(`Invalid fixture id namespace/sequence: ${namespace}/${n}`);
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../../src/common/id.ts"],"names":[],"mappings":";;;AAaA,sBAEC;AAED,oBAEC;AAGD,kCAEC;AASD,8BAIC;AArCD,+BAAoD;AAEpD;;;;GAIG;AACH,MAAM,QAAQ,GAAG,IAAA,uBAAgB,GAAE,CAAC;AAEvB,QAAA,SAAS,GAAG,EAAE,CAAC;AACf,QAAA,UAAU,GAAG,0BAA0B,CAAC;AAErD,0CAA0C;AAC1C,SAAgB,KAAK;IACnB,OAAO,QAAQ,EAAE,CAAC;AACpB,CAAC;AAED,SAAgB,IAAI,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,kBAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED,uCAAuC;AACvC,SAAgB,WAAW,CAAC,EAAU;IACpC,OAAO,IAAI,IAAI,CAAC,IAAA,iBAAU,EAAC,EAAE,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC;;;;GAIG;AACH,SAAgB,SAAS,CAAC,SAAiB,EAAE,CAAS;IACpD,MAAM,EAAE,GAAG,GAAG,cAAc,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAS,GAAG,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;IACzI,IAAI,CAAC,kBAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,SAAS,IAAI,CAAC,EAAE,CAAC,CAAC;IACtG,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./id.js"), exports);
|
|
18
|
+
__exportStar(require("./errors.js"), exports);
|
|
19
|
+
__exportStar(require("./response.js"), exports);
|
|
20
|
+
__exportStar(require("./crypto.js"), exports);
|
|
21
|
+
__exportStar(require("./password.js"), exports);
|
|
22
|
+
__exportStar(require("./jwt.js"), exports);
|
|
23
|
+
__exportStar(require("./text.js"), exports);
|
|
24
|
+
__exportStar(require("./async.js"), exports);
|
|
25
|
+
__exportStar(require("./phone.js"), exports);
|
|
26
|
+
__exportStar(require("./time.js"), exports);
|
|
27
|
+
__exportStar(require("./audit.js"), exports);
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,8CAA4B;AAC5B,gDAA8B;AAC9B,8CAA4B;AAC5B,gDAA8B;AAC9B,2CAAyB;AACzB,4CAA0B;AAC1B,6CAA2B;AAC3B,6CAA2B;AAC3B,4CAA0B;AAC1B,6CAA2B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.signJwt = signJwt;
|
|
7
|
+
exports.verifyJwt = verifyJwt;
|
|
8
|
+
exports.decodeJwt = decodeJwt;
|
|
9
|
+
exports.extractBearerToken = extractBearerToken;
|
|
10
|
+
exports.durationToSeconds = durationToSeconds;
|
|
11
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
12
|
+
function signJwt(payload, secret, options) {
|
|
13
|
+
return jsonwebtoken_1.default.sign(payload, secret, {
|
|
14
|
+
algorithm: 'HS256',
|
|
15
|
+
expiresIn: options.expiresIn,
|
|
16
|
+
...(options.issuer ? { issuer: options.issuer } : {}),
|
|
17
|
+
...(options.audience ? { audience: options.audience } : {}),
|
|
18
|
+
...(options.jwtId ? { jwtid: options.jwtId } : {}),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** Verifies signature, expiry and (when given) issuer/audience. Throws on any failure. */
|
|
22
|
+
function verifyJwt(token, secret, options = {}) {
|
|
23
|
+
const decoded = jsonwebtoken_1.default.verify(token, secret, {
|
|
24
|
+
algorithms: ['HS256'],
|
|
25
|
+
...(options.issuer ? { issuer: options.issuer } : {}),
|
|
26
|
+
...(options.audience ? { audience: options.audience } : {}),
|
|
27
|
+
});
|
|
28
|
+
if (typeof decoded === 'string' || !decoded.sub)
|
|
29
|
+
throw new Error('Invalid token payload');
|
|
30
|
+
return decoded;
|
|
31
|
+
}
|
|
32
|
+
function decodeJwt(token) {
|
|
33
|
+
const decoded = jsonwebtoken_1.default.decode(token);
|
|
34
|
+
return decoded && typeof decoded !== 'string' ? decoded : null;
|
|
35
|
+
}
|
|
36
|
+
function extractBearerToken(header) {
|
|
37
|
+
if (!header)
|
|
38
|
+
return null;
|
|
39
|
+
const [scheme, token] = header.split(' ');
|
|
40
|
+
return scheme?.toLowerCase() === 'bearer' && token ? token.trim() : null;
|
|
41
|
+
}
|
|
42
|
+
/** Converts `'15m'`, `'30d'`, `3600` into seconds. */
|
|
43
|
+
function durationToSeconds(value) {
|
|
44
|
+
if (typeof value === 'number')
|
|
45
|
+
return value;
|
|
46
|
+
const match = /^(\d+)\s*(ms|s|m|h|d|w)?$/.exec(value.trim());
|
|
47
|
+
if (!match)
|
|
48
|
+
throw new Error(`Invalid duration: ${value}`);
|
|
49
|
+
const amount = Number(match[1]);
|
|
50
|
+
switch (match[2]) {
|
|
51
|
+
case 'ms': return Math.ceil(amount / 1000);
|
|
52
|
+
case 'm': return amount * 60;
|
|
53
|
+
case 'h': return amount * 3600;
|
|
54
|
+
case 'd': return amount * 86_400;
|
|
55
|
+
case 'w': return amount * 604_800;
|
|
56
|
+
default: return amount;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../../src/common/jwt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.hashPassword = hashPassword;
|
|
7
|
+
exports.verifyPassword = verifyPassword;
|
|
8
|
+
exports.needsRehash = needsRehash;
|
|
9
|
+
const argon2_1 = __importDefault(require("argon2"));
|
|
10
|
+
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
11
|
+
/**
|
|
12
|
+
* Passwords are hashed with argon2id. Legacy bcrypt hashes (`$2a$`, `$2b$`, `$2y$`) still
|
|
13
|
+
* verify so migrated accounts can sign in; callers should re-hash on success when
|
|
14
|
+
* `needsRehash()` is true.
|
|
15
|
+
*/
|
|
16
|
+
const ARGON2_OPTIONS = { type: argon2_1.default.argon2id, memoryCost: 19_456, timeCost: 2, parallelism: 1 };
|
|
17
|
+
const BCRYPT_PREFIX = /^\$2[aby]\$/;
|
|
18
|
+
async function hashPassword(password) {
|
|
19
|
+
return argon2_1.default.hash(password, ARGON2_OPTIONS);
|
|
20
|
+
}
|
|
21
|
+
async function verifyPassword(password, hash) {
|
|
22
|
+
if (!hash)
|
|
23
|
+
return false;
|
|
24
|
+
try {
|
|
25
|
+
if (BCRYPT_PREFIX.test(hash))
|
|
26
|
+
return await bcryptjs_1.default.compare(password, hash);
|
|
27
|
+
return await argon2_1.default.verify(hash, password);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function needsRehash(hash) {
|
|
34
|
+
if (BCRYPT_PREFIX.test(hash))
|
|
35
|
+
return true;
|
|
36
|
+
return argon2_1.default.needsRehash(hash, ARGON2_OPTIONS);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/common/password.ts"],"names":[],"mappings":";;;;;AAYA,oCAEC;AAED,wCAQC;AAED,kCAGC;AA7BD,oDAA4B;AAC5B,wDAA8B;AAE9B;;;;GAIG;AACH,MAAM,cAAc,GAAG,EAAE,IAAI,EAAE,gBAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAW,CAAC;AAE3G,MAAM,aAAa,GAAG,aAAa,CAAC;AAE7B,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,OAAO,gBAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AAC/C,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,IAA+B;IACpF,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,CAAC;QACH,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,MAAM,kBAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC1E,OAAO,MAAM,gBAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,IAAY;IACtC,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,gBAAM,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.toE164 = toE164;
|
|
7
|
+
exports.toMsisdn = toMsisdn;
|
|
8
|
+
exports.phoneRegion = phoneRegion;
|
|
9
|
+
exports.maskPhone = maskPhone;
|
|
10
|
+
const google_libphonenumber_1 = __importDefault(require("google-libphonenumber"));
|
|
11
|
+
const util = google_libphonenumber_1.default.PhoneNumberUtil.getInstance();
|
|
12
|
+
const { PhoneNumberFormat } = google_libphonenumber_1.default;
|
|
13
|
+
/**
|
|
14
|
+
* Normalises a phone number to E.164 (`+254712345678`). Returns null for anything that is not a
|
|
15
|
+
* valid number for the given default region.
|
|
16
|
+
*/
|
|
17
|
+
function toE164(phone, defaultRegion = 'KE') {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = util.parseAndKeepRawInput(phone.trim(), defaultRegion);
|
|
20
|
+
return util.isValidNumber(parsed) ? util.format(parsed, PhoneNumberFormat.E164) : null;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** E.164 without the plus sign, as most SMS gateways expect (`254712345678`). */
|
|
27
|
+
function toMsisdn(phone, defaultRegion = 'KE') {
|
|
28
|
+
const e164 = toE164(phone, defaultRegion);
|
|
29
|
+
return e164 ? e164.slice(1) : null;
|
|
30
|
+
}
|
|
31
|
+
function phoneRegion(phone, defaultRegion = 'KE') {
|
|
32
|
+
try {
|
|
33
|
+
return util.getRegionCodeForNumber(util.parse(phone, defaultRegion)) ?? null;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function maskPhone(phone) {
|
|
40
|
+
return phone.length <= 4 ? '****' : `${phone.slice(0, 4)}****${phone.slice(-2)}`;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=phone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone.js","sourceRoot":"","sources":["../../../src/common/phone.ts"],"names":[],"mappings":";;;;;AASA,wBAOC;AAGD,4BAGC;AAED,kCAMC;AAED,8BAEC;AAlCD,kFAAmD;AAEnD,MAAM,IAAI,GAAG,+BAAc,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;AAC1D,MAAM,EAAE,iBAAiB,EAAE,GAAG,+BAAc,CAAC;AAE7C;;;GAGG;AACH,SAAgB,MAAM,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IACxD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,aAAa,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,SAAgB,QAAQ,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,SAAgB,WAAW,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IAC7D,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,IAAI,IAAI,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.successResponse = successResponse;
|
|
4
|
+
exports.errorResponse = errorResponse;
|
|
5
|
+
exports.buildPaginationMeta = buildPaginationMeta;
|
|
6
|
+
exports.paginatedResponse = paginatedResponse;
|
|
7
|
+
exports.buildPaginatedResult = buildPaginatedResult;
|
|
8
|
+
exports.pageOffset = pageOffset;
|
|
9
|
+
/** Standard success envelope: `{ success, message, data }`. */
|
|
10
|
+
function successResponse(data, message = 'Success') {
|
|
11
|
+
return { success: true, message, data };
|
|
12
|
+
}
|
|
13
|
+
/** Standard error envelope: `{ success: false, message, code?, errors? }`. */
|
|
14
|
+
function errorResponse(message, errors, code) {
|
|
15
|
+
return { success: false, message, ...(code ? { code } : {}), ...(errors ? { errors } : {}) };
|
|
16
|
+
}
|
|
17
|
+
function buildPaginationMeta(total, page, limit) {
|
|
18
|
+
const totalPages = limit > 0 ? Math.max(1, Math.ceil(total / limit)) : 1;
|
|
19
|
+
return { page, limit, total, totalPages, hasNext: page < totalPages, hasPrev: page > 1 };
|
|
20
|
+
}
|
|
21
|
+
/** Paginated envelope: `{ success, message, data: T[], meta }`. */
|
|
22
|
+
function paginatedResponse(data, total, page, limit, message = 'Success') {
|
|
23
|
+
return { success: true, message, data, meta: buildPaginationMeta(total, page, limit) };
|
|
24
|
+
}
|
|
25
|
+
function buildPaginatedResult(data, total, page, limit) {
|
|
26
|
+
return { data, meta: buildPaginationMeta(total, page, limit) };
|
|
27
|
+
}
|
|
28
|
+
/** SQL offset for 1-based pages. */
|
|
29
|
+
function pageOffset(page, limit) {
|
|
30
|
+
return Math.max(0, (Math.max(1, page) - 1) * limit);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/common/response.ts"],"names":[],"mappings":";;AAGA,0CAEC;AAGD,sCAEC;AAED,kDAGC;AAGD,8CAEC;AAED,oDAEC;AAGD,gCAEC;AA3BD,+DAA+D;AAC/D,SAAgB,eAAe,CAAI,IAAO,EAAE,OAAO,GAAG,SAAS;IAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,8EAA8E;AAC9E,SAAgB,aAAa,CAAC,OAAe,EAAE,MAAiC,EAAE,IAAa;IAC7F,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/F,CAAC;AAED,SAAgB,mBAAmB,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa;IAC5E,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,GAAG,UAAU,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED,mEAAmE;AACnE,SAAgB,iBAAiB,CAAI,IAAS,EAAE,KAAa,EAAE,IAAY,EAAE,KAAa,EAAE,OAAO,GAAG,SAAS;IAC7G,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,SAAgB,oBAAoB,CAAI,IAAS,EAAE,KAAa,EAAE,IAAY,EAAE,KAAa;IAC3F,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,oCAAoC;AACpC,SAAgB,UAAU,CAAC,IAAY,EAAE,KAAa;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.slugify = slugify;
|
|
4
|
+
exports.interpolate = interpolate;
|
|
5
|
+
exports.templateVariables = templateVariables;
|
|
6
|
+
exports.escapeHtml = escapeHtml;
|
|
7
|
+
exports.maskEmail = maskEmail;
|
|
8
|
+
/** URL slug: lowercase ASCII, dash-separated, accents folded. */
|
|
9
|
+
function slugify(value, maxLength = 80) {
|
|
10
|
+
return value
|
|
11
|
+
.normalize('NFKD')
|
|
12
|
+
.replace(/[̀-ͯ]/g, '')
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/&/g, ' and ')
|
|
15
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
16
|
+
.replace(/^-+|-+$/g, '')
|
|
17
|
+
.slice(0, maxLength)
|
|
18
|
+
.replace(/-+$/g, '');
|
|
19
|
+
}
|
|
20
|
+
/** Replaces `{{ name }}` placeholders; unknown names become empty strings. */
|
|
21
|
+
function interpolate(template, variables, escape) {
|
|
22
|
+
return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) => {
|
|
23
|
+
const value = path.split('.').reduce((acc, key) => (acc && typeof acc === 'object' ? acc[key] : undefined), variables);
|
|
24
|
+
const text = value === undefined || value === null ? '' : String(value);
|
|
25
|
+
return escape ? escape(text) : text;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Placeholder names used by a template, e.g. `['user.name', 'code']`. */
|
|
29
|
+
function templateVariables(template) {
|
|
30
|
+
const names = new Set();
|
|
31
|
+
for (const match of template.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g))
|
|
32
|
+
names.add(match[1]);
|
|
33
|
+
return [...names];
|
|
34
|
+
}
|
|
35
|
+
const HTML_ESCAPES = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
36
|
+
function escapeHtml(value) {
|
|
37
|
+
return value.replace(/[&<>"']/g, (ch) => HTML_ESCAPES[ch]);
|
|
38
|
+
}
|
|
39
|
+
/** `jane.doe@example.com` → `ja***@example.com` for logs and audit trails. */
|
|
40
|
+
function maskEmail(email) {
|
|
41
|
+
const [local, domain] = email.split('@');
|
|
42
|
+
if (!local || !domain)
|
|
43
|
+
return '***';
|
|
44
|
+
return `${local.slice(0, 2)}***@${domain}`;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/common/text.ts"],"names":[],"mappings":";;AACA,0BAUC;AAGD,kCAMC;AAGD,8CAIC;AAID,gCAEC;AAGD,8BAIC;AAxCD,iEAAiE;AACjE,SAAgB,OAAO,CAAC,KAAa,EAAE,SAAS,GAAG,EAAE;IACnD,OAAO,KAAK;SACT,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,WAAW,EAAE;SACb,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC;SACnB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,8EAA8E;AAC9E,SAAgB,WAAW,CAAC,QAAgB,EAAE,SAAkC,EAAE,MAAkC;IAClH,OAAO,QAAQ,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE;QACrE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAU,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA+B,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7J,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,SAAgB,iBAAiB,CAAC,QAAgB;IAChD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,YAAY,GAA2B,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAErH,SAAgB,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,CAAE,CAAC,CAAC;AAC9D,CAAC;AAED,8EAA8E;AAC9E,SAAgB,SAAS,CAAC,KAAa;IACrC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addMinutes = exports.addSeconds = void 0;
|
|
4
|
+
exports.isValidTimeZone = isValidTimeZone;
|
|
5
|
+
exports.formatInTimeZone = formatInTimeZone;
|
|
6
|
+
exports.formatInstantInZone = formatInstantInZone;
|
|
7
|
+
exports.timeZoneOffsetMinutes = timeZoneOffsetMinutes;
|
|
8
|
+
exports.parseClockTime = parseClockTime;
|
|
9
|
+
exports.zonedWallTimeToInstant = zonedWallTimeToInstant;
|
|
10
|
+
exports.zonedDayBounds = zonedDayBounds;
|
|
11
|
+
exports.quietWindowEndAt = quietWindowEndAt;
|
|
12
|
+
/** True for IANA zones the runtime knows (`Africa/Nairobi`), false for garbage. */
|
|
13
|
+
function isValidTimeZone(zone) {
|
|
14
|
+
try {
|
|
15
|
+
new Intl.DateTimeFormat('en-US', { timeZone: zone });
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Formats an instant in a zone, e.g. `30 Sep 2026, 14:05 EAT`. Falls back to UTC for invalid zones. */
|
|
23
|
+
function formatInTimeZone(date, zone, locale = 'en-GB') {
|
|
24
|
+
const timeZone = isValidTimeZone(zone) ? zone : 'UTC';
|
|
25
|
+
return new Intl.DateTimeFormat(locale, {
|
|
26
|
+
timeZone,
|
|
27
|
+
day: '2-digit',
|
|
28
|
+
month: 'short',
|
|
29
|
+
year: 'numeric',
|
|
30
|
+
hour: '2-digit',
|
|
31
|
+
minute: '2-digit',
|
|
32
|
+
timeZoneName: 'short',
|
|
33
|
+
}).format(new Date(date));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Formats an instant for a person in their zone, falling back to `fallbackZone` (itself falling back to
|
|
37
|
+
* UTC) when theirs is missing or unknown. Never throws, and says when it fell back so callers can log it.
|
|
38
|
+
*/
|
|
39
|
+
function formatInstantInZone(instant, zone, fallbackZone = 'UTC', locale = 'en-GB') {
|
|
40
|
+
const usedFallback = !(typeof zone === 'string' && zone && isValidTimeZone(zone));
|
|
41
|
+
const timezone = usedFallback ? (isValidTimeZone(fallbackZone) ? fallbackZone : 'UTC') : zone;
|
|
42
|
+
const date = new Date(instant);
|
|
43
|
+
return { text: Number.isNaN(date.getTime()) ? '' : formatInTimeZone(date, timezone, locale), timezone, usedFallback };
|
|
44
|
+
}
|
|
45
|
+
/** Offset of `zone` from UTC in minutes at `at` (positive east of Greenwich). */
|
|
46
|
+
function timeZoneOffsetMinutes(zone, at = new Date()) {
|
|
47
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
48
|
+
timeZone: zone, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit',
|
|
49
|
+
}).formatToParts(at);
|
|
50
|
+
const get = (type) => Number(parts.find((p) => p.type === type)?.value);
|
|
51
|
+
const asUtc = Date.UTC(get('year'), get('month') - 1, get('day'), get('hour'), get('minute'), get('second'));
|
|
52
|
+
return Math.round((asUtc - Math.floor(at.getTime() / 1000) * 1000) / 60_000);
|
|
53
|
+
}
|
|
54
|
+
const addSeconds = (date, seconds) => new Date(date.getTime() + seconds * 1000);
|
|
55
|
+
exports.addSeconds = addSeconds;
|
|
56
|
+
const addMinutes = (date, minutes) => (0, exports.addSeconds)(date, minutes * 60);
|
|
57
|
+
exports.addMinutes = addMinutes;
|
|
58
|
+
const MS_PER_MINUTE = 60_000;
|
|
59
|
+
const MS_PER_DAY = 86_400_000;
|
|
60
|
+
const CLOCK_TIME = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
61
|
+
/** Minutes since midnight of a 24-hour `HH:MM` clock time. Throws on anything else (never guesses). */
|
|
62
|
+
function parseClockTime(value) {
|
|
63
|
+
const match = CLOCK_TIME.exec(String(value ?? '').trim());
|
|
64
|
+
if (!match)
|
|
65
|
+
throw new RangeError(`Not a 24-hour HH:MM clock time: "${value}"`);
|
|
66
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
67
|
+
}
|
|
68
|
+
/** The local calendar date of `at` in `zone`, and how far into that local day it is. */
|
|
69
|
+
function localDate(at, zone) {
|
|
70
|
+
const local = new Date(at.getTime() + timeZoneOffsetMinutes(zone, at) * MS_PER_MINUTE);
|
|
71
|
+
const msOfDay = ((local.getTime() % MS_PER_DAY) + MS_PER_DAY) % MS_PER_DAY;
|
|
72
|
+
return { year: local.getUTCFullYear(), month: local.getUTCMonth(), day: local.getUTCDate(), msOfDay };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The instant a wall-clock time occurs in `zone` (month is 0-based; an overflowing day rolls over).
|
|
76
|
+
* The offset is read again at the first estimate, so the result is right across a DST change; a wall
|
|
77
|
+
* time skipped by a spring-forward resolves to the nearest valid instant.
|
|
78
|
+
*/
|
|
79
|
+
function zonedWallTimeToInstant(year, month, day, minutesOfDay, zone) {
|
|
80
|
+
const wall = Date.UTC(year, month, day) + minutesOfDay * MS_PER_MINUTE;
|
|
81
|
+
const estimate = wall - timeZoneOffsetMinutes(zone, new Date(wall)) * MS_PER_MINUTE;
|
|
82
|
+
return new Date(wall - timeZoneOffsetMinutes(zone, new Date(estimate)) * MS_PER_MINUTE);
|
|
83
|
+
}
|
|
84
|
+
/** The local calendar day containing `at` in `zone`, as a half-open `[start, end)` UTC range (23–25 h on DST days). */
|
|
85
|
+
function zonedDayBounds(at, zone) {
|
|
86
|
+
const { year, month, day } = localDate(at, zone);
|
|
87
|
+
return { start: zonedWallTimeToInstant(year, month, day, 0, zone), end: zonedWallTimeToInstant(year, month, day + 1, 0, zone) };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* When `at` falls inside the daily window `[start, end)` (local `HH:MM` times in `zone`; the window may
|
|
91
|
+
* cross midnight), the instant that window ends; otherwise null. `start === end` means no window.
|
|
92
|
+
*/
|
|
93
|
+
function quietWindowEndAt(at, zone, start, end) {
|
|
94
|
+
const startMin = parseClockTime(start);
|
|
95
|
+
const endMin = parseClockTime(end);
|
|
96
|
+
if (startMin === endMin)
|
|
97
|
+
return null;
|
|
98
|
+
const { year, month, day, msOfDay } = localDate(at, zone);
|
|
99
|
+
const startMs = startMin * MS_PER_MINUTE;
|
|
100
|
+
const endMs = endMin * MS_PER_MINUTE;
|
|
101
|
+
const crossesMidnight = startMin > endMin;
|
|
102
|
+
const inside = crossesMidnight ? msOfDay >= startMs || msOfDay < endMs : msOfDay >= startMs && msOfDay < endMs;
|
|
103
|
+
if (!inside)
|
|
104
|
+
return null;
|
|
105
|
+
// A midnight-crossing window entered before midnight ends tomorrow; otherwise it ends today.
|
|
106
|
+
const endsTomorrow = crossesMidnight && msOfDay >= startMs;
|
|
107
|
+
return zonedWallTimeToInstant(year, month, day + (endsTomorrow ? 1 : 0), endMin, zone);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../../src/common/time.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listFromEnv = exports.ConfigError = exports.redisEnv = exports.messagingEnv = exports.databaseEnv = exports.serviceEnv = void 0;
|
|
4
|
+
exports.amqpUrlFromEnv = amqpUrlFromEnv;
|
|
5
|
+
exports.loadDotEnv = loadDotEnv;
|
|
6
|
+
exports.loadEnv = loadEnv;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
/**
|
|
11
|
+
* Environment building blocks. Services compose the pieces they need:
|
|
12
|
+
*
|
|
13
|
+
* const env = loadEnv(serviceEnv.merge(databaseEnv).merge(messagingEnv).extend({ MY_VAR: z.string() }));
|
|
14
|
+
*/
|
|
15
|
+
exports.serviceEnv = zod_1.z.object({
|
|
16
|
+
NODE_ENV: zod_1.z.enum(['development', 'test', 'staging', 'production']).default('development'),
|
|
17
|
+
PORT: zod_1.z.coerce.number().int().positive(),
|
|
18
|
+
SERVICE_NAME: zod_1.z.string().min(1),
|
|
19
|
+
/** Short app identifier used in exchange names and key prefixes (e.g. `showbiz`). */
|
|
20
|
+
APP_NAME: zod_1.z.string().min(1).default('app'),
|
|
21
|
+
LOG_LEVEL: zod_1.z.enum(['error', 'warn', 'info', 'http', 'debug']).optional(),
|
|
22
|
+
CORS_ORIGINS: zod_1.z.string().default(''),
|
|
23
|
+
/** Verifies gateway-signed identity headers. */
|
|
24
|
+
GATEWAY_SHARED_SECRET: zod_1.z.string().min(16),
|
|
25
|
+
/** Authenticates service-to-service `/internal/*` calls. */
|
|
26
|
+
INTERNAL_SERVICE_SECRET: zod_1.z.string().min(16),
|
|
27
|
+
});
|
|
28
|
+
exports.databaseEnv = zod_1.z.object({
|
|
29
|
+
DB_HOST: zod_1.z.string().default('127.0.0.1'),
|
|
30
|
+
DB_PORT: zod_1.z.coerce.number().int().positive().default(3306),
|
|
31
|
+
DB_USER: zod_1.z.string().default('root'),
|
|
32
|
+
DB_PASSWORD: zod_1.z.string().default(''),
|
|
33
|
+
DB_NAME: zod_1.z.string().min(1),
|
|
34
|
+
DB_POOL_MAX: zod_1.z.coerce.number().int().positive().default(10),
|
|
35
|
+
});
|
|
36
|
+
exports.messagingEnv = zod_1.z.object({
|
|
37
|
+
RABBITMQ_URL: zod_1.z.string().optional(),
|
|
38
|
+
RABBITMQ_HOST: zod_1.z.string().default('127.0.0.1'),
|
|
39
|
+
RABBITMQ_PORT: zod_1.z.coerce.number().int().positive().default(5672),
|
|
40
|
+
RABBITMQ_USERNAME: zod_1.z.string().default('guest'),
|
|
41
|
+
RABBITMQ_PASSWORD: zod_1.z.string().default('guest'),
|
|
42
|
+
RABBITMQ_VHOST: zod_1.z.string().default('/'),
|
|
43
|
+
/** Environment prefix for queue and exchange names (`dev`, `staging`, `prod`). */
|
|
44
|
+
QUEUE_PREFIX: zod_1.z.string().default('dev'),
|
|
45
|
+
RABBITMQ_ENABLED: zod_1.z.enum(['true', 'false']).default('true').transform((v) => v === 'true'),
|
|
46
|
+
});
|
|
47
|
+
exports.redisEnv = zod_1.z.object({
|
|
48
|
+
REDIS_URL: zod_1.z.string().optional(),
|
|
49
|
+
REDIS_DB: zod_1.z.coerce.number().int().min(0).default(0),
|
|
50
|
+
/** Key prefix, e.g. `app:dev:` — never share one between apps or environments. */
|
|
51
|
+
REDIS_PREFIX: zod_1.z.string().default(''),
|
|
52
|
+
});
|
|
53
|
+
/** Builds an AMQP URL from discrete env vars (or returns RABBITMQ_URL when set). */
|
|
54
|
+
function amqpUrlFromEnv(env) {
|
|
55
|
+
if (env.RABBITMQ_URL)
|
|
56
|
+
return env.RABBITMQ_URL;
|
|
57
|
+
const vhost = env.RABBITMQ_VHOST === '/' ? '%2F' : encodeURIComponent(env.RABBITMQ_VHOST.replace(/^\//, ''));
|
|
58
|
+
return `amqp://${encodeURIComponent(env.RABBITMQ_USERNAME)}:${encodeURIComponent(env.RABBITMQ_PASSWORD)}@${env.RABBITMQ_HOST}:${env.RABBITMQ_PORT}/${vhost}`;
|
|
59
|
+
}
|
|
60
|
+
/** Reads `KEY=value` lines from a dotenv file into process.env without overriding set values. */
|
|
61
|
+
function loadDotEnv(path = (0, node_path_1.resolve)(process.cwd(), '.env')) {
|
|
62
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
63
|
+
return;
|
|
64
|
+
for (const line of (0, node_fs_1.readFileSync)(path, 'utf8').split(/\r?\n/)) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
67
|
+
continue;
|
|
68
|
+
const eq = trimmed.indexOf('=');
|
|
69
|
+
if (eq === -1)
|
|
70
|
+
continue;
|
|
71
|
+
const key = trimmed.slice(0, eq).trim();
|
|
72
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
73
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")))
|
|
74
|
+
value = value.slice(1, -1);
|
|
75
|
+
if (process.env[key] === undefined)
|
|
76
|
+
process.env[key] = value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
class ConfigError extends Error {
|
|
80
|
+
}
|
|
81
|
+
exports.ConfigError = ConfigError;
|
|
82
|
+
/** Loads `.env` (if present) and validates process.env. Throws ConfigError listing every problem. */
|
|
83
|
+
function loadEnv(schema, source = process.env, options = {}) {
|
|
84
|
+
if (options.dotenv !== false && source === process.env)
|
|
85
|
+
loadDotEnv();
|
|
86
|
+
const result = schema.safeParse(source);
|
|
87
|
+
if (!result.success) {
|
|
88
|
+
const lines = result.error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\n');
|
|
89
|
+
throw new ConfigError(`Invalid environment configuration:\n${lines}`);
|
|
90
|
+
}
|
|
91
|
+
return result.data;
|
|
92
|
+
}
|
|
93
|
+
/** Comma-separated env value → trimmed, non-empty list. */
|
|
94
|
+
const listFromEnv = (value) => (value ?? '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
95
|
+
exports.listFromEnv = listFromEnv;
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"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"}
|