@heavybit/shared-lib 1.3.2 → 2.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/README.md +100 -0
- package/dist/cjs/common/errors.js +44 -5
- package/dist/cjs/common/errors.js.map +1 -1
- package/dist/cjs/common/phone.js +43 -10
- 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/config/index.js +1 -1
- 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/express/auth.js +44 -11
- package/dist/cjs/express/auth.js.map +1 -1
- package/dist/cjs/express/index.js +1 -0
- package/dist/cjs/express/index.js.map +1 -1
- 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/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/logging/index.js +76 -40
- package/dist/cjs/logging/index.js.map +1 -1
- package/dist/cjs/logging/redact.js +117 -0
- package/dist/cjs/logging/redact.js.map +1 -0
- package/dist/cjs/messaging/index.js +1 -0
- package/dist/cjs/messaging/index.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/validation/index.js +27 -3
- package/dist/cjs/validation/index.js.map +1 -1
- package/dist/esm/common/errors.js +42 -4
- package/dist/esm/common/errors.js.map +1 -1
- package/dist/esm/common/phone.js +43 -10
- 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/config/index.js +1 -1
- 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/express/auth.js +45 -12
- package/dist/esm/express/auth.js.map +1 -1
- package/dist/esm/express/index.js +1 -0
- package/dist/esm/express/index.js.map +1 -1
- 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/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logging/index.js +68 -39
- package/dist/esm/logging/index.js.map +1 -1
- package/dist/esm/logging/redact.js +110 -0
- package/dist/esm/logging/redact.js.map +1 -0
- package/dist/esm/messaging/index.js +1 -0
- package/dist/esm/messaging/index.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/validation/index.js +27 -2
- package/dist/esm/validation/index.js.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/cache/index.d.ts +1 -1
- package/dist/types/cache/index.d.ts.map +1 -1
- package/dist/types/common/errors.d.ts +48 -7
- package/dist/types/common/errors.d.ts.map +1 -1
- package/dist/types/common/phone.d.ts +35 -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/config/index.d.ts +1 -1
- 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 +208 -90
- package/dist/types/contracts/notification-dispatch.d.ts.map +1 -1
- package/dist/types/express/auth.d.ts +42 -6
- package/dist/types/express/auth.d.ts.map +1 -1
- package/dist/types/express/index.d.ts +1 -0
- package/dist/types/express/index.d.ts.map +1 -1
- 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/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- 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/index.d.ts +1 -0
- package/dist/types/messaging/index.d.ts.map +1 -1
- package/dist/types/messaging/staff-notifier.d.ts +67 -36
- 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/types/index.d.ts +36 -1
- 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 +1 -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
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Success-response helpers for Express controllers (HTTP layer only).
|
|
3
|
+
* They write the standard envelope `{ success: true, message, data, meta? }`, so controllers never
|
|
4
|
+
* hand-build bodies. Errors are not sent here: throw an AppError and let `errorHandler` answer.
|
|
5
|
+
*/
|
|
6
|
+
import type { Response } from 'express';
|
|
7
|
+
import type { CursorPage, CursorPageMeta, PaginationMeta } from '../types/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* 200 with the success envelope.
|
|
10
|
+
*
|
|
11
|
+
* @param res Express response.
|
|
12
|
+
* @param data The payload placed under `data`.
|
|
13
|
+
* @param message Optional human-readable message (default `Success`).
|
|
14
|
+
* @param meta Optional list metadata.
|
|
15
|
+
* @returns The Express response.
|
|
16
|
+
* @example ok(res, product, 'Product updated');
|
|
17
|
+
*/
|
|
18
|
+
export declare function ok<T>(res: Response, data: T, message?: string, meta?: PaginationMeta | CursorPageMeta): Response;
|
|
19
|
+
/**
|
|
20
|
+
* 201 with the success envelope, for a newly created resource.
|
|
21
|
+
*
|
|
22
|
+
* @param res Express response.
|
|
23
|
+
* @param data The created resource (or its id).
|
|
24
|
+
* @param message Optional message (default `Created`).
|
|
25
|
+
* @returns The Express response.
|
|
26
|
+
*
|
|
27
|
+
* @example created(res, { id }, 'Shop created');
|
|
28
|
+
*/
|
|
29
|
+
export declare function created<T>(res: Response, data: T, message?: string): Response;
|
|
30
|
+
/**
|
|
31
|
+
* 200 with a cursor-paginated list: `data` is the items, `meta` is `{ limit, nextCursor, hasMore }`.
|
|
32
|
+
*
|
|
33
|
+
* @param res Express response.
|
|
34
|
+
* @param page The page from the service (see `buildCursorPageMeta`).
|
|
35
|
+
* @param message Optional message.
|
|
36
|
+
* @returns The Express response.
|
|
37
|
+
*
|
|
38
|
+
* @example okPage(res, await service.list(scope, { cursor, limit }));
|
|
39
|
+
*/
|
|
40
|
+
export declare function okPage<T>(res: Response, page: CursorPage<T>, message?: string): Response;
|
|
41
|
+
//# sourceMappingURL=respond.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../../src/express/respond.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEpF;;;;;;;;;GASG;AACH,wBAAgB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,cAAc,GAAG,QAAQ,CAGhH;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,SAAY,GAAG,QAAQ,CAEhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAExF"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC"}
|
|
@@ -1,14 +1,35 @@
|
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
1
2
|
import winston from 'winston';
|
|
2
3
|
import type { Logger } from '../types/index.js';
|
|
3
|
-
|
|
4
|
-
export
|
|
4
|
+
export { DEFAULT_ALLOW_KEYS, DEFAULT_REDACT_KEYS, REDACTED, createKeyClassifier, maskPhoneForLog, maskPhonesInText, redactValue } from './redact.js';
|
|
5
|
+
export type { KeyClassifier } from './redact.js';
|
|
6
|
+
/** Options for {@link createLogger}. */
|
|
5
7
|
export interface LoggerOptions {
|
|
8
|
+
/** Minimum level; defaults to `LOG_LEVEL`, else `info` in production and `debug` elsewhere. */
|
|
6
9
|
level?: string;
|
|
7
|
-
/** `json` for machines (default in production), `pretty` for humans. */
|
|
10
|
+
/** `json` for machines (default in production), `pretty` for humans. Files and streams are always JSON. */
|
|
8
11
|
format?: 'json' | 'pretty';
|
|
12
|
+
/** Extra sensitive words, matched like {@link DEFAULT_REDACT_KEYS} (e.g. `nationalId`). */
|
|
9
13
|
redactKeys?: string[];
|
|
14
|
+
/** Exact keys never redacted; replaces {@link DEFAULT_ALLOW_KEYS}. */
|
|
15
|
+
allowKeys?: string[];
|
|
16
|
+
/** Also append JSON lines to this file (e.g. `logs/api.log`). */
|
|
17
|
+
filePath?: string;
|
|
18
|
+
/** Also write JSON lines to this stream (log shippers, tests). */
|
|
19
|
+
stream?: Writable;
|
|
10
20
|
}
|
|
11
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Structured logger. Every line carries `service` and, inside a request or {@link runWithContext}, the
|
|
23
|
+
* context's `correlationId`, `userId` and `scopes`. Secrets are redacted by key word (see
|
|
24
|
+
* {@link DEFAULT_REDACT_KEYS}) and phone numbers are masked to their last 4 digits, in the message and
|
|
25
|
+
* at any depth of the metadata. Writes to stdout (JSON in production, pretty otherwise; silent under
|
|
26
|
+
* `NODE_ENV=test` unless `LOG_IN_TESTS` is set) plus an optional file and stream.
|
|
27
|
+
*
|
|
28
|
+
* @param service Service name on every line.
|
|
29
|
+
* @param options Level, format, extra redact/allow keys, file path, stream.
|
|
30
|
+
* @returns A winston logger that satisfies {@link Logger}.
|
|
31
|
+
* @example const logger = createLogger('api', { filePath: 'logs/api.log' });
|
|
32
|
+
*/
|
|
12
33
|
export declare function createLogger(service: string, options?: LoggerOptions): winston.Logger & Logger;
|
|
13
34
|
/** Logger that discards everything — handy default for libraries and tests. */
|
|
14
35
|
export declare const silentLogger: Logger;
|
|
@@ -17,6 +38,11 @@ export declare const silentLogger: Logger;
|
|
|
17
38
|
* meta wins on a key clash. `undefined` context values are dropped so lines never carry empty keys.
|
|
18
39
|
* Works over any {@link Logger} (winston, a test spy, or another child), so handlers can create one
|
|
19
40
|
* per message and pass it down.
|
|
41
|
+
*
|
|
42
|
+
* @param logger The logger to write through.
|
|
43
|
+
* @param context Values added to every line.
|
|
44
|
+
* @returns A {@link Logger}.
|
|
45
|
+
* @example const log = childLogger(logger, { jobId });
|
|
20
46
|
*/
|
|
21
47
|
export declare function childLogger(logger: Logger, context: Record<string, unknown>): Logger;
|
|
22
48
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/logging/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/logging/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,mBAAmB,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrJ,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2CjD,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2GAA2G;IAC3G,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,CAqBlG;AAED,+EAA+E;AAC/E,eAAO,MAAM,YAAY,EAAE,MAA6E,CAAC;AAEzG;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAKpF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret redaction and phone masking for log lines. Matching is by key *word*, not substring: a key is
|
|
3
|
+
* split on camelCase and separators (`refresh_token` → `refresh`, `token`; `OTPCode` → `otp`, `code`),
|
|
4
|
+
* and it is sensitive when a word (or two adjacent words joined, e.g. `api`+`key`) equals a listed term
|
|
5
|
+
* or its plural. So `accessToken` and `Set-Cookie` are redacted while `pinned` or `spinner` are not.
|
|
6
|
+
*/
|
|
7
|
+
/** Words whose values are always replaced with `[REDACTED]`. Apps add their own via `redactKeys`. */
|
|
8
|
+
export declare const DEFAULT_REDACT_KEYS: readonly string[];
|
|
9
|
+
/** Keys that are never redacted although they contain a listed word (error, status and reference codes). */
|
|
10
|
+
export declare const DEFAULT_ALLOW_KEYS: readonly string[];
|
|
11
|
+
/** The marker that replaces a secret value. */
|
|
12
|
+
export declare const REDACTED = "[REDACTED]";
|
|
13
|
+
/**
|
|
14
|
+
* Masks every digit except the last four (log rule; the UI uses `maskPhone` from common).
|
|
15
|
+
*
|
|
16
|
+
* @param value A phone number in any format.
|
|
17
|
+
* @returns e.g. `********5678`; values with fewer than 5 digits are fully masked.
|
|
18
|
+
* @example maskPhoneForLog('15551234567') // '*******4567'
|
|
19
|
+
*/
|
|
20
|
+
export declare function maskPhoneForLog(value: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Masks phone-number-looking runs inside free text.
|
|
23
|
+
*
|
|
24
|
+
* @param text Any string (a log message or value).
|
|
25
|
+
* @returns The text with each 9–15 digit run masked to its last 4 digits.
|
|
26
|
+
* @example maskPhonesInText('OTP sent to 15551234567') // 'OTP sent to *******4567'
|
|
27
|
+
*/
|
|
28
|
+
export declare function maskPhonesInText(text: string): string;
|
|
29
|
+
/** Decides, per key, whether a value is a secret, a phone number or neither. */
|
|
30
|
+
export interface KeyClassifier {
|
|
31
|
+
isSecret(key: string): boolean;
|
|
32
|
+
isPhone(key: string): boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Builds a key classifier from the default terms plus app-specific ones.
|
|
36
|
+
*
|
|
37
|
+
* @param extraKeys Extra words (matched like the defaults, case-insensitive).
|
|
38
|
+
* @param allowKeys Exact keys never treated as secret (defaults to {@link DEFAULT_ALLOW_KEYS}).
|
|
39
|
+
* @returns The classifier.
|
|
40
|
+
* @example createKeyClassifier(['nationalId']).isSecret('nationalId') // true
|
|
41
|
+
*/
|
|
42
|
+
export declare function createKeyClassifier(extraKeys?: readonly string[], allowKeys?: readonly string[]): KeyClassifier;
|
|
43
|
+
/**
|
|
44
|
+
* Returns a copy of `value` with secrets replaced by `[REDACTED]` and phone numbers masked, at any depth
|
|
45
|
+
* (up to 8 levels; deeper values are dropped as `[TRUNCATED]`). Errors are kept as-is.
|
|
46
|
+
*
|
|
47
|
+
* @param value Log metadata (object, array or scalar).
|
|
48
|
+
* @param classifier From {@link createKeyClassifier}.
|
|
49
|
+
* @param depth Internal recursion depth; callers omit it.
|
|
50
|
+
* @returns The redacted copy; the input is not modified.
|
|
51
|
+
* @example redactValue({ user: { otp: '1234', phone: '15551234567' } }, createKeyClassifier())
|
|
52
|
+
*/
|
|
53
|
+
export declare function redactValue(value: unknown, classifier: KeyClassifier, depth?: number): unknown;
|
|
54
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../../src/logging/redact.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qGAAqG;AACrG,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAGhD,CAAC;AAEF,4GAA4G;AAC5G,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAAwF,CAAC;AAQzI,+CAA+C;AAC/C,eAAO,MAAM,QAAQ,eAAe,CAAC;AAGrC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAWD,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,GAAE,SAAS,MAAM,EAAO,EAAE,SAAS,GAAE,SAAS,MAAM,EAAuB,GAAG,aAAa,CAgBvI;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,SAAI,GAAG,OAAO,CAYzF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/messaging/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9D,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/messaging/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9D,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,cAAc,CAAC;IAC3B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,YAAY,CAAC;IACtB,0FAA0F;IAC1F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CA0BpE"}
|
|
@@ -1,56 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Staff alerts (messaging layer helper): stage one notification dispatch per recipient of a
|
|
3
|
+
* permission through the caller's outbox. App vocabulary (category, channels, command name) is
|
|
4
|
+
* passed in as options; nothing app-specific is assumed.
|
|
5
|
+
*/
|
|
6
|
+
import { type DispatchValue } from '../contracts/notification-dispatch.js';
|
|
3
7
|
import type { Logger } from '../types/index.js';
|
|
4
8
|
import type { EnvelopeMeta } from './envelope.js';
|
|
5
|
-
|
|
9
|
+
import type { StaffRecipientResolver } from './staff-recipients.js';
|
|
10
|
+
/**
|
|
11
|
+
* The slice of a service's outbox the notifier needs.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam E The service's transaction/executor type.
|
|
14
|
+
* @example const outbox: CommandOutbox<Tx> = { command: (tx, name, data, meta) => outboxRepo.stageCommand(tx, name, data, meta) };
|
|
15
|
+
*/
|
|
6
16
|
export interface CommandOutbox<E> {
|
|
7
17
|
command<T>(executor: E, command: string, data: T, meta?: EnvelopeMeta): Promise<void>;
|
|
8
18
|
}
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
private readonly byPermission;
|
|
16
|
-
constructor(byPermission: Readonly<Record<string, readonly DispatchRecipient[]>>);
|
|
17
|
-
resolve(permission: string): Promise<DispatchRecipient[]>;
|
|
18
|
-
}
|
|
19
|
-
export interface StaffAlert {
|
|
19
|
+
/**
|
|
20
|
+
* One operational alert to the staff who hold a permission.
|
|
21
|
+
*
|
|
22
|
+
* @example { template: 'payout-failed', permission: 'payouts.manage', data: { reference: 'PO-1' } }
|
|
23
|
+
*/
|
|
24
|
+
export interface StaffAlert<Ch extends string = string> {
|
|
20
25
|
/** Seeded notification template slug. */
|
|
21
26
|
template: string;
|
|
22
|
-
/** The permission its recipients hold (e.g. `
|
|
27
|
+
/** The permission its recipients hold (e.g. `orders.manage`). */
|
|
23
28
|
permission: string;
|
|
24
29
|
/** Template variables. */
|
|
25
30
|
data: Record<string, DispatchValue>;
|
|
26
|
-
/**
|
|
27
|
-
channels?:
|
|
31
|
+
/** Channels for this alert (at least one); defaults to the notifier's `defaultChannels`. */
|
|
32
|
+
channels?: [Ch, ...Ch[]];
|
|
28
33
|
}
|
|
29
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Tracing for the staged commands; the actor is always the system.
|
|
36
|
+
*
|
|
37
|
+
* @example { correlationId: correlationId(req), aggregate: { type: 'payout', id: payout.id } }
|
|
38
|
+
*/
|
|
30
39
|
export type StaffAlertMeta = Pick<EnvelopeMeta, 'correlationId' | 'aggregate'>;
|
|
31
40
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
41
|
+
* How the notifier stages commands. All app vocabulary is passed in; nothing is assumed.
|
|
42
|
+
*
|
|
43
|
+
* @example { category: 'staff', defaultChannels: ['email'], logger }
|
|
44
|
+
*/
|
|
45
|
+
export interface StaffNotifierOptions<C extends string, Ch extends string> {
|
|
46
|
+
/** The dispatch category for staff alerts in this app (e.g. `staff`). */
|
|
47
|
+
category: C;
|
|
48
|
+
/** Channels used when an alert names none. Staff addresses usually have no account, so typically `['email']`. */
|
|
49
|
+
defaultChannels: [Ch, ...Ch[]];
|
|
50
|
+
/** Command name; defaults to {@link NOTIFICATION_DISPATCH}. */
|
|
51
|
+
command?: string;
|
|
52
|
+
/** Warns when an alert resolves to no recipients; silent when omitted. */
|
|
53
|
+
logger?: Logger;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Stages one dispatch command per recipient through the outbox, in the caller's transaction, so an
|
|
57
|
+
* alert is sent if and only if the state change that raised it commits. Never sends anything itself.
|
|
34
58
|
* An alert that resolves to nobody is logged as a warning (an unconfigured list must not fail silently).
|
|
59
|
+
* Staff alerts always bypass recipient preferences and record the target permission.
|
|
60
|
+
*
|
|
61
|
+
* @typeParam E The service's transaction/executor type.
|
|
62
|
+
* @typeParam C The app's dispatch categories.
|
|
63
|
+
* @typeParam Ch The app's dispatch channels.
|
|
64
|
+
* @example
|
|
65
|
+
* const notifier = new StaffNotifier(outbox, new ConfiguredStaffRecipients({ 'payouts.manage': config.financeEmails }),
|
|
66
|
+
* { category: 'staff', defaultChannels: ['email'], logger });
|
|
67
|
+
* await notifier.alert(tx, { template: 'payout-failed', permission: 'payouts.manage', data: { reference } }, { correlationId });
|
|
35
68
|
*/
|
|
36
|
-
export declare class StaffNotifier<E> {
|
|
69
|
+
export declare class StaffNotifier<E, C extends string = string, Ch extends string = string> {
|
|
37
70
|
private readonly outbox;
|
|
38
71
|
private readonly recipients;
|
|
72
|
+
private readonly category;
|
|
73
|
+
private readonly defaultChannels;
|
|
74
|
+
private readonly command;
|
|
39
75
|
private readonly logger;
|
|
40
|
-
constructor(outbox: CommandOutbox<E>, recipients: StaffRecipientResolver,
|
|
41
|
-
/**
|
|
42
|
-
|
|
76
|
+
constructor(outbox: CommandOutbox<E>, recipients: StaffRecipientResolver, options: StaffNotifierOptions<C, Ch>);
|
|
77
|
+
/**
|
|
78
|
+
* Stage the alert for every recipient of its permission.
|
|
79
|
+
*
|
|
80
|
+
* @param executor The caller's open transaction; the commands commit or roll back with it.
|
|
81
|
+
* @param alert Template, permission, variables and optional channels.
|
|
82
|
+
* @param meta Correlation id and aggregate for tracing; the actor is always the system.
|
|
83
|
+
* @returns How many commands were staged (0 when nobody is configured).
|
|
84
|
+
*/
|
|
85
|
+
alert(executor: E, alert: StaffAlert<Ch>, meta?: StaffAlertMeta): Promise<number>;
|
|
43
86
|
}
|
|
44
|
-
/**
|
|
45
|
-
* A comma-separated staff address list from env (`"a@x.io, b@y.io"`): trimmed, blanks dropped,
|
|
46
|
-
* de-duplicated case-insensitively. An invalid address fails validation, so a typo is caught at boot
|
|
47
|
-
* instead of dead-lettering in notification-service when the alert finally fires.
|
|
48
|
-
*/
|
|
49
|
-
export declare const staffEmailListSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodString>, string[], string | undefined>, string[], string | undefined>, {
|
|
50
|
-
email: string;
|
|
51
|
-
name?: string | undefined;
|
|
52
|
-
userId?: string | null | undefined;
|
|
53
|
-
locale?: string | null | undefined;
|
|
54
|
-
timezone?: string | null | undefined;
|
|
55
|
-
}[], string | undefined>;
|
|
56
87
|
//# sourceMappingURL=staff-notifier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staff-notifier.d.ts","sourceRoot":"","sources":["../../../src/messaging/staff-notifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"staff-notifier.d.ts","sourceRoot":"","sources":["../../../src/messaging/staff-notifier.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvF;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM;IACpD,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpC,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,WAAW,CAAC,CAAC;AAE/E;;;;GAIG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM;IACvE,yEAAyE;IACzE,QAAQ,EAAE,CAAC,CAAC;IACZ,iHAAiH;IACjH,eAAe,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC/B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM;IAO/E,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAP7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAI;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAGb,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,UAAU,EAAE,sBAAsB,EACnD,OAAO,EAAE,oBAAoB,CAAC,CAAC,EAAE,EAAE,CAAC;IAQtC;;;;;;;OAOG;IACG,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;CAoB5F"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staff alert recipients (messaging layer helper): who receives an alert raised for a permission.
|
|
3
|
+
* Today the lists come from configuration; an app can plug in a lookup (e.g. its auth service)
|
|
4
|
+
* by implementing {@link StaffRecipientResolver}.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { type DispatchRecipient } from '../contracts/notification-dispatch.js';
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the recipients who hold a permission.
|
|
10
|
+
*
|
|
11
|
+
* @example const resolver: StaffRecipientResolver = { resolve: async (p) => authClient.usersWithPermission(p) };
|
|
12
|
+
*/
|
|
13
|
+
export interface StaffRecipientResolver {
|
|
14
|
+
/**
|
|
15
|
+
* @param permission The permission an alert targets.
|
|
16
|
+
* @returns Recipients (possibly empty).
|
|
17
|
+
*/
|
|
18
|
+
resolve(permission: string): Promise<DispatchRecipient[]>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Recipients from configuration (env), keyed by the permission an alert targets.
|
|
22
|
+
*
|
|
23
|
+
* @param byPermission Map of permission → recipients, typically built with {@link staffEmailListSchema}.
|
|
24
|
+
* @example new ConfiguredStaffRecipients({ 'payouts.manage': env.FINANCE_ALERT_EMAILS })
|
|
25
|
+
*/
|
|
26
|
+
export declare class ConfiguredStaffRecipients implements StaffRecipientResolver {
|
|
27
|
+
private readonly byPermission;
|
|
28
|
+
constructor(byPermission: Readonly<Record<string, readonly DispatchRecipient[]>>);
|
|
29
|
+
/**
|
|
30
|
+
* @param permission The permission an alert targets.
|
|
31
|
+
* @returns A copy of the configured recipients, or `[]` when none are configured.
|
|
32
|
+
*/
|
|
33
|
+
resolve(permission: string): Promise<DispatchRecipient[]>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A comma-separated staff address list from env (`"a@x.io, b@y.io"`): trimmed, blanks dropped,
|
|
37
|
+
* de-duplicated case-insensitively. An invalid address fails validation, so a typo is caught at boot
|
|
38
|
+
* instead of dead-lettering in the notification-service when the alert finally fires.
|
|
39
|
+
*
|
|
40
|
+
* @returns (on parse) `DispatchRecipient[]` with `email` only.
|
|
41
|
+
* @example const config = z.object({ FINANCE_ALERT_EMAILS: staffEmailListSchema }).parse(process.env);
|
|
42
|
+
*/
|
|
43
|
+
export declare const staffEmailListSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodString>, string[], string | undefined>, string[], string | undefined>, {
|
|
44
|
+
email: string;
|
|
45
|
+
userId?: string | null | undefined;
|
|
46
|
+
name?: string | undefined;
|
|
47
|
+
locale?: string | null | undefined;
|
|
48
|
+
timezone?: string | null | undefined;
|
|
49
|
+
}[], string | undefined>;
|
|
50
|
+
//# sourceMappingURL=staff-recipients.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staff-recipients.d.ts","sourceRoot":"","sources":["../../../src/messaging/staff-recipients.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAEhG;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;CAC3D;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,YAAW,sBAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAAZ,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAAC;IAEjG;;;OAGG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;CAGhE;AAID;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB;;;;;;wBAegD,CAAC"}
|
|
@@ -13,6 +13,7 @@ export interface AuthUser {
|
|
|
13
13
|
attrs: Record<string, unknown>;
|
|
14
14
|
sessionId?: string;
|
|
15
15
|
}
|
|
16
|
+
/** Offset pagination metadata (page/limit with totals). For large or growing lists prefer {@link CursorPageMeta}. */
|
|
16
17
|
export interface PaginationMeta {
|
|
17
18
|
page: number;
|
|
18
19
|
limit: number;
|
|
@@ -21,18 +22,52 @@ export interface PaginationMeta {
|
|
|
21
22
|
hasNext: boolean;
|
|
22
23
|
hasPrev: boolean;
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Cursor (keyset) pagination metadata: no totals or page numbers, so it stays cheap on large tables.
|
|
27
|
+
* `nextCursor` is opaque to clients (it encodes the sort key + an id tie-breaker); `null` on the last page.
|
|
28
|
+
*/
|
|
29
|
+
export interface CursorPageMeta {
|
|
30
|
+
limit: number;
|
|
31
|
+
nextCursor: string | null;
|
|
32
|
+
hasMore: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** One page of a cursor-paginated list, as a repository or service returns it. */
|
|
35
|
+
export interface CursorPage<T> {
|
|
36
|
+
data: T[];
|
|
37
|
+
meta: CursorPageMeta;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The standard response envelope. Success: `{ success: true, message, data, meta? }`.
|
|
41
|
+
* Error: see {@link ErrorBody}.
|
|
42
|
+
*/
|
|
24
43
|
export interface ApiResponse<T = unknown> {
|
|
25
44
|
success: boolean;
|
|
26
45
|
message: string;
|
|
27
46
|
code?: string;
|
|
28
47
|
data?: T;
|
|
29
|
-
meta?: PaginationMeta;
|
|
48
|
+
meta?: PaginationMeta | CursorPageMeta;
|
|
49
|
+
errors?: Record<string, string[]>;
|
|
50
|
+
/** Correlation id of the failed request (error bodies only), so support can find the log lines. */
|
|
51
|
+
requestId?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The error body every service returns: `{ success: false, code, message, errors?, requestId? }`.
|
|
55
|
+
* `code` is UPPER_SNAKE_CASE; `errors` maps field paths to messages (validation only); 5xx bodies
|
|
56
|
+
* always carry a generic message.
|
|
57
|
+
*/
|
|
58
|
+
export interface ErrorBody {
|
|
59
|
+
success: false;
|
|
60
|
+
code: string;
|
|
61
|
+
message: string;
|
|
30
62
|
errors?: Record<string, string[]>;
|
|
63
|
+
requestId?: string;
|
|
31
64
|
}
|
|
65
|
+
/** One page of an offset-paginated list, as a repository or service returns it. */
|
|
32
66
|
export interface PaginatedResult<T> {
|
|
33
67
|
data: T[];
|
|
34
68
|
meta: PaginationMeta;
|
|
35
69
|
}
|
|
70
|
+
/** Parsed offset-pagination query: 1-based `page` and page size `limit`. */
|
|
36
71
|
export interface PageQuery {
|
|
37
72
|
page: number;
|
|
38
73
|
limit: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,IAAI,CAAC,EAAE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
/** A ULID in canonical form (26 upper-case Crockford base32 chars), as `newId()` makes and `CHAR(26)` stores. */
|
|
2
3
|
export declare const idSchema: z.ZodString;
|
|
4
|
+
/** Route params `{ id }` where `id` is a canonical ULID. Use with `validate({ params: idParamSchema })`. */
|
|
3
5
|
export declare const idParamSchema: z.ZodObject<{
|
|
4
6
|
id: z.ZodString;
|
|
5
7
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -7,6 +9,18 @@ export declare const idParamSchema: z.ZodObject<{
|
|
|
7
9
|
}, {
|
|
8
10
|
id: string;
|
|
9
11
|
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Alias of {@link idParamSchema} for `validate({ params: idParam })`. Stricter than `z.string().ulid()`:
|
|
14
|
+
* lower-case ULIDs are rejected, so a lookup never misses a stored upper-case id.
|
|
15
|
+
*/
|
|
16
|
+
export declare const idParam: z.ZodObject<{
|
|
17
|
+
id: z.ZodString;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
id: string;
|
|
20
|
+
}, {
|
|
21
|
+
id: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** Offset pagination query: `page` ≥ 1 (default 1), `limit` 1–100 (default 20). Prefer cursor pagination (D6). */
|
|
10
24
|
export declare const paginationSchema: z.ZodObject<{
|
|
11
25
|
page: z.ZodDefault<z.ZodNumber>;
|
|
12
26
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
@@ -17,8 +31,11 @@ export declare const paginationSchema: z.ZodObject<{
|
|
|
17
31
|
page?: number | undefined;
|
|
18
32
|
limit?: number | undefined;
|
|
19
33
|
}>;
|
|
34
|
+
/** `asc` or `desc`, default `desc`. */
|
|
20
35
|
export declare const sortOrderSchema: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
|
36
|
+
/** Trimmed, lower-cased email address, max 191 chars. */
|
|
21
37
|
export declare const emailSchema: z.ZodString;
|
|
38
|
+
/** Lower-case kebab-case slug, 1–120 chars. */
|
|
22
39
|
export declare const slugSchema: z.ZodString;
|
|
23
40
|
/** Length-first password rule (NIST 800-63B): 8–128 chars, no composition rules. Tighten per app if needed. */
|
|
24
41
|
export declare const passwordSchema: z.ZodString;
|
|
@@ -26,9 +43,23 @@ export declare const passwordSchema: z.ZodString;
|
|
|
26
43
|
export declare const booleanish: z.ZodEffects<z.ZodUnion<[z.ZodBoolean, z.ZodEnum<["true", "false", "1", "0", "yes", "no"]>]>, boolean, boolean | "0" | "1" | "true" | "false" | "yes" | "no">;
|
|
27
44
|
/** Comma list or repeated query param → string[]. */
|
|
28
45
|
export declare const csvList: z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, string[], string | string[]>;
|
|
29
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Converts Zod issues into the `{ field: [messages] }` shape used by the error envelope.
|
|
48
|
+
*
|
|
49
|
+
* @param error A Zod error.
|
|
50
|
+
* @returns Messages keyed by dotted field path (`_` for the root).
|
|
51
|
+
* @example zodIssuesToErrors(result.error) // { 'items.0': ['Expected string'] }
|
|
52
|
+
*/
|
|
30
53
|
export declare function zodIssuesToErrors(error: z.ZodError): Record<string, string[]>;
|
|
31
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Parses `input` or throws a ValidationError (422).
|
|
56
|
+
*
|
|
57
|
+
* @param schema Zod schema.
|
|
58
|
+
* @param input Untrusted value.
|
|
59
|
+
* @returns The parsed value.
|
|
60
|
+
* @example const dto = parseOrThrow(createSchema, payload);
|
|
61
|
+
*/
|
|
32
62
|
export declare function parseOrThrow<S extends z.ZodTypeAny>(schema: S, input: unknown): z.infer<S>;
|
|
63
|
+
/** Zod re-exported so services build schemas on the same zod instance as the library. */
|
|
33
64
|
export { z };
|
|
34
65
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/validation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,QAAQ,aAA6C,CAAC;AAEnE,eAAO,MAAM,aAAa;;;;;;EAA6B,CAAC;AAExD,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AAEH,eAAO,MAAM,eAAe,0CAA0C,CAAC;AAEvE,eAAO,MAAM,WAAW,aAA0E,CAAC;AAEnG,eAAO,MAAM,UAAU,aAAwF,CAAC;AAEhH,+GAA+G;AAC/G,eAAO,MAAM,cAAc,aAA+F,CAAC;AAE3H,0DAA0D;AAC1D,eAAO,MAAM,UAAU,+JAAoJ,CAAC;AAE5K,qDAAqD;AACrD,eAAO,MAAM,OAAO,uGAA0I,CAAC;AAE/J
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/validation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,iHAAiH;AACjH,eAAO,MAAM,QAAQ,aAA6C,CAAC;AAEnE,4GAA4G;AAC5G,eAAO,MAAM,aAAa;;;;;;EAA6B,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;;;EAAgB,CAAC;AAErC,kHAAkH;AAClH,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AAEH,uCAAuC;AACvC,eAAO,MAAM,eAAe,0CAA0C,CAAC;AAEvE,yDAAyD;AACzD,eAAO,MAAM,WAAW,aAA0E,CAAC;AAEnG,+CAA+C;AAC/C,eAAO,MAAM,UAAU,aAAwF,CAAC;AAEhH,+GAA+G;AAC/G,eAAO,MAAM,cAAc,aAA+F,CAAC;AAE3H,0DAA0D;AAC1D,eAAO,MAAM,UAAU,+JAAoJ,CAAC;AAE5K,qDAAqD;AACrD,eAAO,MAAM,OAAO,uGAA0I,CAAC;AAE/J;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAO7E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAI1F;AAED,yFAAyF;AACzF,OAAO,EAAE,CAAC,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heavybit/shared-lib",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "App-agnostic building blocks for Express/TypeScript microservices: gateway identity, access scoping, RabbitMQ events/commands/RPC with retries and DLQs, outbox, cache-aside, rate limiting, sockets, signing, logging and config.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|