@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/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
@@ -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
- 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, voWithValidation, withClockFactory, withCommit, withEventIdFactory };
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