@shirudo/ddd-kit 1.0.0-rc.9 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -1518
- package/dist/http.d.ts +46 -0
- package/dist/http.js +18 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +35 -2
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +28 -28
- package/package.json +10 -5
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ValidationError, ProblemDetailsOptions, ProblemDetails } from '@shirudo/base-error';
|
|
2
|
+
|
|
3
|
+
/** Extension member that carries the collected field issues. */
|
|
4
|
+
type ValidationProblemMember = "errors" | "invalid-params";
|
|
5
|
+
/**
|
|
6
|
+
* Options for {@link toProblemDetails}. Mirrors base-error's
|
|
7
|
+
* `ProblemDetailsOptions` but takes over the `extensions` member to attach the
|
|
8
|
+
* collected field issues, and adds {@link member} to choose the wire key.
|
|
9
|
+
*/
|
|
10
|
+
interface ValidationProblemOptions extends Omit<ProblemDetailsOptions, "extensions"> {
|
|
11
|
+
/**
|
|
12
|
+
* Extension member that carries the field issues. Default `"errors"`
|
|
13
|
+
* (`{ message, path, code?, pointer? }` entries). RFC 9457 does not
|
|
14
|
+
* standardize a multi-error member; `errors` is the common convention.
|
|
15
|
+
*/
|
|
16
|
+
member?: ValidationProblemMember;
|
|
17
|
+
/** Extra public extension members merged alongside the issues. */
|
|
18
|
+
extensions?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Projects a base-error {@link ValidationError} to an RFC 9457 Problem Details
|
|
22
|
+
* object with the collected field issues attached under an extension member.
|
|
23
|
+
*
|
|
24
|
+
* base-error is **safe by default**: `ValidationError.toProblemDetails()` does
|
|
25
|
+
* not expose the issues on its own — they only cross to a client through the
|
|
26
|
+
* `publicIssues()` whitelist. This helper performs that explicit projection and
|
|
27
|
+
* applies sensible validation defaults (`422`, `"Validation Failed"`), so the
|
|
28
|
+
* common boundary case is a one-liner instead of a footgun.
|
|
29
|
+
*
|
|
30
|
+
* This is a presentation/transport concern and ships from the opt-in
|
|
31
|
+
* `@shirudo/ddd-kit/http` entry point — the core kit stays transport-free.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { toProblemDetails } from "@shirudo/ddd-kit/http";
|
|
36
|
+
*
|
|
37
|
+
* if (result.isErr()) {
|
|
38
|
+
* return Response.json(toProblemDetails(result.error), { status: 422 });
|
|
39
|
+
* }
|
|
40
|
+
* // → { type, title: "Validation Failed", status: 422,
|
|
41
|
+
* // errors: [{ message: "must be a valid email", path: ["email"], pointer: "email" }] }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function toProblemDetails(error: ValidationError, options?: ValidationProblemOptions): ProblemDetails;
|
|
45
|
+
|
|
46
|
+
export { type ValidationProblemMember, type ValidationProblemOptions, toProblemDetails };
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/http/problem-details.ts
|
|
5
|
+
function toProblemDetails(error, options = {}) {
|
|
6
|
+
const { member = "errors", extensions, ...rest } = options;
|
|
7
|
+
return error.toProblemDetails({
|
|
8
|
+
title: "Validation Failed",
|
|
9
|
+
status: 422,
|
|
10
|
+
...rest,
|
|
11
|
+
extensions: { ...extensions, [member]: error.publicIssues() }
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
__name(toProblemDetails, "toProblemDetails");
|
|
15
|
+
|
|
16
|
+
export { toProblemDetails };
|
|
17
|
+
//# sourceMappingURL=http.js.map
|
|
18
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/http/problem-details.ts"],"names":[],"mappings":";;;;AAkDO,SAAS,gBAAA,CACf,KAAA,EACA,OAAA,GAAoC,EAAC,EACpB;AACjB,EAAA,MAAM,EAAE,MAAA,GAAS,QAAA,EAAU,UAAA,EAAY,GAAG,MAAK,GAAI,OAAA;AACnD,EAAA,OAAO,MAAM,gBAAA,CAAiB;AAAA,IAC7B,KAAA,EAAO,mBAAA;AAAA,IACP,MAAA,EAAQ,GAAA;AAAA,IACR,GAAG,IAAA;AAAA,IACH,UAAA,EAAY,EAAE,GAAG,UAAA,EAAY,CAAC,MAAM,GAAG,KAAA,CAAM,YAAA,EAAa;AAAE,GAC5D,CAAA;AACF;AAXgB,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA","file":"http.js","sourcesContent":["import type {\n\tProblemDetails,\n\tProblemDetailsOptions,\n\tValidationError,\n} from \"@shirudo/base-error\";\n\n/** Extension member that carries the collected field issues. */\nexport type ValidationProblemMember = \"errors\" | \"invalid-params\";\n\n/**\n * Options for {@link toProblemDetails}. Mirrors base-error's\n * `ProblemDetailsOptions` but takes over the `extensions` member to attach the\n * collected field issues, and adds {@link member} to choose the wire key.\n */\nexport interface ValidationProblemOptions\n\textends Omit<ProblemDetailsOptions, \"extensions\"> {\n\t/**\n\t * Extension member that carries the field issues. Default `\"errors\"`\n\t * (`{ message, path, code?, pointer? }` entries). RFC 9457 does not\n\t * standardize a multi-error member; `errors` is the common convention.\n\t */\n\tmember?: ValidationProblemMember;\n\t/** Extra public extension members merged alongside the issues. */\n\textensions?: Record<string, unknown>;\n}\n\n/**\n * Projects a base-error {@link ValidationError} to an RFC 9457 Problem Details\n * object with the collected field issues attached under an extension member.\n *\n * base-error is **safe by default**: `ValidationError.toProblemDetails()` does\n * not expose the issues on its own — they only cross to a client through the\n * `publicIssues()` whitelist. This helper performs that explicit projection and\n * applies sensible validation defaults (`422`, `\"Validation Failed\"`), so the\n * common boundary case is a one-liner instead of a footgun.\n *\n * This is a presentation/transport concern and ships from the opt-in\n * `@shirudo/ddd-kit/http` entry point — the core kit stays transport-free.\n *\n * @example\n * ```ts\n * import { toProblemDetails } from \"@shirudo/ddd-kit/http\";\n *\n * if (result.isErr()) {\n * return Response.json(toProblemDetails(result.error), { status: 422 });\n * }\n * // → { type, title: \"Validation Failed\", status: 422,\n * // errors: [{ message: \"must be a valid email\", path: [\"email\"], pointer: \"email\" }] }\n * ```\n */\nexport function toProblemDetails(\n\terror: ValidationError,\n\toptions: ValidationProblemOptions = {},\n): ProblemDetails {\n\tconst { member = \"errors\", extensions, ...rest } = options;\n\treturn error.toProblemDetails({\n\t\ttitle: \"Validation Failed\",\n\t\tstatus: 422,\n\t\t...rest,\n\t\textensions: { ...extensions, [member]: error.publicIssues() },\n\t});\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Result } from '@shirudo/result';
|
|
2
|
-
import { BaseError } from '@shirudo/base-error';
|
|
2
|
+
import { BaseError, ValidationError } from '@shirudo/base-error';
|
|
3
3
|
import { DeepEqualExceptOptions } from './utils.js';
|
|
4
4
|
export { DeepOmitOptions, Key, PathSegment, deepEqual, deepEqualExcept, deepOmit } from './utils.js';
|
|
5
5
|
|
|
@@ -2553,4 +2553,37 @@ declare abstract class ValueObject<T extends object> implements IValueObject<T>
|
|
|
2553
2553
|
toJSON(): Readonly<T>;
|
|
2554
2554
|
}
|
|
2555
2555
|
|
|
2556
|
-
|
|
2556
|
+
/**
|
|
2557
|
+
* Builds an immutable value object while collecting **all** validation
|
|
2558
|
+
* violations into a single {@link ValidationError}, instead of failing on the
|
|
2559
|
+
* first one. This is the Result-first, multi-error counterpart to
|
|
2560
|
+
* `voWithValidation` (which returns a single string message).
|
|
2561
|
+
*
|
|
2562
|
+
* The `validate` callback receives a fresh `ValidationError` to push field
|
|
2563
|
+
* issues onto (via `addIssue` / `addIssues`) and the raw input. When no issue
|
|
2564
|
+
* was recorded the input is frozen into a `VO<T>` and returned as `Ok`;
|
|
2565
|
+
* otherwise the populated `ValidationError` is returned as `Err`.
|
|
2566
|
+
*
|
|
2567
|
+
* `ValidationError` comes from `@shirudo/base-error` — import it from there to
|
|
2568
|
+
* narrow the `Err` branch, exactly as `Result` is imported from
|
|
2569
|
+
* `@shirudo/result`. It serializes to RFC 9457 Problem Details; use
|
|
2570
|
+
* {@link validationProblemDetails} at the HTTP boundary to surface the issues.
|
|
2571
|
+
*
|
|
2572
|
+
* @example
|
|
2573
|
+
* ```ts
|
|
2574
|
+
* const result = voValidated(
|
|
2575
|
+
* { email, age },
|
|
2576
|
+
* (issues, m) => {
|
|
2577
|
+
* if (!isEmail(m.email))
|
|
2578
|
+
* issues.addIssue({ message: "must be a valid email", path: ["email"] });
|
|
2579
|
+
* if (m.age < 0)
|
|
2580
|
+
* issues.addIssue({ message: "must not be negative", path: ["age"] });
|
|
2581
|
+
* },
|
|
2582
|
+
* "Registration is invalid",
|
|
2583
|
+
* );
|
|
2584
|
+
* // result.isErr() → result.error.publicIssues() has both violations
|
|
2585
|
+
* ```
|
|
2586
|
+
*/
|
|
2587
|
+
declare function voValidated<T>(t: T, validate: (issues: ValidationError, value: T) => void, message?: string): Result<VO<T>, ValidationError>;
|
|
2588
|
+
|
|
2589
|
+
export { type AggregateConfig, AggregateNotFoundError, AggregateRoot, type AggregateSnapshot, type AnyDomainEvent, type ClockFactory, type Command, CommandBus, type CommandHandler, ConcurrencyConflictError, type CreateDomainEventOptions, DeepEqualExceptOptions, DomainError, type DomainEvent, Entity, type EventBus, EventBusImpl, type EventHandler, type EventIdFactory, type EventMetadata, EventSourcedAggregate, type IAggregateRoot, type ICommandBus, type IEntity, type IEventSourcedAggregate, type IQueryBus, type IQueryableRepository, type IRepository, type IValueObject, type Id, type IdGenerator, type Identifiable, InMemoryOutbox, InfrastructureError, MissingHandlerError, type OnceOptions, type Outbox, type OutboxRecord, type Query, QueryBus, type QueryHandler, type TransactionScope, type VO, ValueObject, type Version, copyMetadata, createDomainEvent, createDomainEventWithMetadata, deepFreeze, entityIds, findEntityById, freezeShallow, hasEntityId, mergeMetadata, removeEntityById, replaceEntityById, resetClockFactory, resetEventIdFactory, sameEntity, sameVersion, setClockFactory, setEventIdFactory, updateEntityById, vo, voEquals, voEqualsExcept, voValidated, voWithValidation, withClockFactory, withCommit, withEventIdFactory };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { err, ok } from '@shirudo/result';
|
|
2
|
-
import { BaseError } from '@shirudo/base-error';
|
|
2
|
+
import { BaseError, ValidationError } from '@shirudo/base-error';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
@@ -1260,7 +1260,13 @@ var InMemoryOutbox = class {
|
|
|
1260
1260
|
for (const id of dispatchIds) this.pending.delete(id);
|
|
1261
1261
|
}
|
|
1262
1262
|
};
|
|
1263
|
+
function voValidated(t, validate, message = "Validation failed") {
|
|
1264
|
+
const issues = new ValidationError(message);
|
|
1265
|
+
validate(issues, t);
|
|
1266
|
+
return issues.hasIssues() ? err(issues) : ok(vo(t));
|
|
1267
|
+
}
|
|
1268
|
+
__name(voValidated, "voValidated");
|
|
1263
1269
|
|
|
1264
|
-
export { AggregateNotFoundError, AggregateRoot, CommandBus, ConcurrencyConflictError, DomainError, Entity, EventBusImpl, EventSourcedAggregate, InMemoryOutbox, InfrastructureError, MissingHandlerError, QueryBus, ValueObject, copyMetadata, createDomainEvent, createDomainEventWithMetadata, deepEqual, deepEqualExcept, deepFreeze, deepOmit, entityIds, findEntityById, freezeShallow, hasEntityId, mergeMetadata, removeEntityById, replaceEntityById, resetClockFactory, resetEventIdFactory, sameEntity, sameVersion, setClockFactory, setEventIdFactory, updateEntityById, vo, voEquals, voEqualsExcept, voWithValidation, withClockFactory, withCommit, withEventIdFactory };
|
|
1270
|
+
export { AggregateNotFoundError, AggregateRoot, CommandBus, ConcurrencyConflictError, DomainError, Entity, EventBusImpl, EventSourcedAggregate, InMemoryOutbox, InfrastructureError, MissingHandlerError, QueryBus, ValueObject, copyMetadata, createDomainEvent, createDomainEventWithMetadata, deepEqual, deepEqualExcept, deepFreeze, deepOmit, entityIds, findEntityById, freezeShallow, hasEntityId, mergeMetadata, removeEntityById, replaceEntityById, resetClockFactory, resetEventIdFactory, sameEntity, sameVersion, setClockFactory, setEventIdFactory, updateEntityById, vo, voEquals, voEqualsExcept, voValidated, voWithValidation, withClockFactory, withCommit, withEventIdFactory };
|
|
1265
1271
|
//# sourceMappingURL=index.js.map
|
|
1266
1272
|
//# sourceMappingURL=index.js.map
|