@stone-js/validation 0.8.9 → 0.8.11

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.
@@ -1,13 +1,13 @@
1
- import { ValidationSchema, StandardSchemaV1 } from '../declarations.js';
1
+ import { NativeSchema, StandardSchemaV1 } from '../declarations.js';
2
2
  /**
3
3
  * Adapts a [Standard Schema](https://standardschema.dev) (Zod 3.24+, Valibot, ArkType, …) to the
4
- * Stone.js {@link ValidationSchema} contract. Only the synchronous path is supported here; an
4
+ * Stone.js {@link NativeSchema} contract. Only the synchronous path is supported here; an
5
5
  * async schema throws a clear {@link ValidationError} so the misuse is obvious.
6
6
  *
7
7
  * @param schema - The Standard Schema.
8
8
  * @returns A Stone.js validation schema.
9
9
  */
10
- export declare function fromStandard<T>(schema: StandardSchemaV1<T>): ValidationSchema<T>;
10
+ export declare function fromStandard<T>(schema: StandardSchemaV1<T>): NativeSchema<T>;
11
11
  /**
12
12
  * Whether a value implements the Standard Schema v1 contract.
13
13
  *
@@ -1,13 +1,13 @@
1
- import { ValidationSchema, ZodLikeSchema } from '../declarations.js';
1
+ import { NativeSchema, ZodLikeSchema } from '../declarations.js';
2
2
  /**
3
3
  * Adapts a Zod-style schema (anything exposing a synchronous `safeParse`) to the Stone.js
4
- * {@link ValidationSchema} contract. Structural — never imports Zod, so it works with any
4
+ * {@link NativeSchema} contract. Structural — never imports Zod, so it works with any
5
5
  * compatible engine and keeps the module dependency-free.
6
6
  *
7
7
  * @param schema - The Zod-like schema.
8
8
  * @returns A Stone.js validation schema.
9
9
  */
10
- export declare function fromZod<T>(schema: ZodLikeSchema<T>): ValidationSchema<T>;
10
+ export declare function fromZod<T>(schema: ZodLikeSchema<T>): NativeSchema<T>;
11
11
  /**
12
12
  * Whether a value looks like a Zod-style schema.
13
13
  *
@@ -29,7 +29,7 @@ export type ValidationResult<T> = {
29
29
  * implement the Standard Schema spec, or expose `safeParse`), so you write the schema once and
30
30
  * use it identically on the backend and the frontend.
31
31
  */
32
- export interface ValidationSchema<T = unknown> {
32
+ export interface NativeSchema<T = unknown> {
33
33
  /** Validate a value, returning a normalised result. */
34
34
  validate: (data: unknown) => ValidationResult<T>;
35
35
  }
@@ -76,10 +76,10 @@ export type ZodSafeParseResult<T> = {
76
76
  };
77
77
  };
78
78
  /**
79
- * Anything that can be resolved into a {@link ValidationSchema}: a native Stone.js schema, a
79
+ * Anything that can be resolved into a {@link NativeSchema}: a native Stone.js schema, a
80
80
  * Standard Schema, or a Zod-like schema.
81
81
  */
82
- export type SchemaInput<T = unknown> = ValidationSchema<T> | StandardSchemaV1<T> | ZodLikeSchema<T>;
82
+ export type SchemaInput<T = unknown> = NativeSchema<T> | StandardSchemaV1<T> | ZodLikeSchema<T>;
83
83
  /**
84
84
  * The telemetry-free validation service contract.
85
85
  */
