@lunora/values 1.0.0-alpha.6 → 1.0.0-alpha.8

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/index.d.mts CHANGED
@@ -27,8 +27,16 @@ declare class ValidationError extends LunoraError {
27
27
  * capped) literal so messages distinguish `string "7"` from `number 7`;
28
28
  * non-plain objects carry their constructor name (e.g. `Date`) so a class
29
29
  * instance is not flattened to a bare `"object"`.
30
+ *
31
+ * Pass `{ literal: false }` to suppress the concrete primitive literal and
32
+ * return only the type tag (`"string"`, `"number"`, `"bigint"`, …). This is used
33
+ * on `.check()` refinement failures — where the value already passed its type
34
+ * check — so a secret-bearing field (password, token) never surfaces its value
35
+ * in the `ValidationError.message`/`received` that goes to the wire and logs.
30
36
  */
31
- declare const describeValue: (value: unknown) => string;
37
+ declare const describeValue: (value: unknown, options?: {
38
+ literal?: boolean;
39
+ }) => string;
32
40
  declare const formatPath: (path: ValidationPath) => string;
33
41
  /** Branded id type, e.g. `Id<"users">`. */
34
42
  type Id<TableName extends string> = string & {
@@ -238,8 +246,17 @@ declare const id: <TableName extends string>(tableName: TableName) => ColumnVali
238
246
  declare const storage: (bucket?: string) => ColumnValidator<string, string>;
239
247
  declare const literal: <T extends bigint | boolean | number | string | null>(literalValue: T) => ColumnValidator<T, T>;
240
248
  declare const array: <V extends Validator>(inner: V) => ColumnValidator<Infer<V>[], Infer<V>[]>;
249
+ /**
250
+ * Split a value-type map into optional + required keys: any member whose value
251
+ * type includes `undefined` becomes an optional key. The single optionality rule
252
+ * shared by object-shape inference ({@link ObjectShapeType}) and args-map
253
+ * inference (`InferValidatorMap` in `./validator-map`), so the two can never
254
+ * drift. (`InsertShape` stays separate — it additionally `Exclude`s `undefined`
255
+ * from the optional value, a deliberate insert-type difference.)
256
+ */
257
+ type OptionalizeShape<M> = { [K in keyof M as undefined extends M[K] ? K : never]?: M[K] } & { [K in keyof M as undefined extends M[K] ? never : K]: M[K] };
241
258
  type ObjectShape = Record<string, Validator>;
242
- type ObjectShapeType<S extends ObjectShape> = { [K in keyof S as undefined extends Infer<S[K]> ? K : never]?: Infer<S[K]> } & { [K in keyof S as undefined extends Infer<S[K]> ? never : K]: Infer<S[K]> };
259
+ type ObjectShapeType<S extends ObjectShape> = OptionalizeShape<{ [K in keyof S]: Infer<S[K]> }>;
243
260
  declare const objectValidator: <S extends ObjectShape>(shape: S) => ColumnValidator<ObjectShapeType<S>, ObjectShapeType<S>>;
244
261
  declare const record: <K extends Validator<string>, V extends Validator>(keyValidator: K, valueValidator: V) => ColumnValidator<Record<Infer<K>, Infer<V>>, Record<Infer<K>, Infer<V>>>;
245
262
  declare const union: <Vs extends ReadonlyArray<Validator>>(...members: Vs) => ColumnValidator<Infer<Vs[number]>, Infer<Vs[number]>>;
@@ -403,8 +420,13 @@ declare const toJsonSchema: (validator: Validator) => JsonSchema;
403
420
  declare const argsToJsonSchema: (args: Record<string, Validator>) => JsonSchema;
404
421
  /** Map of validators describing a record of named fields (a function's args, a step's args, an HTTP query/body/params). */
405
422
  type ValidatorMap = Record<string, Validator>;
406
- /** Infer the object type from a {@link ValidatorMap} — optional validators (`v.optional`) become optional keys. */
407
- type InferValidatorMap<A extends ValidatorMap> = { [K in keyof A as undefined extends Infer<A[K]> ? K : never]?: Infer<A[K]> } & { [K in keyof A as undefined extends Infer<A[K]> ? never : K]: Infer<A[K]> };
423
+ /**
424
+ * Infer the object type from a {@link ValidatorMap} optional validators
425
+ * (`v.optional`) become optional keys. Shares the single optionality rule with
426
+ * `ObjectShapeType` via {@link OptionalizeShape}, so args-map and object-shape
427
+ * inference can never drift.
428
+ */
429
+ type InferValidatorMap<A extends ValidatorMap> = OptionalizeShape<{ [K in keyof A]: Infer<A[K]> }>;
408
430
  /**
409
431
  * A precompiled fast-path parser for one {@link ValidatorMap}. Returns the fully
410
432
  * built, validated record on a confident success, or the {@link DEFER_VALIDATION}
@@ -462,5 +484,4 @@ declare const installCompiledValidatorMap: (validators: object, compiled: Compil
462
484
  * which case the interpreted loop below runs and owns the result (and any error).
463
485
  */
464
486
  declare const parseValidatorMap: (validators: ValidatorMap, source: Record<string, unknown>, label: string) => Record<string, unknown>;
465
- declare const VERSION = "0.0.0";
466
- export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type Id, type Infer, type InferInsert, type InferSelect, type InferStandardOutput, type InferValidatorMap, type InsertShape, type JsonSchema, type JsonSchemaFragment, type MetaOptions, type SchemaNodeReader, type SelectShape, type ServerDefaultContext, type TimestampColumnValidator, VERSION, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
487
+ export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type Id, type Infer, type InferInsert, type InferSelect, type InferStandardOutput, type InferValidatorMap, type InsertShape, type JsonSchema, type JsonSchemaFragment, type MetaOptions, type SchemaNodeReader, type SelectShape, type ServerDefaultContext, type TimestampColumnValidator, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
package/dist/index.d.ts CHANGED
@@ -27,8 +27,16 @@ declare class ValidationError extends LunoraError {
27
27
  * capped) literal so messages distinguish `string "7"` from `number 7`;
28
28
  * non-plain objects carry their constructor name (e.g. `Date`) so a class
29
29
  * instance is not flattened to a bare `"object"`.
30
+ *
31
+ * Pass `{ literal: false }` to suppress the concrete primitive literal and
32
+ * return only the type tag (`"string"`, `"number"`, `"bigint"`, …). This is used
33
+ * on `.check()` refinement failures — where the value already passed its type
34
+ * check — so a secret-bearing field (password, token) never surfaces its value
35
+ * in the `ValidationError.message`/`received` that goes to the wire and logs.
30
36
  */
31
- declare const describeValue: (value: unknown) => string;
37
+ declare const describeValue: (value: unknown, options?: {
38
+ literal?: boolean;
39
+ }) => string;
32
40
  declare const formatPath: (path: ValidationPath) => string;
33
41
  /** Branded id type, e.g. `Id&lt;"users">`. */
34
42
  type Id<TableName extends string> = string & {
@@ -238,8 +246,17 @@ declare const id: <TableName extends string>(tableName: TableName) => ColumnVali
238
246
  declare const storage: (bucket?: string) => ColumnValidator<string, string>;
239
247
  declare const literal: <T extends bigint | boolean | number | string | null>(literalValue: T) => ColumnValidator<T, T>;
240
248
  declare const array: <V extends Validator>(inner: V) => ColumnValidator<Infer<V>[], Infer<V>[]>;
249
+ /**
250
+ * Split a value-type map into optional + required keys: any member whose value
251
+ * type includes `undefined` becomes an optional key. The single optionality rule
252
+ * shared by object-shape inference ({@link ObjectShapeType}) and args-map
253
+ * inference (`InferValidatorMap` in `./validator-map`), so the two can never
254
+ * drift. (`InsertShape` stays separate — it additionally `Exclude`s `undefined`
255
+ * from the optional value, a deliberate insert-type difference.)
256
+ */
257
+ type OptionalizeShape<M> = { [K in keyof M as undefined extends M[K] ? K : never]?: M[K] } & { [K in keyof M as undefined extends M[K] ? never : K]: M[K] };
241
258
  type ObjectShape = Record<string, Validator>;
242
- type ObjectShapeType<S extends ObjectShape> = { [K in keyof S as undefined extends Infer<S[K]> ? K : never]?: Infer<S[K]> } & { [K in keyof S as undefined extends Infer<S[K]> ? never : K]: Infer<S[K]> };
259
+ type ObjectShapeType<S extends ObjectShape> = OptionalizeShape<{ [K in keyof S]: Infer<S[K]> }>;
243
260
  declare const objectValidator: <S extends ObjectShape>(shape: S) => ColumnValidator<ObjectShapeType<S>, ObjectShapeType<S>>;
244
261
  declare const record: <K extends Validator<string>, V extends Validator>(keyValidator: K, valueValidator: V) => ColumnValidator<Record<Infer<K>, Infer<V>>, Record<Infer<K>, Infer<V>>>;
245
262
  declare const union: <Vs extends ReadonlyArray<Validator>>(...members: Vs) => ColumnValidator<Infer<Vs[number]>, Infer<Vs[number]>>;
@@ -403,8 +420,13 @@ declare const toJsonSchema: (validator: Validator) => JsonSchema;
403
420
  declare const argsToJsonSchema: (args: Record<string, Validator>) => JsonSchema;
404
421
  /** Map of validators describing a record of named fields (a function's args, a step's args, an HTTP query/body/params). */
405
422
  type ValidatorMap = Record<string, Validator>;
406
- /** Infer the object type from a {@link ValidatorMap} — optional validators (`v.optional`) become optional keys. */
407
- type InferValidatorMap<A extends ValidatorMap> = { [K in keyof A as undefined extends Infer<A[K]> ? K : never]?: Infer<A[K]> } & { [K in keyof A as undefined extends Infer<A[K]> ? never : K]: Infer<A[K]> };
423
+ /**
424
+ * Infer the object type from a {@link ValidatorMap} optional validators
425
+ * (`v.optional`) become optional keys. Shares the single optionality rule with
426
+ * `ObjectShapeType` via {@link OptionalizeShape}, so args-map and object-shape
427
+ * inference can never drift.
428
+ */
429
+ type InferValidatorMap<A extends ValidatorMap> = OptionalizeShape<{ [K in keyof A]: Infer<A[K]> }>;
408
430
  /**
409
431
  * A precompiled fast-path parser for one {@link ValidatorMap}. Returns the fully
410
432
  * built, validated record on a confident success, or the {@link DEFER_VALIDATION}
@@ -462,5 +484,4 @@ declare const installCompiledValidatorMap: (validators: object, compiled: Compil
462
484
  * which case the interpreted loop below runs and owns the result (and any error).
463
485
  */
464
486
  declare const parseValidatorMap: (validators: ValidatorMap, source: Record<string, unknown>, label: string) => Record<string, unknown>;
465
- declare const VERSION = "0.0.0";
466
- export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type Id, type Infer, type InferInsert, type InferSelect, type InferStandardOutput, type InferValidatorMap, type InsertShape, type JsonSchema, type JsonSchemaFragment, type MetaOptions, type SchemaNodeReader, type SelectShape, type ServerDefaultContext, type TimestampColumnValidator, VERSION, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
487
+ export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type Id, type Infer, type InferInsert, type InferSelect, type InferStandardOutput, type InferValidatorMap, type InsertShape, type JsonSchema, type JsonSchemaFragment, type MetaOptions, type SchemaNodeReader, type SelectShape, type ServerDefaultContext, type TimestampColumnValidator, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
package/dist/index.mjs CHANGED
@@ -1,9 +1,5 @@
1
- export { ValidationError, describeValue, formatPath } from './packem_shared/ValidationError-CdSwhYHu.mjs';
1
+ export { ValidationError, describeValue, formatPath } from './packem_shared/ValidationError-CoyFtkxj.mjs';
2
2
  export { jsonSchemaFromNode, objectSchemaFromNodes } from './packem_shared/jsonSchemaFromNode-weszUOQG.mjs';
3
3
  export { argsToJsonSchema, toJsonSchema } from './packem_shared/argsToJsonSchema-DdHmmamC.mjs';
4
- export { isOrWrapsFromValidator, optionalInner, v } from './packem_shared/isOrWrapsFromValidator-Bg1o5VFG.mjs';
5
- export { DEFER_VALIDATION, installCompiledValidatorMap, parseValidatorMap } from './packem_shared/DEFER_VALIDATION-Cpy5SwBo.mjs';
6
-
7
- const VERSION = "0.0.0";
8
-
9
- export { VERSION };
4
+ export { isOrWrapsFromValidator, optionalInner, v } from './packem_shared/isOrWrapsFromValidator-UlWeMhFL.mjs';
5
+ export { DEFER_VALIDATION, installCompiledValidatorMap, parseValidatorMap } from './packem_shared/DEFER_VALIDATION-CIKr17sW.mjs';
@@ -1,4 +1,4 @@
1
- import { ValidationError } from './ValidationError-CdSwhYHu.mjs';
1
+ import { ValidationError } from './ValidationError-CoyFtkxj.mjs';
2
2
 
3
3
  const DEFER_VALIDATION = /* @__PURE__ */ Symbol("lunora.deferValidation");
4
4
  const COMPILED_PARSERS = /* @__PURE__ */ new WeakMap();
@@ -19,7 +19,7 @@ const parseValidatorMap = (validators, source, label) => {
19
19
  if (!validator) {
20
20
  continue;
21
21
  }
22
- const candidate = source[key];
22
+ const candidate = Object.hasOwn(source, key) ? source[key] : void 0;
23
23
  if (candidate === void 0 && validator.kind === "optional") {
24
24
  continue;
25
25
  }
@@ -2,6 +2,18 @@ import { LunoraError } from '@lunora/errors';
2
2
 
3
3
  const MAX_DESCRIBED_LENGTH = 80;
4
4
  const truncate = (text) => text.length > MAX_DESCRIBED_LENGTH ? `${text.slice(0, MAX_DESCRIBED_LENGTH)}…` : text;
5
+ const describeObject = (value) => {
6
+ try {
7
+ const { constructor } = value;
8
+ const constructorName = constructor?.name;
9
+ if (constructorName !== void 0 && constructorName !== "Object") {
10
+ return `object ${constructorName}`;
11
+ }
12
+ } catch {
13
+ return "object";
14
+ }
15
+ return "object";
16
+ };
5
17
  class ValidationError extends LunoraError {
6
18
  path;
7
19
  expected;
@@ -13,7 +25,8 @@ class ValidationError extends LunoraError {
13
25
  this.received = options.received;
14
26
  }
15
27
  }
16
- const describeValue = (value) => {
28
+ const describeValue = (value, options) => {
29
+ const literal = options?.literal ?? true;
17
30
  if (value === null) {
18
31
  return "null";
19
32
  }
@@ -24,25 +37,16 @@ const describeValue = (value) => {
24
37
  return "ArrayBuffer";
25
38
  }
26
39
  if (typeof value === "string") {
27
- return `string ${truncate(JSON.stringify(value))}`;
40
+ return literal ? `string ${truncate(JSON.stringify(value))}` : "string";
28
41
  }
29
42
  if (typeof value === "number" || typeof value === "boolean") {
30
- return `${typeof value} ${String(value)}`;
43
+ return literal ? `${typeof value} ${String(value)}` : typeof value;
31
44
  }
32
45
  if (typeof value === "bigint") {
33
- return `bigint ${value.toString()}n`;
46
+ return literal ? `bigint ${value.toString()}n` : "bigint";
34
47
  }
35
48
  if (typeof value === "object") {
36
- try {
37
- const { constructor } = value;
38
- const constructorName = constructor?.name;
39
- if (constructorName !== void 0 && constructorName !== "Object") {
40
- return `object ${constructorName}`;
41
- }
42
- } catch {
43
- return "object";
44
- }
45
- return "object";
49
+ return describeObject(value);
46
50
  }
47
51
  return typeof value;
48
52
  };
@@ -1,9 +1,9 @@
1
1
  import { LunoraError } from '@lunora/errors';
2
- import { ValidationError, formatPath, describeValue } from './ValidationError-CdSwhYHu.mjs';
2
+ import { ValidationError, formatPath, describeValue } from './ValidationError-CoyFtkxj.mjs';
3
3
 
4
- function fail(context, expected, received) {
4
+ function fail(context, expected, received, options) {
5
5
  const path = [...context.path];
6
- const receivedDescription = describeValue(received);
6
+ const receivedDescription = describeValue(received, { literal: !options?.redactValue });
7
7
  throw new ValidationError(`Expected ${expected} at ${formatPath(path)}, received ${receivedDescription}`, {
8
8
  expected,
9
9
  path,
@@ -78,7 +78,7 @@ const createValidator = (kind, parser, meta) => {
78
78
  const refinedParser = (value, context) => {
79
79
  const parsed = parser(value, context);
80
80
  if (!predicate(parsed)) {
81
- fail(context, message ?? "value matching refinement", parsed);
81
+ fail(context, message ?? "value matching refinement", parsed, { redactValue: true });
82
82
  }
83
83
  return parsed;
84
84
  };
@@ -223,7 +223,7 @@ const objectValidator = (shape) => {
223
223
  const out = {};
224
224
  const { path } = context;
225
225
  for (const { child, isOptional, key } of entries) {
226
- const fieldValue = input[key];
226
+ const fieldValue = Object.hasOwn(input, key) ? input[key] : void 0;
227
227
  if (fieldValue === void 0 && isOptional) {
228
228
  continue;
229
229
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/values",
3
- "version": "1.0.0-alpha.6",
3
+ "version": "1.0.0-alpha.8",
4
4
  "description": "Validators for Lunora: the v.* validator suite with end-to-end return-type inference",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,7 +46,7 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/errors": "1.0.0-alpha.3"
49
+ "@lunora/errors": "1.0.0-alpha.5"
50
50
  },
51
51
  "engines": {
52
52
  "node": "^22.15.0 || >=24.11.0"