@@ -21,7 +21,7 @@ export interface ValidationDecoratorOptions extends ValidationConfig {
21
21
  * ```typescript
22
22
  * import { Validation } from '@stone-js/validation'
23
23
  *
24
- * @Validation({ abortEarly: false })
24
+ * @Validation({ schemas: { listQuery: ListQuerySchema } })
25
25
  * @StoneApp({ name: 'my-app' })
26
26
  * export class Application {}
27
27
  * ```
@@ -1,18 +1,28 @@
1
+ import { ClassType } from '@stone-js/core';
1
2
  /**
2
- * Class decorator: register a schema class under a name.
3
+ * Declare a class as a rule set.
3
4
  *
4
- * ```ts
5
- * @ValidationSchema('createUser')
6
- * export class CreateUserSchema implements IValidationSchema { rules () { … } }
7
- * ```
5
+ * Three statements in one, which is why nothing has to be wired by hand:
8
6
  *
9
- * Routes and handlers then refer to it by name (`@Validate('createUser')`), so schemas live in their
10
- * own files, organised however the application likes, and nothing has to be imported at the route.
11
- * The class is resolved by the container, so its constructor receives services and `rules()` can use
12
- * them.
7
+ * 1. **It is a service.** The container builds it, as a singleton, so its constructor is auto-wired
8
+ * like any other class: a repository, a client, a translator, whatever it destructures is resolved
9
+ * for it. That is what lets a rule set depend on the application instead of on constants.
10
+ * 2. **It is reachable by name.** The alias is bound as `schema:<name>`, prefixed on purpose: an
11
+ * application is free to bind its own service under a plain word, and a declaration named after a
12
+ * domain concept must not compete for that name.
13
+ * 3. **It activates the module.** The blueprint comes with the decorator, so declaring this is the
14
+ * whole setup, and a route naming it resolves to this class.
13
15
  *
14
- * @param alias - The name the schema is registered under. Defaults to the class name, which the
15
- * discovery middleware fills in, since it is the one holding the class.
16
+ * @param alias - The name a route refers to it by. Defaults to the class name.
16
17
  * @returns A class decorator.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * @ValidationSchema('createUser')
22
+ * export class CreateUser {
23
+ * constructor (private readonly users: UserRepository) {}
24
+ * rules (): RouteValidationRules { return { body: { email: { rules: 'email' } } } }
25
+ * }
26
+ * ```
17
27
  */
18
- export declare const ValidationSchema: (alias?: string) => ClassDecorator;
28
+ export declare const ValidationSchema: <T extends ClassType = ClassType>(alias?: string) => ClassDecorator;
package/dist/index.d.ts CHANGED
@@ -1,18 +1,18 @@
1
- export * from './ValidationServiceProvider.js';
2
- export * from './Validator.js';
3
1
  export * from './adapters/standardSchema.js';
4
2
  export * from './adapters/zod.js';
5
3
  export * from './declarations.js';
4
+ export * from './decorators/constants.js';
6
5
  export * from './decorators/Validate.js';
7
6
  export * from './decorators/Validation.js';
8
7
  export * from './decorators/ValidationSchema.js';
9
- export * from './decorators/constants.js';
10
8
  export * from './errors/ValidationError.js';
11
9
  export * from './middleware/BlueprintMiddleware.js';
12
- export * from './middleware/ValidateRouteMiddleware.js';
13
10
  export * from './middleware/validate.js';
11
+ export * from './middleware/ValidateRouteMiddleware.js';
14
12
  export * from './options/ValidationBlueprint.js';
15
13
  export * from './schema.js';
16
14
  export * from './schemaClass.js';
17
15
  export * from './sources.js';
18
16
  export * from './validateEvent.js';
17
+ export * from './ValidationServiceProvider.js';
18
+ export * from './Validator.js';
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { IntegrationError, hasMetadata, getMetadata, classDecoratorLegacyWrapper, addBlueprint, methodDecoratorLegacyWrapper, addMetadata, setClassMetadata } from '@stone-js/core';
1
+ import { IntegrationError, methodDecoratorLegacyWrapper, addMetadata, hasMetadata, getMetadata, classDecoratorLegacyWrapper, addBlueprint, setMetadata, SERVICE_KEY } from '@stone-js/core';
2
2
  import { cloneValue } from '@stone-js/config';
3
3
 
4
4
  /**
5
5
  * Adapts a Zod-style schema (anything exposing a synchronous `safeParse`) to the Stone.js
6
- * {@link ValidationSchema} contract. Structural — never imports Zod, so it works with any
6
+ * {@link NativeSchema} contract. Structural — never imports Zod, so it works with any
7
7
  * compatible engine and keeps the module dependency-free.
8
8
  *
9
9
  * @param schema - The Zod-like schema.
@@ -71,7 +71,7 @@ class ValidationError extends IntegrationError {
71
71
 
72
72
  /**
73
73
  * Adapts a [Standard Schema](https://standardschema.dev) (Zod 3.24+, Valibot, ArkType, …) to the
74
- * Stone.js {@link ValidationSchema} contract. Only the synchronous path is supported here; an
74
+ * Stone.js {@link NativeSchema} contract. Only the synchronous path is supported here; an
75
75
  * async schema throws a clear {@link ValidationError} so the misuse is obvious.
76
76
  *
77
77
  * @param schema - The Standard Schema.
@@ -110,7 +110,7 @@ function isStandardSchema(value) {
110
110
  }
111
111
 
112
112
  /**
113
- * Normalises any supported schema input into a Stone.js {@link ValidationSchema}.
113
+ * Normalises any supported schema input into a Stone.js {@link NativeSchema}.
114
114
  *
115
115
  * Resolution order: a Standard Schema (`~standard`) is preferred (canonical, covers Zod 3.24+,
116
116
  * Valibot, ArkType), then a Zod-like `safeParse`, then a native Stone.js schema (`validate`).
@@ -132,7 +132,7 @@ function resolveSchema(input) {
132
132
  throw new ValidationError('Unrecognised validation schema: expected a Standard Schema, a Zod-like schema, or a Stone.js schema.', { issues: [] });
133
133
  }
134
134
  /**
135
- * Whether a value is already a native Stone.js {@link ValidationSchema}.
135
+ * Whether a value is already a native Stone.js {@link NativeSchema}.
136
136
  *
137
137
  * @param value - The value to test.
138
138
  * @returns True when it exposes a `validate` function.
@@ -407,6 +407,30 @@ const VALIDATE_KEY = '@stone-js/validation/validate';
407
407
  */
408
408
  const VALIDATION_SCHEMA_KEY = '@stone-js/validation/schema';
409
409
 
410
+ /**
411
+ * Method decorator: declare what a handler accepts.
412
+ *
413
+ * ```ts
414
+ * @Validate(CreateUserSchema) // the body
415
+ * @Validate({ body: CreateUserSchema, query: Page }) // several sources
416
+ * @Validate('createUser') // a registered schema class
417
+ * ```
418
+ *
419
+ * This knows nothing about the router, and that is the point: the declaration is recorded on the
420
+ * handler itself, under this module's own key, so validation runs the same in a routed application,
421
+ * a single-handler service, a CLI command or the browser. When a router *is* in play you may instead
422
+ * put it on the route (`@Post('/users', { validation: … })`), which keeps the method uncluttered and
423
+ * puts everything a route does in one place; both forms end up in the same middleware.
424
+ *
425
+ * @param validation - What the handler accepts.
426
+ * @returns A method decorator.
427
+ */
428
+ const Validate = (validation) => {
429
+ return methodDecoratorLegacyWrapper((_target, context) => {
430
+ addMetadata(context, VALIDATE_KEY, { action: context.name, validation });
431
+ });
432
+ };
433
+
410
434
  /**
411
435
  * Route middleware: validates what a route declared, before its handler runs.
412
436
  *
@@ -652,7 +676,7 @@ const validationBlueprint = {
652
676
  * ```typescript
653
677
  * import { Validation } from '@stone-js/validation'
654
678
  *
655
- * @Validation({ abortEarly: false })
679
+ * @Validation({ schemas: { listQuery: ListQuerySchema } })
656
680
  * @StoneApp({ name: 'my-app' })
657
681
  * export class Application {}
658
682
  * ```
@@ -669,48 +693,44 @@ const Validation = (options = {}) => {
669
693
  };
670
694
 
671
695
  /**
672
- * Method decorator: declare what a handler accepts.
696
+ * Declare a class as a rule set.
673
697
  *
674
- * ```ts
675
- * @Validate(CreateUserSchema) // the body
676
- * @Validate({ body: CreateUserSchema, query: Page }) // several sources
677
- * @Validate('createUser') // a registered schema class
678
- * ```
698
+ * Three statements in one, which is why nothing has to be wired by hand:
679
699
  *
680
- * This knows nothing about the router, and that is the point: the declaration is recorded on the
681
- * handler itself, under this module's own key, so validation runs the same in a routed application,
682
- * a single-handler service, a CLI command or the browser. When a router *is* in play you may instead
683
- * put it on the route (`@Post('/users', { validation: })`), which keeps the method uncluttered and
684
- * puts everything a route does in one place; both forms end up in the same middleware.
700
+ * 1. **It is a service.** The container builds it, as a singleton, so its constructor is auto-wired
701
+ * like any other class: a repository, a client, a translator, whatever it destructures is resolved
702
+ * for it. That is what lets a rule set depend on the application instead of on constants.
703
+ * 2. **It is reachable by name.** The alias is bound as `schema:<name>`, prefixed on purpose: an
704
+ * application is free to bind its own service under a plain word, and a declaration named after a
705
+ * domain concept must not compete for that name.
706
+ * 3. **It activates the module.** The blueprint comes with the decorator, so declaring this is the
707
+ * whole setup, and a route naming it resolves to this class.
685
708
  *
686
- * @param validation - What the handler accepts.
687
- * @returns A method decorator.
688
- */
689
- const Validate = (validation) => {
690
- return methodDecoratorLegacyWrapper((_target, context) => {
691
- addMetadata(context, VALIDATE_KEY, { action: context.name, validation });
692
- });
693
- };
694
-
695
- /**
696
- * Class decorator: register a schema class under a name.
709
+ * @param alias - The name a route refers to it by. Defaults to the class name.
710
+ * @returns A class decorator.
697
711
  *
712
+ * @example
698
713
  * ```ts
699
714
  * @ValidationSchema('createUser')
700
- * export class CreateUserSchema implements IValidationSchema { rules () { … } }
715
+ * export class CreateUser {
716
+ * constructor (private readonly users: UserRepository) {}
717
+ * rules (): RouteValidationRules { return { body: { email: { rules: 'email' } } } }
718
+ * }
701
719
  * ```
702
- *
703
- * Routes and handlers then refer to it by name (`@Validate('createUser')`), so schemas live in their
704
- * own files, organised however the application likes, and nothing has to be imported at the route.
705
- * The class is resolved by the container, so its constructor receives services and `rules()` can use
706
- * them.
707
- *
708
- * @param alias - The name the schema is registered under. Defaults to the class name, which the
709
- * discovery middleware fills in, since it is the one holding the class.
710
- * @returns A class decorator.
711
720
  */
712
721
  const ValidationSchema = (alias) => {
713
- return setClassMetadata(VALIDATION_SCHEMA_KEY, { alias });
722
+ return classDecoratorLegacyWrapper((target, context) => {
723
+ const name = alias ?? target.name;
724
+ setMetadata(context, VALIDATION_SCHEMA_KEY, { alias: name });
725
+ setMetadata(context, SERVICE_KEY, { singleton: true, isClass: true, alias: `schema:${name}` });
726
+ addBlueprint(target, context, validationBlueprint, {
727
+ stone: {
728
+ validation: {
729
+ schemas: { [name]: target }
730
+ }
731
+ }
732
+ });
733
+ });
714
734
  };
715
735
 
716
736
  /**
package/dist/schema.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { SchemaInput, ValidationSchema } from './declarations.js';
1
+ import { NativeSchema, SchemaInput } from './declarations.js';
2
2
  /**
3
- * Normalises any supported schema input into a Stone.js {@link ValidationSchema}.
3
+ * Normalises any supported schema input into a Stone.js {@link NativeSchema}.
4
4
  *
5
5
  * Resolution order: a Standard Schema (`~standard`) is preferred (canonical, covers Zod 3.24+,
6
6
  * Valibot, ArkType), then a Zod-like `safeParse`, then a native Stone.js schema (`validate`).
@@ -9,11 +9,11 @@ import { SchemaInput, ValidationSchema } from './declarations.js';
9
9
  * @returns A Stone.js validation schema.
10
10
  * @throws {ValidationError} When the input is not a recognisable schema.
11
11
  */
12
- export declare function resolveSchema<T>(input: SchemaInput<T>): ValidationSchema<T>;
12
+ export declare function resolveSchema<T>(input: SchemaInput<T>): NativeSchema<T>;
13
13
  /**
14
- * Whether a value is already a native Stone.js {@link ValidationSchema}.
14
+ * Whether a value is already a native Stone.js {@link NativeSchema}.
15
15
  *
16
16
  * @param value - The value to test.
17
17
  * @returns True when it exposes a `validate` function.
18
18
  */
19
- export declare function isNativeSchema<T>(value: unknown): value is ValidationSchema<T>;
19
+ export declare function isNativeSchema<T>(value: unknown): value is NativeSchema<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stone-js/validation",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "Framework-agnostic input validation for Stone.js. Define a schema once (Zod, Valibot, ArkType — anything Standard Schema) and validate it identically on the backend and the frontend.",
5
5
  "author": "Mr. Stone <evensstone@gmail.com>",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "node": ">=18.17.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "@stone-js/core": "0.8.9"
43
+ "@stone-js/core": "0.8.11"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@commitlint/cli": "^19.8.1",
@@ -62,7 +62,7 @@
62
62
  "typescript": "^5.6.3",
63
63
  "vitest": "^3.2.4",
64
64
  "zod": "^3.24.1",
65
- "@stone-js/core": "0.8.9"
65
+ "@stone-js/core": "0.8.11"
66
66
  },
67
67
  "ts-standard": {
68
68
  "globals": [
@@ -75,7 +75,7 @@
75
75
  ]
76
76
  },
77
77
  "dependencies": {
78
- "@stone-js/config": "0.8.9"
78
+ "@stone-js/config": "0.8.11"
79
79
  },
80
80
  "scripts": {
81
81
  "lint": "ts-standard src",