@atproto/lex-schema 0.0.12 → 0.0.13

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.
Files changed (199) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/core/schema.d.ts +4 -4
  3. package/dist/core/schema.d.ts.map +1 -1
  4. package/dist/core/schema.js +1 -1
  5. package/dist/core/schema.js.map +1 -1
  6. package/dist/core/validation-issue.js +3 -1
  7. package/dist/core/validation-issue.js.map +1 -1
  8. package/dist/core/validator.d.ts +10 -2
  9. package/dist/core/validator.d.ts.map +1 -1
  10. package/dist/core/validator.js +21 -3
  11. package/dist/core/validator.js.map +1 -1
  12. package/dist/helpers.d.ts +10 -11
  13. package/dist/helpers.d.ts.map +1 -1
  14. package/dist/helpers.js.map +1 -1
  15. package/dist/schema/array.d.ts +1 -0
  16. package/dist/schema/array.d.ts.map +1 -1
  17. package/dist/schema/array.js +2 -1
  18. package/dist/schema/array.js.map +1 -1
  19. package/dist/schema/blob.d.ts +4 -2
  20. package/dist/schema/blob.d.ts.map +1 -1
  21. package/dist/schema/blob.js +5 -2
  22. package/dist/schema/blob.js.map +1 -1
  23. package/dist/schema/boolean.d.ts +1 -0
  24. package/dist/schema/boolean.d.ts.map +1 -1
  25. package/dist/schema/boolean.js +2 -1
  26. package/dist/schema/boolean.js.map +1 -1
  27. package/dist/schema/bytes.d.ts +1 -0
  28. package/dist/schema/bytes.d.ts.map +1 -1
  29. package/dist/schema/bytes.js +2 -1
  30. package/dist/schema/bytes.js.map +1 -1
  31. package/dist/schema/cid.d.ts +1 -0
  32. package/dist/schema/cid.d.ts.map +1 -1
  33. package/dist/schema/cid.js +2 -1
  34. package/dist/schema/cid.js.map +1 -1
  35. package/dist/schema/custom.d.ts +1 -0
  36. package/dist/schema/custom.d.ts.map +1 -1
  37. package/dist/schema/custom.js +1 -0
  38. package/dist/schema/custom.js.map +1 -1
  39. package/dist/schema/dict.d.ts +1 -0
  40. package/dist/schema/dict.d.ts.map +1 -1
  41. package/dist/schema/dict.js +2 -1
  42. package/dist/schema/dict.js.map +1 -1
  43. package/dist/schema/discriminated-union.d.ts +1 -0
  44. package/dist/schema/discriminated-union.d.ts.map +1 -1
  45. package/dist/schema/discriminated-union.js +2 -1
  46. package/dist/schema/discriminated-union.js.map +1 -1
  47. package/dist/schema/enum.d.ts +1 -0
  48. package/dist/schema/enum.d.ts.map +1 -1
  49. package/dist/schema/enum.js +1 -0
  50. package/dist/schema/enum.js.map +1 -1
  51. package/dist/schema/integer.d.ts +1 -0
  52. package/dist/schema/integer.d.ts.map +1 -1
  53. package/dist/schema/integer.js +2 -1
  54. package/dist/schema/integer.js.map +1 -1
  55. package/dist/schema/intersection.d.ts +1 -0
  56. package/dist/schema/intersection.d.ts.map +1 -1
  57. package/dist/schema/intersection.js +1 -0
  58. package/dist/schema/intersection.js.map +1 -1
  59. package/dist/schema/lex-map.d.ts +37 -0
  60. package/dist/schema/lex-map.d.ts.map +1 -0
  61. package/dist/schema/lex-map.js +60 -0
  62. package/dist/schema/lex-map.js.map +1 -0
  63. package/dist/schema/lex-value.d.ts +35 -0
  64. package/dist/schema/lex-value.d.ts.map +1 -0
  65. package/dist/schema/lex-value.js +87 -0
  66. package/dist/schema/lex-value.js.map +1 -0
  67. package/dist/schema/literal.d.ts +1 -0
  68. package/dist/schema/literal.d.ts.map +1 -1
  69. package/dist/schema/literal.js +1 -0
  70. package/dist/schema/literal.js.map +1 -1
  71. package/dist/schema/never.d.ts +1 -0
  72. package/dist/schema/never.d.ts.map +1 -1
  73. package/dist/schema/never.js +2 -1
  74. package/dist/schema/never.js.map +1 -1
  75. package/dist/schema/null.d.ts +1 -0
  76. package/dist/schema/null.d.ts.map +1 -1
  77. package/dist/schema/null.js +2 -1
  78. package/dist/schema/null.js.map +1 -1
  79. package/dist/schema/nullable.d.ts +1 -0
  80. package/dist/schema/nullable.d.ts.map +1 -1
  81. package/dist/schema/nullable.js +1 -0
  82. package/dist/schema/nullable.js.map +1 -1
  83. package/dist/schema/object.d.ts +1 -0
  84. package/dist/schema/object.d.ts.map +1 -1
  85. package/dist/schema/object.js +2 -1
  86. package/dist/schema/object.js.map +1 -1
  87. package/dist/schema/optional.d.ts +1 -0
  88. package/dist/schema/optional.d.ts.map +1 -1
  89. package/dist/schema/optional.js +1 -0
  90. package/dist/schema/optional.js.map +1 -1
  91. package/dist/schema/params.d.ts +14 -10
  92. package/dist/schema/params.d.ts.map +1 -1
  93. package/dist/schema/params.js +84 -24
  94. package/dist/schema/params.js.map +1 -1
  95. package/dist/schema/payload.d.ts.map +1 -1
  96. package/dist/schema/payload.js +3 -3
  97. package/dist/schema/payload.js.map +1 -1
  98. package/dist/schema/record.d.ts +13 -17
  99. package/dist/schema/record.d.ts.map +1 -1
  100. package/dist/schema/record.js +1 -0
  101. package/dist/schema/record.js.map +1 -1
  102. package/dist/schema/ref.d.ts +1 -0
  103. package/dist/schema/ref.d.ts.map +1 -1
  104. package/dist/schema/ref.js +1 -0
  105. package/dist/schema/ref.js.map +1 -1
  106. package/dist/schema/regexp.d.ts +1 -0
  107. package/dist/schema/regexp.d.ts.map +1 -1
  108. package/dist/schema/regexp.js +2 -1
  109. package/dist/schema/regexp.js.map +1 -1
  110. package/dist/schema/string.d.ts +22 -6
  111. package/dist/schema/string.d.ts.map +1 -1
  112. package/dist/schema/string.js +16 -9
  113. package/dist/schema/string.js.map +1 -1
  114. package/dist/schema/token.d.ts +1 -0
  115. package/dist/schema/token.d.ts.map +1 -1
  116. package/dist/schema/token.js +2 -1
  117. package/dist/schema/token.js.map +1 -1
  118. package/dist/schema/typed-object.d.ts +11 -15
  119. package/dist/schema/typed-object.d.ts.map +1 -1
  120. package/dist/schema/typed-object.js +2 -1
  121. package/dist/schema/typed-object.js.map +1 -1
  122. package/dist/schema/typed-ref.d.ts +1 -0
  123. package/dist/schema/typed-ref.d.ts.map +1 -1
  124. package/dist/schema/typed-ref.js +1 -0
  125. package/dist/schema/typed-ref.js.map +1 -1
  126. package/dist/schema/typed-union.d.ts +1 -0
  127. package/dist/schema/typed-union.d.ts.map +1 -1
  128. package/dist/schema/typed-union.js +2 -1
  129. package/dist/schema/typed-union.js.map +1 -1
  130. package/dist/schema/union.d.ts +1 -0
  131. package/dist/schema/union.d.ts.map +1 -1
  132. package/dist/schema/union.js +1 -0
  133. package/dist/schema/union.js.map +1 -1
  134. package/dist/schema/unknown.d.ts +1 -0
  135. package/dist/schema/unknown.d.ts.map +1 -1
  136. package/dist/schema/unknown.js +1 -0
  137. package/dist/schema/unknown.js.map +1 -1
  138. package/dist/schema/with-default.d.ts +1 -0
  139. package/dist/schema/with-default.d.ts.map +1 -1
  140. package/dist/schema/with-default.js +1 -0
  141. package/dist/schema/with-default.js.map +1 -1
  142. package/dist/schema.d.ts +2 -1
  143. package/dist/schema.d.ts.map +1 -1
  144. package/dist/schema.js +2 -1
  145. package/dist/schema.js.map +1 -1
  146. package/dist/util/if-any.d.ts +2 -0
  147. package/dist/util/if-any.d.ts.map +1 -0
  148. package/dist/util/if-any.js +3 -0
  149. package/dist/util/if-any.js.map +1 -0
  150. package/package.json +2 -2
  151. package/src/core/schema.ts +9 -3
  152. package/src/core/validation-issue.ts +3 -2
  153. package/src/core/validator.ts +23 -3
  154. package/src/helpers.test.ts +1 -1
  155. package/src/helpers.ts +53 -19
  156. package/src/schema/array.ts +3 -1
  157. package/src/schema/blob.ts +4 -1
  158. package/src/schema/boolean.ts +3 -1
  159. package/src/schema/bytes.ts +3 -1
  160. package/src/schema/cid.ts +3 -1
  161. package/src/schema/custom.ts +2 -0
  162. package/src/schema/dict.ts +3 -1
  163. package/src/schema/discriminated-union.ts +3 -1
  164. package/src/schema/enum.ts +2 -0
  165. package/src/schema/integer.ts +3 -1
  166. package/src/schema/intersection.ts +2 -0
  167. package/src/schema/{unknown-object.test.ts → lex-map.test.ts} +9 -9
  168. package/src/schema/lex-map.ts +63 -0
  169. package/src/schema/lex-value.test.ts +81 -0
  170. package/src/schema/lex-value.ts +86 -0
  171. package/src/schema/literal.ts +2 -0
  172. package/src/schema/never.ts +3 -1
  173. package/src/schema/null.ts +3 -1
  174. package/src/schema/nullable.ts +2 -0
  175. package/src/schema/object.ts +3 -1
  176. package/src/schema/optional.ts +2 -0
  177. package/src/schema/params.test.ts +82 -43
  178. package/src/schema/params.ts +133 -39
  179. package/src/schema/payload.test.ts +2 -2
  180. package/src/schema/payload.ts +3 -4
  181. package/src/schema/record.ts +19 -8
  182. package/src/schema/ref.ts +2 -0
  183. package/src/schema/regexp.ts +3 -1
  184. package/src/schema/string.test.ts +99 -2
  185. package/src/schema/string.ts +58 -15
  186. package/src/schema/token.ts +3 -1
  187. package/src/schema/typed-object.ts +19 -8
  188. package/src/schema/typed-ref.ts +2 -0
  189. package/src/schema/typed-union.ts +3 -1
  190. package/src/schema/union.ts +2 -0
  191. package/src/schema/unknown.ts +2 -0
  192. package/src/schema/with-default.ts +2 -0
  193. package/src/schema.ts +2 -1
  194. package/src/util/if-any.ts +3 -0
  195. package/dist/schema/unknown-object.d.ts +0 -42
  196. package/dist/schema/unknown-object.d.ts.map +0 -1
  197. package/dist/schema/unknown-object.js +0 -50
  198. package/dist/schema/unknown-object.js.map +0 -1
  199. package/src/schema/unknown-object.ts +0 -53
@@ -21,6 +21,7 @@ const memoize_js_1 = require("../util/memoize.js");
21
21
  */
22
22
  class OptionalSchema extends core_js_1.Schema {
23
23
  validator;
24
+ type = 'optional';
24
25
  constructor(validator) {
25
26
  super();
26
27
  this.validator = validator;
@@ -1 +1 @@
1
- {"version":3,"file":"optional.js","sourceRoot":"","sources":["../../src/schema/optional.ts"],"names":[],"mappings":";;;AAAA,wCAOmB;AACnB,mDAAwD;AAGxD;;;;;;;;;;;;;;;GAeG;AACH,MAAa,cAA6C,SAAQ,gBAKjE;IACsB;IAArB,YAAqB,SAAqB;QACxC,KAAK,EAAE,CAAA;QADY,cAAS,GAAT,SAAS,CAAY;IAE1C,CAAC;IAED,iBAAiB,CAAC,KAAc,EAAE,GAAsB;QACtD,0EAA0E;QAC1E,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3D,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;QAED,0EAA0E;QAC1E,8BAA8B;QAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QAElD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,MAAM,CAAA;QACf,CAAC;QAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AA9BD,wCA8BC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACU,QAAA,QAAQ,GAAiB,IAAA,gCAAmB,EAAC,UAExD,SAAqB;IACrB,OAAO,IAAI,cAAc,CAAa,SAAS,CAAC,CAAA;AAClD,CAAC,CAAC,CAAA","sourcesContent":["import {\n InferInput,\n InferOutput,\n Schema,\n UnwrapValidator,\n ValidationContext,\n Validator,\n} from '../core.js'\nimport { memoizedTransformer } from '../util/memoize.js'\nimport { WithDefaultSchema } from './with-default.js'\n\n/**\n * Schema wrapper that makes a value optional (allows undefined).\n *\n * When the input is `undefined`, validation succeeds without running the\n * inner validator. If the inner validator has a default value (via `withDefault`),\n * that default will be applied in parse mode.\n *\n * @template TValidator - The wrapped validator type\n *\n * @example\n * ```ts\n * const schema = new OptionalSchema(l.string())\n * schema.validate(undefined) // success\n * schema.validate('hello') // success\n * ```\n */\nexport class OptionalSchema<TValidator extends Validator> extends Schema<\n InferInput<TValidator> | undefined,\n UnwrapValidator<TValidator> extends WithDefaultSchema<infer TValidator>\n ? InferOutput<TValidator>\n : InferOutput<TValidator> | undefined\n> {\n constructor(readonly validator: TValidator) {\n super()\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n // Optimization: No need to apply child schema defaults in validation mode\n if (input === undefined && ctx.options.mode === 'validate') {\n return ctx.success(input)\n }\n\n // @NOTE The inner schema might apply a default value so we need to run it\n // even if input is undefined.\n const result = ctx.validate(input, this.validator)\n\n if (result.success) {\n return result\n }\n\n if (input === undefined) {\n return ctx.success(input)\n }\n\n return result\n }\n}\n\n/**\n * Creates an optional schema that allows undefined values.\n *\n * Wraps another schema to make it optional. When used in an object schema,\n * properties with optional schemas are not required.\n *\n * @param validator - The validator to make optional\n * @returns A new {@link OptionalSchema} instance\n *\n * @example\n * ```ts\n * // Optional string\n * const optionalBio = l.optional(l.string())\n *\n * // In an object - property is not required\n * const userSchema = l.object({\n * name: l.string(),\n * bio: l.optional(l.string()),\n * })\n * userSchema.parse({ name: 'Alice' }) // Valid, bio is undefined\n *\n * // With default value\n * const countSchema = l.optional(l.withDefault(l.integer(), 0))\n * countSchema.parse(undefined) // Returns 0\n * ```\n */\nexport const optional = /*#__PURE__*/ memoizedTransformer(function <\n const TValidator extends Validator,\n>(validator: TValidator) {\n return new OptionalSchema<TValidator>(validator)\n})\n"]}
1
+ {"version":3,"file":"optional.js","sourceRoot":"","sources":["../../src/schema/optional.ts"],"names":[],"mappings":";;;AAAA,wCAOmB;AACnB,mDAAwD;AAGxD;;;;;;;;;;;;;;;GAeG;AACH,MAAa,cAA6C,SAAQ,gBAKjE;IAGsB;IAFZ,IAAI,GAAG,UAAmB,CAAA;IAEnC,YAAqB,SAAqB;QACxC,KAAK,EAAE,CAAA;QADY,cAAS,GAAT,SAAS,CAAY;IAE1C,CAAC;IAED,iBAAiB,CAAC,KAAc,EAAE,GAAsB;QACtD,0EAA0E;QAC1E,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3D,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;QAED,0EAA0E;QAC1E,8BAA8B;QAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QAElD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,MAAM,CAAA;QACf,CAAC;QAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAhCD,wCAgCC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACU,QAAA,QAAQ,GAAiB,IAAA,gCAAmB,EAAC,UAExD,SAAqB;IACrB,OAAO,IAAI,cAAc,CAAa,SAAS,CAAC,CAAA;AAClD,CAAC,CAAC,CAAA","sourcesContent":["import {\n InferInput,\n InferOutput,\n Schema,\n UnwrapValidator,\n ValidationContext,\n Validator,\n} from '../core.js'\nimport { memoizedTransformer } from '../util/memoize.js'\nimport { WithDefaultSchema } from './with-default.js'\n\n/**\n * Schema wrapper that makes a value optional (allows undefined).\n *\n * When the input is `undefined`, validation succeeds without running the\n * inner validator. If the inner validator has a default value (via `withDefault`),\n * that default will be applied in parse mode.\n *\n * @template TValidator - The wrapped validator type\n *\n * @example\n * ```ts\n * const schema = new OptionalSchema(l.string())\n * schema.validate(undefined) // success\n * schema.validate('hello') // success\n * ```\n */\nexport class OptionalSchema<TValidator extends Validator> extends Schema<\n InferInput<TValidator> | undefined,\n UnwrapValidator<TValidator> extends WithDefaultSchema<infer TValidator>\n ? InferOutput<TValidator>\n : InferOutput<TValidator> | undefined\n> {\n readonly type = 'optional' as const\n\n constructor(readonly validator: TValidator) {\n super()\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n // Optimization: No need to apply child schema defaults in validation mode\n if (input === undefined && ctx.options.mode === 'validate') {\n return ctx.success(input)\n }\n\n // @NOTE The inner schema might apply a default value so we need to run it\n // even if input is undefined.\n const result = ctx.validate(input, this.validator)\n\n if (result.success) {\n return result\n }\n\n if (input === undefined) {\n return ctx.success(input)\n }\n\n return result\n }\n}\n\n/**\n * Creates an optional schema that allows undefined values.\n *\n * Wraps another schema to make it optional. When used in an object schema,\n * properties with optional schemas are not required.\n *\n * @param validator - The validator to make optional\n * @returns A new {@link OptionalSchema} instance\n *\n * @example\n * ```ts\n * // Optional string\n * const optionalBio = l.optional(l.string())\n *\n * // In an object - property is not required\n * const userSchema = l.object({\n * name: l.string(),\n * bio: l.optional(l.string()),\n * })\n * userSchema.parse({ name: 'Alice' }) // Valid, bio is undefined\n *\n * // With default value\n * const countSchema = l.optional(l.withDefault(l.integer(), 0))\n * countSchema.parse(undefined) // Returns 0\n * ```\n */\nexport const optional = /*#__PURE__*/ memoizedTransformer(function <\n const TValidator extends Validator,\n>(validator: TValidator) {\n return new OptionalSchema<TValidator>(validator)\n})\n"]}
@@ -1,7 +1,9 @@
1
- import { Infer, InferInput, InferOutput, Schema, ValidationContext, WithOptionalProperties } from '../core.js';
1
+ import { Infer, InferInput, InferOutput, ParseOptions, Schema, ValidationContext, Validator, WithOptionalProperties } from '../core.js';
2
2
  import { ArraySchema } from './array.js';
3
3
  import { BooleanSchema } from './boolean.js';
4
+ import { EnumSchema } from './enum.js';
4
5
  import { IntegerSchema } from './integer.js';
6
+ import { LiteralSchema } from './literal.js';
5
7
  import { OptionalSchema } from './optional.js';
6
8
  import { StringSchema } from './string.js';
7
9
  import { WithDefaultSchema } from './with-default.js';
@@ -17,7 +19,7 @@ export type Param = Infer<typeof paramSchema>;
17
19
  /**
18
20
  * Schema for validating individual parameter values.
19
21
  */
20
- export declare const paramSchema: import("./union.js").UnionSchema<readonly [import("./union.js").UnionSchema<readonly [BooleanSchema, IntegerSchema, StringSchema<{}>]>, ArraySchema<import("./union.js").UnionSchema<readonly [BooleanSchema, IntegerSchema, StringSchema<{}>]>>]>;
22
+ export declare const paramSchema: import("./union.js").UnionSchema<readonly [import("./union.js").UnionSchema<readonly [BooleanSchema, IntegerSchema, StringSchema<{}>]>, ArraySchema<BooleanSchema>, ArraySchema<IntegerSchema>, ArraySchema<StringSchema<{}>>]>;
21
23
  /**
22
24
  * Type for a params object with string keys and optional param values.
23
25
  */
@@ -25,16 +27,17 @@ export type Params = Infer<typeof paramsSchema>;
25
27
  /**
26
28
  * Schema for validating arbitrary params objects.
27
29
  */
28
- export declare const paramsSchema: import("./dict.js").DictSchema<StringSchema<{}>, OptionalSchema<import("./union.js").UnionSchema<readonly [import("./union.js").UnionSchema<readonly [BooleanSchema, IntegerSchema, StringSchema<{}>]>, ArraySchema<import("./union.js").UnionSchema<readonly [BooleanSchema, IntegerSchema, StringSchema<{}>]>>]>>>;
29
- type ParamScalarValidator = StringSchema | BooleanSchema | IntegerSchema;
30
- type ParamValueValidator = ParamScalarValidator | ArraySchema<ParamScalarValidator>;
31
- type ParamValidator = ParamValueValidator | OptionalSchema<ParamValueValidator> | OptionalSchema<WithDefaultSchema<ParamValueValidator>> | WithDefaultSchema<ParamValueValidator>;
30
+ export declare const paramsSchema: import("./dict.js").DictSchema<StringSchema<{}>, OptionalSchema<import("./union.js").UnionSchema<readonly [import("./union.js").UnionSchema<readonly [BooleanSchema, IntegerSchema, StringSchema<{}>]>, ArraySchema<BooleanSchema>, ArraySchema<IntegerSchema>, ArraySchema<StringSchema<{}>>]>>>;
31
+ export type ParamScalarValidator = LiteralSchema<string> | LiteralSchema<number> | LiteralSchema<boolean> | EnumSchema<string> | EnumSchema<number> | StringSchema<any> | BooleanSchema | IntegerSchema;
32
+ type AsArrayParamSchema<TSchema extends Validator> = TSchema extends any ? ArraySchema<TSchema> : never;
33
+ export type ParamValueValidator = ParamScalarValidator | AsArrayParamSchema<ParamScalarValidator>;
34
+ export type ParamValidator = ParamValueValidator | OptionalSchema<ParamValueValidator> | OptionalSchema<WithDefaultSchema<ParamValueValidator>> | WithDefaultSchema<ParamValueValidator>;
32
35
  /**
33
36
  * Type representing the shape of a params schema definition.
34
37
  *
35
38
  * Maps parameter names to their validators (must be Param or undefined).
36
39
  */
37
- export type ParamsSchemaShape = {
40
+ export type ParamsShape = {
38
41
  [x: string]: ParamValidator;
39
42
  };
40
43
  /**
@@ -56,16 +59,17 @@ export type ParamsSchemaShape = {
56
59
  * })
57
60
  * ```
58
61
  */
59
- export declare class ParamsSchema<const TShape extends ParamsSchemaShape = ParamsSchemaShape> extends Schema<WithOptionalProperties<{
62
+ export declare class ParamsSchema<const TShape extends ParamsShape = ParamsShape> extends Schema<WithOptionalProperties<{
60
63
  [K in keyof TShape]: InferInput<TShape[K]>;
61
64
  }>, WithOptionalProperties<{
62
65
  [K in keyof TShape]: InferOutput<TShape[K]>;
63
66
  }>> {
64
67
  readonly shape: TShape;
68
+ readonly type: "params";
65
69
  constructor(shape: TShape);
66
70
  get shapeValidators(): Map<string, ParamValidator>;
67
71
  validateInContext(input: unknown, ctx: ValidationContext): import("../core.js").ValidationResult<Record<string, unknown>>;
68
- fromURLSearchParams(iterable: Iterable<[string, string]>): InferOutput<this>;
72
+ fromURLSearchParams(input: string | Iterable<[string, string]>, options?: ParseOptions): InferOutput<this>;
69
73
  toURLSearchParams(input: InferInput<this>): URLSearchParams;
70
74
  }
71
75
  /**
@@ -103,6 +107,6 @@ export declare class ParamsSchema<const TShape extends ParamsSchemaShape = Param
103
107
  * const searchParams = paginationParams.toURLSearchParams({ limit: 25 })
104
108
  * ```
105
109
  */
106
- export declare const params: <const TShape extends ParamsSchemaShape = {}>(properties?: TShape) => ParamsSchema<TShape>;
110
+ export declare const params: <const TShape extends ParamsShape = {}>(properties?: TShape) => ParamsSchema<TShape>;
107
111
  export {};
108
112
  //# sourceMappingURL=params.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../../src/schema/params.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EACL,UAAU,EACV,WAAW,EACX,MAAM,EACN,iBAAiB,EAEjB,sBAAsB,EACvB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,WAAW,EAAS,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAW,MAAM,cAAc,CAAA;AAErD,OAAO,EAAE,aAAa,EAAW,MAAM,cAAc,CAAA;AACrD,OAAO,EAAE,cAAc,EAAY,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,YAAY,EAAU,MAAM,aAAa,CAAA;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AACzD,QAAA,MAAM,iBAAiB,6FAA0C,CAAA;AAEjE;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,WAAW,oPAAuD,CAAA;AAE/E;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE/C;;GAEG;AACH,eAAO,MAAM,YAAY,sTAAwC,CAAA;AAKjE,KAAK,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,CAAA;AACxE,KAAK,mBAAmB,GACpB,oBAAoB,GACpB,WAAW,CAAC,oBAAoB,CAAC,CAAA;AACrC,KAAK,cAAc,GACf,mBAAmB,GACnB,cAAc,CAAC,mBAAmB,CAAC,GACnC,cAAc,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,GACtD,iBAAiB,CAAC,mBAAmB,CAAC,CAAA;AAE1C;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,CAAC,EAAE,MAAM,GAAG,cAAc,CAAA;CAC5B,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,YAAY,CACvB,KAAK,CAAC,MAAM,SAAS,iBAAiB,GAAG,iBAAiB,CAC1D,SAAQ,MAAM,CACd,sBAAsB,CAAC;KACpB,CAAC,IAAI,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CAC3C,CAAC,EACF,sBAAsB,CAAC;KACpB,CAAC,IAAI,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CAC5C,CAAC,CACH;IACa,QAAQ,CAAC,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;IAIlC,IAAI,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAIjD;IAED,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB;IAyDxD,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC;IAsC5E,iBAAiB,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,eAAe;CAmB5D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,MAAM,SACX,MAAM,SAAS,iBAAiB,oBAC1B,MAAM,yBAElB,CAAA"}
1
+ {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../../src/schema/params.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,9 @@ const memoize_js_1 = require("../util/memoize.js");
8
8
  const array_js_1 = require("./array.js");
9
9
  const boolean_js_1 = require("./boolean.js");
10
10
  const dict_js_1 = require("./dict.js");
11
+ const enum_js_1 = require("./enum.js");
11
12
  const integer_js_1 = require("./integer.js");
13
+ const literal_js_1 = require("./literal.js");
12
14
  const optional_js_1 = require("./optional.js");
13
15
  const string_js_1 = require("./string.js");
14
16
  const union_js_1 = require("./union.js");
@@ -17,7 +19,12 @@ const paramScalarSchema = (0, union_js_1.union)([(0, boolean_js_1.boolean)(), (0
17
19
  /**
18
20
  * Schema for validating individual parameter values.
19
21
  */
20
- exports.paramSchema = (0, union_js_1.union)([paramScalarSchema, (0, array_js_1.array)(paramScalarSchema)]);
22
+ exports.paramSchema = (0, union_js_1.union)([
23
+ paramScalarSchema,
24
+ (0, array_js_1.array)((0, boolean_js_1.boolean)()),
25
+ (0, array_js_1.array)((0, integer_js_1.integer)()),
26
+ (0, array_js_1.array)((0, string_js_1.string)()),
27
+ ]);
21
28
  /**
22
29
  * Schema for validating arbitrary params objects.
23
30
  */
@@ -43,6 +50,7 @@ exports.paramsSchema = (0, dict_js_1.dict)((0, string_js_1.string)(), (0, option
43
50
  */
44
51
  class ParamsSchema extends core_js_1.Schema {
45
52
  shape;
53
+ type = 'params';
46
54
  constructor(shape) {
47
55
  super();
48
56
  this.shape = shape;
@@ -53,7 +61,7 @@ class ParamsSchema extends core_js_1.Schema {
53
61
  }
54
62
  validateInContext(input, ctx) {
55
63
  if (!(0, lex_data_1.isPlainObject)(input)) {
56
- return ctx.issueInvalidType(input, 'object');
64
+ return ctx.issueUnexpectedType(input, 'object');
57
65
  }
58
66
  // Lazily copy value
59
67
  let copy;
@@ -98,37 +106,30 @@ class ParamsSchema extends core_js_1.Schema {
98
106
  }
99
107
  return ctx.success(copy ?? input);
100
108
  }
101
- fromURLSearchParams(iterable) {
109
+ fromURLSearchParams(input, options) {
102
110
  const params = {};
103
- // Compatibility with URLSearchParams not being iterable in some environments
111
+ const iterable = typeof input === 'string' ? new URLSearchParams(input) : input;
104
112
  const entries = iterable instanceof URLSearchParams ? iterable.entries() : iterable;
105
- for (const [key, value] of entries) {
106
- const validator = unwrapValidator(this.shapeValidators.get(key));
107
- const expectsArray = validator instanceof array_js_1.ArraySchema;
113
+ for (const [name, value] of entries) {
114
+ const validator = this.shapeValidators.get(name);
115
+ const innerValidator = validator ? unwrapSchema(validator) : undefined;
116
+ const expectsArray = innerValidator instanceof array_js_1.ArraySchema;
108
117
  const scalarValidator = expectsArray
109
- ? unwrapValidator(validator.validator)
110
- : validator;
111
- const coerced = scalarValidator instanceof string_js_1.StringSchema
112
- ? value
113
- : value === 'true'
114
- ? true
115
- : value === 'false'
116
- ? false
117
- : /^-?\d+$/.test(value)
118
- ? Number(value)
119
- : value;
120
- const currentParam = params[key];
118
+ ? unwrapSchema(innerValidator.validator)
119
+ : innerValidator;
120
+ const coerced = coerceParam(name, value, scalarValidator, options);
121
+ const currentParam = params[name];
121
122
  if (currentParam === undefined) {
122
- params[key] = expectsArray ? [coerced] : coerced;
123
+ params[name] = expectsArray ? [coerced] : coerced;
123
124
  }
124
125
  else if (Array.isArray(currentParam)) {
125
126
  currentParam.push(coerced);
126
127
  }
127
128
  else {
128
- params[key] = [currentParam, coerced];
129
+ params[name] = [currentParam, coerced];
129
130
  }
130
131
  }
131
- return this.parse(params);
132
+ return this.parse(params, options);
132
133
  }
133
134
  toURLSearchParams(input) {
134
135
  const urlSearchParams = new URLSearchParams();
@@ -149,6 +150,65 @@ class ParamsSchema extends core_js_1.Schema {
149
150
  }
150
151
  }
151
152
  exports.ParamsSchema = ParamsSchema;
153
+ function coerceParam(name, param, schema, options) {
154
+ let issue;
155
+ if (!schema) {
156
+ // The param is unknown (not defined in schema), so we don't apply any
157
+ // coercion and just return the string value.
158
+ return param;
159
+ }
160
+ else if (schema instanceof string_js_1.StringSchema) {
161
+ return param;
162
+ }
163
+ else if (schema instanceof integer_js_1.IntegerSchema) {
164
+ if (/^-?\d+$/.test(param))
165
+ return Number(param);
166
+ issue = new core_js_1.IssueInvalidType(paramPath(name, options), param, ['integer']);
167
+ }
168
+ else if (schema instanceof boolean_js_1.BooleanSchema) {
169
+ if (param === 'true')
170
+ return true;
171
+ if (param === 'false')
172
+ return false;
173
+ issue = new core_js_1.IssueInvalidType(paramPath(name, options), param, ['boolean']);
174
+ }
175
+ else if (schema instanceof literal_js_1.LiteralSchema) {
176
+ const { value } = schema;
177
+ if (String(value) === param)
178
+ return value;
179
+ issue = new core_js_1.IssueInvalidValue(paramPath(name, options), param, [value]);
180
+ }
181
+ else if (schema instanceof enum_js_1.EnumSchema) {
182
+ const { values } = schema;
183
+ for (const value of values) {
184
+ if (String(value) === param)
185
+ return value;
186
+ }
187
+ issue = new core_js_1.IssueInvalidValue(paramPath(name, options), param, values);
188
+ }
189
+ else {
190
+ // This should never happen. If it *does*, it means that the user of
191
+ // lex-schema is mixing different versions of the lib, which is not
192
+ // supported. Throwing an error here is better than silently accepting
193
+ // invalid params and causing unexpected behavior down the line (ie. error
194
+ // message returning the string value instead of the expected
195
+ // boolean/number/string value).
196
+ throw new Error(`Unsupported schema type for param coercion: ${schema}`);
197
+ }
198
+ // We were not able to coerce the param to the expected type. There is no
199
+ // point in returning the original string value since it doesn't conform to
200
+ // the expected schema, so we throw a validation error instead. We could
201
+ // return the "param" here, which would cause the validation to fail later on
202
+ // (see fromURLSearchParams()'s return statement). The main benefit of
203
+ // returning the original "param" value is that the error path would include
204
+ // the index of the param in case of array params (e.g. "tags[1]"), which
205
+ // could be helpful for debugging. The cost overhead is not worth it though
206
+ // (IMO).
207
+ throw new core_js_1.ValidationError([issue]);
208
+ }
209
+ function paramPath(key, options) {
210
+ return options?.path ? [...options.path, key] : [key];
211
+ }
152
212
  /**
153
213
  * Creates a params schema for URL query parameters.
154
214
  *
@@ -187,10 +247,10 @@ exports.ParamsSchema = ParamsSchema;
187
247
  exports.params = (0, memoize_js_1.memoizedOptions)(function params(properties = {}) {
188
248
  return new ParamsSchema(properties);
189
249
  });
190
- function unwrapValidator(schema) {
250
+ function unwrapSchema(schema) {
191
251
  while (schema instanceof optional_js_1.OptionalSchema ||
192
252
  schema instanceof with_default_js_1.WithDefaultSchema) {
193
- schema = schema.validator;
253
+ return unwrapSchema(schema.validator);
194
254
  }
195
255
  return schema;
196
256
  }
@@ -1 +1 @@
1
- {"version":3,"file":"params.js","sourceRoot":"","sources":["../../src/schema/params.ts"],"names":[],"mappings":"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","sourcesContent":["import { isPlainObject } from '@atproto/lex-data'\nimport {\n Infer,\n InferInput,\n InferOutput,\n Schema,\n ValidationContext,\n Validator,\n WithOptionalProperties,\n} from '../core.js'\nimport { lazyProperty } from '../util/lazy-property.js'\nimport { memoizedOptions } from '../util/memoize.js'\nimport { ArraySchema, array } from './array.js'\nimport { BooleanSchema, boolean } from './boolean.js'\nimport { dict } from './dict.js'\nimport { IntegerSchema, integer } from './integer.js'\nimport { OptionalSchema, optional } from './optional.js'\nimport { StringSchema, string } from './string.js'\nimport { union } from './union.js'\nimport { WithDefaultSchema } from './with-default.js'\n\n/**\n * Scalar types allowed in URL parameters: boolean, integer, or string.\n */\nexport type ParamScalar = Infer<typeof paramScalarSchema>\nconst paramScalarSchema = union([boolean(), integer(), string()])\n\n/**\n * A single parameter value: scalar or array of scalars.\n */\nexport type Param = Infer<typeof paramSchema>\n\n/**\n * Schema for validating individual parameter values.\n */\nexport const paramSchema = union([paramScalarSchema, array(paramScalarSchema)])\n\n/**\n * Type for a params object with string keys and optional param values.\n */\nexport type Params = Infer<typeof paramsSchema>\n\n/**\n * Schema for validating arbitrary params objects.\n */\nexport const paramsSchema = dict(string(), optional(paramSchema))\n\n// @NOTE In order to properly coerce URLSearchParams, we need to distinguish\n// between scalar and array validators, requiring to be able to detect which\n// schema types are being used, restricting the allowed param validators here.\ntype ParamScalarValidator = StringSchema | BooleanSchema | IntegerSchema\ntype ParamValueValidator =\n | ParamScalarValidator\n | ArraySchema<ParamScalarValidator>\ntype ParamValidator =\n | ParamValueValidator\n | OptionalSchema<ParamValueValidator>\n | OptionalSchema<WithDefaultSchema<ParamValueValidator>>\n | WithDefaultSchema<ParamValueValidator>\n\n/**\n * Type representing the shape of a params schema definition.\n *\n * Maps parameter names to their validators (must be Param or undefined).\n */\nexport type ParamsSchemaShape = {\n [x: string]: ParamValidator\n}\n\n/**\n * Schema for validating URL query parameters in Lexicon endpoints.\n *\n * Params are the query string parameters passed to queries, procedures,\n * and subscriptions. Values must be scalars (boolean, integer, string)\n * or arrays of scalars, as they need to be serializable to URL format.\n *\n * Provides methods for converting to/from URLSearchParams.\n *\n * @template TShape - The params shape type mapping names to validators\n *\n * @example\n * ```ts\n * const schema = new ParamsSchema({\n * limit: l.optional(l.integer({ minimum: 1, maximum: 100 })),\n * cursor: l.optional(l.string()),\n * })\n * ```\n */\nexport class ParamsSchema<\n const TShape extends ParamsSchemaShape = ParamsSchemaShape,\n> extends Schema<\n WithOptionalProperties<{\n [K in keyof TShape]: InferInput<TShape[K]>\n }>,\n WithOptionalProperties<{\n [K in keyof TShape]: InferOutput<TShape[K]>\n }>\n> {\n constructor(readonly shape: TShape) {\n super()\n }\n\n get shapeValidators(): Map<string, ParamValidator> {\n const map = new Map(Object.entries(this.shape))\n\n return lazyProperty(this, 'shapeValidators', map)\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n if (!isPlainObject(input)) {\n return ctx.issueInvalidType(input, 'object')\n }\n\n // Lazily copy value\n let copy: undefined | Record<string, unknown>\n\n // Ensure that non-specified params conform to param schema\n for (const key in input) {\n if (this.shapeValidators.has(key)) continue\n\n const result = ctx.validateChild(input, key, paramSchema)\n if (!result.success) return result\n\n if (result.value !== input[key]) {\n if (ctx.options.mode === 'validate') {\n // In \"validate\" mode, we can't modify the input, so we issue an error\n return ctx.issueInvalidPropertyValue(input, key, [result.value])\n }\n\n copy ??= { ...input }\n copy[key] = result.value\n }\n }\n\n for (const [key, propDef] of this.shapeValidators) {\n const result = ctx.validateChild(input, key, propDef)\n if (!result.success) {\n if (!(key in input)) {\n // Transform into \"required key\" issue\n return ctx.issueRequiredKey(input, key)\n }\n\n return result\n }\n\n // Skip copying if key is not present in input (and value is undefined)\n if (result.value === undefined && !(key in input)) {\n continue\n }\n\n if (!Object.is(result.value, input[key])) {\n if (ctx.options.mode === 'validate') {\n // In \"validate\" mode, we can't modify the input, so we issue an error\n return ctx.issueInvalidPropertyValue(input, key, [result.value])\n }\n\n // Copy on write\n copy ??= { ...input }\n copy[key] = result.value\n }\n }\n\n return ctx.success(copy ?? input)\n }\n\n fromURLSearchParams(iterable: Iterable<[string, string]>): InferOutput<this> {\n const params: Record<string, Param> = {}\n\n // Compatibility with URLSearchParams not being iterable in some environments\n const entries =\n iterable instanceof URLSearchParams ? iterable.entries() : iterable\n\n for (const [key, value] of entries) {\n const validator = unwrapValidator(this.shapeValidators.get(key))\n const expectsArray = validator instanceof ArraySchema\n const scalarValidator = expectsArray\n ? unwrapValidator(validator.validator)\n : validator\n\n const coerced: ParamScalar =\n scalarValidator instanceof StringSchema\n ? value\n : value === 'true'\n ? true\n : value === 'false'\n ? false\n : /^-?\\d+$/.test(value)\n ? Number(value)\n : value\n\n const currentParam = params[key]\n if (currentParam === undefined) {\n params[key] = expectsArray ? [coerced] : coerced\n } else if (Array.isArray(currentParam)) {\n currentParam.push(coerced)\n } else {\n params[key] = [currentParam, coerced]\n }\n }\n\n return this.parse(params)\n }\n\n toURLSearchParams(input: InferInput<this>): URLSearchParams {\n const urlSearchParams = new URLSearchParams()\n\n // @NOTE We apply defaults here to ensure that server with different\n // defaults still receive all expected parameters.\n const params = this.parse(input)\n\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n urlSearchParams.append(key, String(v))\n }\n } else if (value !== undefined) {\n urlSearchParams.append(key, String(value))\n }\n }\n\n return urlSearchParams\n }\n}\n\n/**\n * Creates a params schema for URL query parameters.\n *\n * Params schemas validate query string parameters for Lexicon endpoints.\n * Values must be boolean, integer, string, or arrays of those types.\n *\n * @param properties - Object mapping parameter names to their validators\n * @returns A new {@link ParamsSchema} instance\n *\n * @example\n * ```ts\n * // Simple pagination params\n * const paginationParams = l.params({\n * limit: l.optional(l.withDefault(l.integer({ minimum: 1, maximum: 100 }), 50)),\n * cursor: l.optional(l.string()),\n * })\n *\n * // Required parameter\n * const actorParams = l.params({\n * actor: l.string({ format: 'at-identifier' }),\n * })\n *\n * // Array parameter (multiple values)\n * const filterParams = l.params({\n * tags: l.optional(l.array(l.string())),\n * })\n *\n * // Convert from URL\n * const urlParams = new URLSearchParams('limit=25&cursor=abc')\n * const validated = paginationParams.fromURLSearchParams(urlParams)\n *\n * // Convert to URL\n * const searchParams = paginationParams.toURLSearchParams({ limit: 25 })\n * ```\n */\nexport const params = /*#__PURE__*/ memoizedOptions(function params<\n const TShape extends ParamsSchemaShape = NonNullable<unknown>,\n>(properties: TShape = {} as TShape) {\n return new ParamsSchema<TShape>(properties)\n})\n\nfunction unwrapValidator(schema?: Validator): Validator | undefined {\n while (\n schema instanceof OptionalSchema ||\n schema instanceof WithDefaultSchema\n ) {\n schema = schema.validator\n }\n return schema\n}\n"]}
1
+ {"version":3,"file":"params.js","sourceRoot":"","sources":["../../src/schema/params.ts"],"names":[],"mappings":"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","sourcesContent":["import { isPlainObject } from '@atproto/lex-data'\nimport {\n Infer,\n InferInput,\n InferOutput,\n Issue,\n IssueInvalidType,\n IssueInvalidValue,\n ParseOptions,\n Schema,\n ValidationContext,\n ValidationError,\n Validator,\n WithOptionalProperties,\n} from '../core.js'\nimport { lazyProperty } from '../util/lazy-property.js'\nimport { memoizedOptions } from '../util/memoize.js'\nimport { ArraySchema, array } from './array.js'\nimport { BooleanSchema, boolean } from './boolean.js'\nimport { dict } from './dict.js'\nimport { EnumSchema } from './enum.js'\nimport { IntegerSchema, integer } from './integer.js'\nimport { LiteralSchema } from './literal.js'\nimport { OptionalSchema, optional } from './optional.js'\nimport { StringSchema, string } from './string.js'\nimport { union } from './union.js'\nimport { WithDefaultSchema } from './with-default.js'\n\n/**\n * Scalar types allowed in URL parameters: boolean, integer, or string.\n */\nexport type ParamScalar = Infer<typeof paramScalarSchema>\nconst paramScalarSchema = union([boolean(), integer(), string()])\n\n/**\n * A single parameter value: scalar or array of scalars.\n */\nexport type Param = Infer<typeof paramSchema>\n\n/**\n * Schema for validating individual parameter values.\n */\nexport const paramSchema = union([\n paramScalarSchema,\n array(boolean()),\n array(integer()),\n array(string()),\n])\n\n/**\n * Type for a params object with string keys and optional param values.\n */\nexport type Params = Infer<typeof paramsSchema>\n\n/**\n * Schema for validating arbitrary params objects.\n */\nexport const paramsSchema = dict(string(), optional(paramSchema))\n\nexport type ParamScalarValidator =\n // @NOTE In order to properly coerce URLSearchParams, we need to distinguish\n // between scalar and array validators, requiring to be able to detect which\n // schema types are being used, restricting the allowed param validators here.\n | LiteralSchema<string>\n | LiteralSchema<number>\n | LiteralSchema<boolean>\n | EnumSchema<string>\n | EnumSchema<number>\n // | EnumSchema<boolean> // Boolean lexicon definitions don't allow \"enum\"\n | StringSchema<any>\n | BooleanSchema\n | IntegerSchema\n\ntype AsArrayParamSchema<TSchema extends Validator> =\n // This allows to \"distribute\" any union of scalar validators into a union of\n // arrays of those validators, instead of an array of union. If TSchema is\n // BooleanSchema | IntegerSchema, we want the result to be\n // ArraySchema<BooleanSchema> | ArraySchema<IntegerSchema>, not\n // ArraySchema<BooleanSchema | IntegerSchema>, since the latter would allow\n // arrays with mixed types (e.g. [true, 42]), which we don't want.\n TSchema extends any ? ArraySchema<TSchema> : never\n\nexport type ParamValueValidator =\n | ParamScalarValidator\n | AsArrayParamSchema<ParamScalarValidator>\n\nexport type ParamValidator =\n | ParamValueValidator\n | OptionalSchema<ParamValueValidator>\n | OptionalSchema<WithDefaultSchema<ParamValueValidator>>\n | WithDefaultSchema<ParamValueValidator>\n\n/**\n * Type representing the shape of a params schema definition.\n *\n * Maps parameter names to their validators (must be Param or undefined).\n */\nexport type ParamsShape = {\n [x: string]: ParamValidator\n}\n\n/**\n * Schema for validating URL query parameters in Lexicon endpoints.\n *\n * Params are the query string parameters passed to queries, procedures,\n * and subscriptions. Values must be scalars (boolean, integer, string)\n * or arrays of scalars, as they need to be serializable to URL format.\n *\n * Provides methods for converting to/from URLSearchParams.\n *\n * @template TShape - The params shape type mapping names to validators\n *\n * @example\n * ```ts\n * const schema = new ParamsSchema({\n * limit: l.optional(l.integer({ minimum: 1, maximum: 100 })),\n * cursor: l.optional(l.string()),\n * })\n * ```\n */\nexport class ParamsSchema<\n const TShape extends ParamsShape = ParamsShape,\n> extends Schema<\n WithOptionalProperties<{\n [K in keyof TShape]: InferInput<TShape[K]>\n }>,\n WithOptionalProperties<{\n [K in keyof TShape]: InferOutput<TShape[K]>\n }>\n> {\n readonly type = 'params' as const\n\n constructor(readonly shape: TShape) {\n super()\n }\n\n get shapeValidators(): Map<string, ParamValidator> {\n const map = new Map(Object.entries(this.shape))\n\n return lazyProperty(this, 'shapeValidators', map)\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n if (!isPlainObject(input)) {\n return ctx.issueUnexpectedType(input, 'object')\n }\n\n // Lazily copy value\n let copy: undefined | Record<string, unknown>\n\n // Ensure that non-specified params conform to param schema\n for (const key in input) {\n if (this.shapeValidators.has(key)) continue\n\n const result = ctx.validateChild(input, key, paramSchema)\n if (!result.success) return result\n\n if (result.value !== input[key]) {\n if (ctx.options.mode === 'validate') {\n // In \"validate\" mode, we can't modify the input, so we issue an error\n return ctx.issueInvalidPropertyValue(input, key, [result.value])\n }\n\n copy ??= { ...input }\n copy[key] = result.value\n }\n }\n\n for (const [key, propDef] of this.shapeValidators) {\n const result = ctx.validateChild(input, key, propDef)\n if (!result.success) {\n if (!(key in input)) {\n // Transform into \"required key\" issue\n return ctx.issueRequiredKey(input, key)\n }\n\n return result\n }\n\n // Skip copying if key is not present in input (and value is undefined)\n if (result.value === undefined && !(key in input)) {\n continue\n }\n\n if (!Object.is(result.value, input[key])) {\n if (ctx.options.mode === 'validate') {\n // In \"validate\" mode, we can't modify the input, so we issue an error\n return ctx.issueInvalidPropertyValue(input, key, [result.value])\n }\n\n // Copy on write\n copy ??= { ...input }\n copy[key] = result.value\n }\n }\n\n return ctx.success(copy ?? input)\n }\n\n fromURLSearchParams(\n input: string | Iterable<[string, string]>,\n options?: ParseOptions,\n ): InferOutput<this> {\n const params: Record<string, unknown> = {}\n\n const iterable =\n typeof input === 'string' ? new URLSearchParams(input) : input\n const entries =\n iterable instanceof URLSearchParams ? iterable.entries() : iterable\n\n for (const [name, value] of entries) {\n const validator = this.shapeValidators.get(name)\n const innerValidator = validator ? unwrapSchema(validator) : undefined\n const expectsArray = innerValidator instanceof ArraySchema\n const scalarValidator = expectsArray\n ? unwrapSchema(innerValidator.validator)\n : innerValidator\n\n const coerced = coerceParam(name, value, scalarValidator, options)\n\n const currentParam = params[name]\n if (currentParam === undefined) {\n params[name] = expectsArray ? [coerced] : coerced\n } else if (Array.isArray(currentParam)) {\n currentParam.push(coerced)\n } else {\n params[name] = [currentParam, coerced]\n }\n }\n\n return this.parse(params, options)\n }\n\n toURLSearchParams(input: InferInput<this>): URLSearchParams {\n const urlSearchParams = new URLSearchParams()\n\n // @NOTE We apply defaults here to ensure that server with different\n // defaults still receive all expected parameters.\n const params = this.parse(input)\n\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n urlSearchParams.append(key, String(v))\n }\n } else if (value !== undefined) {\n urlSearchParams.append(key, String(value))\n }\n }\n\n return urlSearchParams\n }\n}\n\nfunction coerceParam(\n name: string,\n param: string,\n schema?: ParamScalarValidator,\n options?: ParseOptions,\n): ParamScalar {\n let issue: Issue\n\n if (!schema) {\n // The param is unknown (not defined in schema), so we don't apply any\n // coercion and just return the string value.\n return param\n } else if (schema instanceof StringSchema) {\n return param\n } else if (schema instanceof IntegerSchema) {\n if (/^-?\\d+$/.test(param)) return Number(param)\n issue = new IssueInvalidType(paramPath(name, options), param, ['integer'])\n } else if (schema instanceof BooleanSchema) {\n if (param === 'true') return true\n if (param === 'false') return false\n issue = new IssueInvalidType(paramPath(name, options), param, ['boolean'])\n } else if (schema instanceof LiteralSchema) {\n const { value } = schema\n if (String(value) === param) return value\n issue = new IssueInvalidValue(paramPath(name, options), param, [value])\n } else if (schema instanceof EnumSchema) {\n const { values } = schema\n for (const value of values) {\n if (String(value) === param) return value\n }\n issue = new IssueInvalidValue(paramPath(name, options), param, values)\n } else {\n // This should never happen. If it *does*, it means that the user of\n // lex-schema is mixing different versions of the lib, which is not\n // supported. Throwing an error here is better than silently accepting\n // invalid params and causing unexpected behavior down the line (ie. error\n // message returning the string value instead of the expected\n // boolean/number/string value).\n throw new Error(`Unsupported schema type for param coercion: ${schema}`)\n }\n\n // We were not able to coerce the param to the expected type. There is no\n // point in returning the original string value since it doesn't conform to\n // the expected schema, so we throw a validation error instead. We could\n // return the \"param\" here, which would cause the validation to fail later on\n // (see fromURLSearchParams()'s return statement). The main benefit of\n // returning the original \"param\" value is that the error path would include\n // the index of the param in case of array params (e.g. \"tags[1]\"), which\n // could be helpful for debugging. The cost overhead is not worth it though\n // (IMO).\n throw new ValidationError([issue])\n}\n\nfunction paramPath(key: string, options?: ParseOptions) {\n return options?.path ? [...options.path, key] : [key]\n}\n\n/**\n * Creates a params schema for URL query parameters.\n *\n * Params schemas validate query string parameters for Lexicon endpoints.\n * Values must be boolean, integer, string, or arrays of those types.\n *\n * @param properties - Object mapping parameter names to their validators\n * @returns A new {@link ParamsSchema} instance\n *\n * @example\n * ```ts\n * // Simple pagination params\n * const paginationParams = l.params({\n * limit: l.optional(l.withDefault(l.integer({ minimum: 1, maximum: 100 }), 50)),\n * cursor: l.optional(l.string()),\n * })\n *\n * // Required parameter\n * const actorParams = l.params({\n * actor: l.string({ format: 'at-identifier' }),\n * })\n *\n * // Array parameter (multiple values)\n * const filterParams = l.params({\n * tags: l.optional(l.array(l.string())),\n * })\n *\n * // Convert from URL\n * const urlParams = new URLSearchParams('limit=25&cursor=abc')\n * const validated = paginationParams.fromURLSearchParams(urlParams)\n *\n * // Convert to URL\n * const searchParams = paginationParams.toURLSearchParams({ limit: 25 })\n * ```\n */\nexport const params = /*#__PURE__*/ memoizedOptions(function params<\n const TShape extends ParamsShape = NonNullable<unknown>,\n>(properties: TShape = {} as TShape) {\n return new ParamsSchema<TShape>(properties)\n})\n\ntype UnwrapSchema<S extends Validator> =\n S extends OptionalSchema<infer U>\n ? UnwrapSchema<U>\n : S extends WithDefaultSchema<infer U>\n ? UnwrapSchema<U>\n : S\n\nfunction unwrapSchema<S extends Validator>(schema: S): UnwrapSchema<S> {\n while (\n schema instanceof OptionalSchema ||\n schema instanceof WithDefaultSchema\n ) {\n return unwrapSchema(schema.validator)\n }\n return schema as UnwrapSchema<S>\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../src/schema/payload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../src/schema/payload.ts"],"names":[],"mappings":"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"}
@@ -36,20 +36,20 @@ class Payload {
36
36
  * encoding.
37
37
  */
38
38
  matchesEncoding(contentType) {
39
- const mime = contentType?.split(';', 1)[0].trim();
40
39
  const { encoding } = this;
41
40
  // Handle undefined cases
42
41
  if (encoding === undefined) {
43
42
  // Expecting no body
44
- return mime === undefined;
43
+ return contentType == null;
45
44
  }
46
- else if (mime === undefined) {
45
+ else if (contentType == null) {
47
46
  // Expecting a body, but got no content-type
48
47
  return false;
49
48
  }
50
49
  if (encoding === '*/*') {
51
50
  return true;
52
51
  }
52
+ const mime = contentType?.split(';', 1)[0].trim();
53
53
  if (encoding.endsWith('/*')) {
54
54
  return mime.startsWith(encoding.slice(0, -1));
55
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../src/schema/payload.ts"],"names":[],"mappings":";;;AAwKA,0BAKC;AA4BD,kCAIC;AA3MD,2CAAkD;AAwElD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,OAAO;IAKP;IACA;IAFX,YACW,QAAmB,EACnB,MAAe;QADf,aAAQ,GAAR,QAAQ,CAAW;QACnB,WAAM,GAAN,MAAM,CAAS;QAExB,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnD,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAA;QAC5E,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,WAA+B;QAC7C,MAAM,IAAI,GAAG,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAEjD,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;QAEzB,yBAAyB;QACzB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,oBAAoB;YACpB,OAAO,IAAI,KAAK,SAAS,CAAA;QAC3B,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,4CAA4C;YAC5C,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;YACvB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/C,CAAC;QAED,gEAAgE;QAChE,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,OAAO,QAAQ,KAAK,IAAI,CAAA;IAC1B,CAAC;CACF;AA9CD,0BA8CC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAwB;AACxB,SAAgB,OAAO,CAGrB,WAAc,SAAc,EAAE,YAAe,SAAc;IAC3D,OAAO,IAAI,OAAO,CAAO,QAAQ,EAAE,SAAS,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAwB;AACxB,SAAgB,WAAW,CAEzB,UAAa;IACb,OAAO,OAAO,CAAC,kBAAkB,EAAE,IAAA,kBAAM,EAAC,UAAU,CAAC,CAAC,CAAA;AACxD,CAAC","sourcesContent":["import { LexValue } from '@atproto/lex-data'\nimport { Infer, Schema, Validator } from '../core.js'\nimport { ObjectSchema, object } from './object.js'\n\nexport type { LexValue }\n\ntype ToBodyMime<TEncoding extends string> = TEncoding extends '*/*'\n ? `${string}/${string}`\n : TEncoding extends `${infer T extends string}/*`\n ? `${T}/${string}`\n : TEncoding\n\ntype ToBodyType<\n TEncoding extends string,\n TSchema,\n TBinary,\n> = TSchema extends Schema\n ? Infer<TSchema>\n : TEncoding extends `application/json`\n ? LexValue\n : TBinary\n\n/**\n * Infers the type of a Payload's encoding and body.\n *\n * @template TPayload - The Payload type\n * @template TBody - Fallback body type for non-JSON encodings\n */\nexport type InferPayload<TPayload extends Payload, TBinary> =\n TPayload extends Payload<infer TEncoding, infer TSchema>\n ? TEncoding extends string\n ? {\n encoding: ToBodyMime<TEncoding>\n body: ToBodyType<TEncoding, TSchema, TBinary>\n }\n : undefined\n : never\n\n/**\n * Converts schema encoding patterns to data encoding types.\n *\n * Handles wildcards like '*\\/*' and 'image/*' in MIME types.\n *\n * @template TPayload - The Payload type\n */\nexport type InferPayloadEncoding<TPayload extends Payload> =\n TPayload extends Payload<infer TEncoding, any>\n ? TEncoding extends string\n ? ToBodyMime<TEncoding>\n : undefined\n : never\n\n/**\n * Infers the body type from a Payload and fallback type.\n *\n * @template TPayload - The Payload type\n * @template TBody - Fallback body type for non-JSON encodings without schema\n */\nexport type InferPayloadBody<TPayload extends Payload, TBinary> =\n TPayload extends Payload<infer TEncoding, infer TSchema>\n ? TEncoding extends string\n ? ToBodyType<TEncoding, TSchema, TBinary>\n : undefined\n : never\n\n/**\n * Determines valid schema type based on encoding presence.\n *\n * @template E - The encoding string type, or undefined\n */\nexport type PayloadSchema<E extends string | undefined> = E extends undefined\n ? undefined\n : Schema<LexValue> | undefined\n\n/**\n * Represents a payload definition for Lexicon endpoints.\n *\n * Payloads define the body format for HTTP requests and responses.\n * They consist of an encoding (MIME type) and an optional schema\n * for validating the body content.\n *\n * @template TEncoding - The MIME type string, or undefined for no body\n * @template TPayload - The schema type for body validation\n *\n * @example\n * ```ts\n * const jsonPayload = new Payload('application/json', l.object({ data: l.string() }))\n * const binaryPayload = new Payload('image/*', undefined)\n * const noPayload = new Payload(undefined, undefined)\n * ```\n */\nexport class Payload<\n const TEncoding extends string | undefined = string | undefined,\n const TSchema extends PayloadSchema<TEncoding> = PayloadSchema<TEncoding>,\n> {\n constructor(\n readonly encoding: TEncoding,\n readonly schema: TSchema,\n ) {\n if (encoding === undefined && schema !== undefined) {\n throw new TypeError('schema cannot be defined when encoding is undefined')\n }\n }\n\n /**\n * Checks whether the given content-type matches the expected payload schema's\n * encoding.\n */\n matchesEncoding(contentType: string | undefined): boolean {\n const mime = contentType?.split(';', 1)[0].trim()\n\n const { encoding } = this\n\n // Handle undefined cases\n if (encoding === undefined) {\n // Expecting no body\n return mime === undefined\n } else if (mime === undefined) {\n // Expecting a body, but got no content-type\n return false\n }\n\n if (encoding === '*/*') {\n return true\n }\n\n if (encoding.endsWith('/*')) {\n return mime.startsWith(encoding.slice(0, -1))\n }\n\n // Invalid: Lexicon can only specify \"*/*\" or \"type/*\" wildcards\n if (encoding.includes('*')) {\n return false\n }\n\n return encoding === mime\n }\n}\n\n/**\n * Creates a payload definition for Lexicon endpoint bodies.\n *\n * Defines the expected MIME type and optional validation schema for\n * request or response bodies.\n *\n * @param encoding - MIME type string (e.g., 'application/json', 'image/*'), or undefined for no body\n * @param validator - Optional schema for validating the body content. Must be undefined if encoding is undefined.\n * @returns A new {@link Payload} instance\n *\n * @example\n * ```ts\n * // JSON payload with schema\n * const output = l.payload('application/json', l.object({\n * posts: l.array(postSchema),\n * cursor: l.optional(l.string()),\n * }))\n *\n * // Binary payload (no schema validation)\n * const blobInput = l.payload('*\\/*', undefined)\n *\n * // Image payload with wildcard\n * const imageInput = l.payload('image/*', undefined)\n *\n * // No payload (for endpoints without body)\n * const noBody = l.payload()\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function payload<\n const E extends string | undefined = undefined,\n const S extends PayloadSchema<E> = undefined,\n>(encoding: E = undefined as E, validator: S = undefined as S) {\n return new Payload<E, S>(encoding, validator)\n}\n\n/**\n * Creates a JSON payload with an object schema.\n *\n * Convenience function for the common case of JSON request/response bodies.\n * Equivalent to `l.payload('application/json', l.object(properties))`.\n *\n * @param properties - Object mapping property names to validators\n * @returns A new {@link Payload} instance with 'application/json' encoding\n *\n * @example\n * ```ts\n * // Query output\n * const profileOutput = l.jsonPayload({\n * did: l.string({ format: 'did' }),\n * handle: l.string({ format: 'handle' }),\n * displayName: l.optional(l.string()),\n * })\n *\n * // Procedure input\n * const createPostInput = l.jsonPayload({\n * text: l.string({ maxGraphemes: 300 }),\n * createdAt: l.string({ format: 'datetime' }),\n * })\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function jsonPayload<\n P extends Record<string, Validator<undefined | LexValue>>,\n>(properties: P): Payload<'application/json', ObjectSchema<P>> {\n return payload('application/json', object(properties))\n}\n"]}
1
+ {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../src/schema/payload.ts"],"names":[],"mappings":";;;AAuKA,0BAKC;AA4BD,kCAIC;AA1MD,2CAAkD;AAwElD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,OAAO;IAKP;IACA;IAFX,YACW,QAAmB,EACnB,MAAe;QADf,aAAQ,GAAR,QAAQ,CAAW;QACnB,WAAM,GAAN,MAAM,CAAS;QAExB,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnD,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAA;QAC5E,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,WAA+B;QAC7C,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;QAEzB,yBAAyB;QACzB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,oBAAoB;YACpB,OAAO,WAAW,IAAI,IAAI,CAAA;QAC5B,CAAC;aAAM,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;YAC/B,4CAA4C;YAC5C,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;YACvB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,MAAM,IAAI,GAAG,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACjD,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/C,CAAC;QAED,gEAAgE;QAChE,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,OAAO,QAAQ,KAAK,IAAI,CAAA;IAC1B,CAAC;CACF;AA7CD,0BA6CC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAwB;AACxB,SAAgB,OAAO,CAGrB,WAAc,SAAc,EAAE,YAAe,SAAc;IAC3D,OAAO,IAAI,OAAO,CAAO,QAAQ,EAAE,SAAS,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAwB;AACxB,SAAgB,WAAW,CAEzB,UAAa;IACb,OAAO,OAAO,CAAC,kBAAkB,EAAE,IAAA,kBAAM,EAAC,UAAU,CAAC,CAAC,CAAA;AACxD,CAAC","sourcesContent":["import { LexValue } from '@atproto/lex-data'\nimport { Infer, Schema, Validator } from '../core.js'\nimport { ObjectSchema, object } from './object.js'\n\nexport type { LexValue }\n\ntype ToBodyMime<TEncoding extends string> = TEncoding extends '*/*'\n ? `${string}/${string}`\n : TEncoding extends `${infer T extends string}/*`\n ? `${T}/${string}`\n : TEncoding\n\ntype ToBodyType<\n TEncoding extends string,\n TSchema,\n TBinary,\n> = TSchema extends Schema\n ? Infer<TSchema>\n : TEncoding extends `application/json`\n ? LexValue\n : TBinary\n\n/**\n * Infers the type of a Payload's encoding and body.\n *\n * @template TPayload - The Payload type\n * @template TBody - Fallback body type for non-JSON encodings\n */\nexport type InferPayload<TPayload extends Payload, TBinary> =\n TPayload extends Payload<infer TEncoding, infer TSchema>\n ? TEncoding extends string\n ? {\n encoding: ToBodyMime<TEncoding>\n body: ToBodyType<TEncoding, TSchema, TBinary>\n }\n : undefined\n : never\n\n/**\n * Converts schema encoding patterns to data encoding types.\n *\n * Handles wildcards like '*\\/*' and 'image/*' in MIME types.\n *\n * @template TPayload - The Payload type\n */\nexport type InferPayloadEncoding<TPayload extends Payload> =\n TPayload extends Payload<infer TEncoding, any>\n ? TEncoding extends string\n ? ToBodyMime<TEncoding>\n : undefined\n : never\n\n/**\n * Infers the body type from a Payload and fallback type.\n *\n * @template TPayload - The Payload type\n * @template TBody - Fallback body type for non-JSON encodings without schema\n */\nexport type InferPayloadBody<TPayload extends Payload, TBinary> =\n TPayload extends Payload<infer TEncoding, infer TSchema>\n ? TEncoding extends string\n ? ToBodyType<TEncoding, TSchema, TBinary>\n : undefined\n : never\n\n/**\n * Determines valid schema type based on encoding presence.\n *\n * @template E - The encoding string type, or undefined\n */\nexport type PayloadSchema<E extends string | undefined> = E extends undefined\n ? undefined\n : Schema<LexValue> | undefined\n\n/**\n * Represents a payload definition for Lexicon endpoints.\n *\n * Payloads define the body format for HTTP requests and responses.\n * They consist of an encoding (MIME type) and an optional schema\n * for validating the body content.\n *\n * @template TEncoding - The MIME type string, or undefined for no body\n * @template TPayload - The schema type for body validation\n *\n * @example\n * ```ts\n * const jsonPayload = new Payload('application/json', l.object({ data: l.string() }))\n * const binaryPayload = new Payload('image/*', undefined)\n * const noPayload = new Payload(undefined, undefined)\n * ```\n */\nexport class Payload<\n const TEncoding extends string | undefined = string | undefined,\n const TSchema extends PayloadSchema<TEncoding> = PayloadSchema<TEncoding>,\n> {\n constructor(\n readonly encoding: TEncoding,\n readonly schema: TSchema,\n ) {\n if (encoding === undefined && schema !== undefined) {\n throw new TypeError('schema cannot be defined when encoding is undefined')\n }\n }\n\n /**\n * Checks whether the given content-type matches the expected payload schema's\n * encoding.\n */\n matchesEncoding(contentType: string | undefined): boolean {\n const { encoding } = this\n\n // Handle undefined cases\n if (encoding === undefined) {\n // Expecting no body\n return contentType == null\n } else if (contentType == null) {\n // Expecting a body, but got no content-type\n return false\n }\n\n if (encoding === '*/*') {\n return true\n }\n\n const mime = contentType?.split(';', 1)[0].trim()\n if (encoding.endsWith('/*')) {\n return mime.startsWith(encoding.slice(0, -1))\n }\n\n // Invalid: Lexicon can only specify \"*/*\" or \"type/*\" wildcards\n if (encoding.includes('*')) {\n return false\n }\n\n return encoding === mime\n }\n}\n\n/**\n * Creates a payload definition for Lexicon endpoint bodies.\n *\n * Defines the expected MIME type and optional validation schema for\n * request or response bodies.\n *\n * @param encoding - MIME type string (e.g., 'application/json', 'image/*'), or undefined for no body\n * @param validator - Optional schema for validating the body content. Must be undefined if encoding is undefined.\n * @returns A new {@link Payload} instance\n *\n * @example\n * ```ts\n * // JSON payload with schema\n * const output = l.payload('application/json', l.object({\n * posts: l.array(postSchema),\n * cursor: l.optional(l.string()),\n * }))\n *\n * // Binary payload (no schema validation)\n * const blobInput = l.payload('*\\/*', undefined)\n *\n * // Image payload with wildcard\n * const imageInput = l.payload('image/*', undefined)\n *\n * // No payload (for endpoints without body)\n * const noBody = l.payload()\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function payload<\n const E extends string | undefined = undefined,\n const S extends PayloadSchema<E> = undefined,\n>(encoding: E = undefined as E, validator: S = undefined as S) {\n return new Payload<E, S>(encoding, validator)\n}\n\n/**\n * Creates a JSON payload with an object schema.\n *\n * Convenience function for the common case of JSON request/response bodies.\n * Equivalent to `l.payload('application/json', l.object(properties))`.\n *\n * @param properties - Object mapping property names to validators\n * @returns A new {@link Payload} instance with 'application/json' encoding\n *\n * @example\n * ```ts\n * // Query output\n * const profileOutput = l.jsonPayload({\n * did: l.string({ format: 'did' }),\n * handle: l.string({ format: 'handle' }),\n * displayName: l.optional(l.string()),\n * })\n *\n * // Procedure input\n * const createPostInput = l.jsonPayload({\n * text: l.string({ maxGraphemes: 300 }),\n * createdAt: l.string({ format: 'datetime' }),\n * })\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function jsonPayload<\n P extends Record<string, Validator<undefined | LexValue>>,\n>(properties: P): Payload<'application/json', ObjectSchema<P>> {\n return payload('application/json', object(properties))\n}\n"]}
@@ -5,6 +5,13 @@ import { $Typed, InferInput, InferOutput, LexiconRecordKey, NsidString, Schema,
5
5
  * @template R - The RecordSchema type
6
6
  */
7
7
  export type InferRecordKey<R extends RecordSchema> = R extends RecordSchema<infer TKey> ? RecordKeySchemaOutput<TKey> : never;
8
+ export type TypedRecord<TType extends NsidString, TValue extends {
9
+ $type?: unknown;
10
+ } = {
11
+ $type?: unknown;
12
+ }> = TValue extends {
13
+ $type: TType;
14
+ } ? TValue : $Typed<Exclude<TValue, Unknown$TypedObject>, TType>;
8
15
  /**
9
16
  * Schema for AT Protocol records with a type identifier and key constraints.
10
17
  *
@@ -31,28 +38,17 @@ export declare class RecordSchema<const TKey extends LexiconRecordKey = any, con
31
38
  readonly key: TKey;
32
39
  readonly $type: TType;
33
40
  readonly schema: TShape;
41
+ readonly type: "record";
34
42
  keySchema: RecordKeySchema<TKey>;
35
43
  constructor(key: TKey, $type: TType, schema: TShape);
36
- isTypeOf<X extends {
44
+ isTypeOf<TValue extends {
37
45
  $type?: unknown;
38
- }>(value: X): value is X extends {
39
- $type: TType;
40
- } ? X : $Typed<Exclude<X, Unknown$TypedObject>, TType>;
46
+ }>(value: TValue): value is TypedRecord<TType, TValue>;
41
47
  build(input: Omit<InferInput<this>, '$type'>): $Typed<InferOutput<this>, TType>;
42
- $isTypeOf<X extends {
48
+ $isTypeOf<TValue extends {
43
49
  $type?: unknown;
44
- }>(value: X): value is X extends {
45
- $type: TType;
46
- } ? X : Exclude<X, Unknown$TypedObject> & {
47
- $type: TType;
48
- } extends infer T ? { [K in keyof T]: (Exclude<X, Unknown$TypedObject> & {
49
- $type: TType;
50
- })[K]; } : never;
51
- $build(input: Omit<InferInput<this>, '$type'>): InferOutput<this> & {
52
- $type: TType;
53
- } extends infer T ? { [K in keyof T]: (InferOutput<this> & {
54
- $type: TType;
55
- })[K]; } : never;
50
+ }>(value: TValue): value is TypedRecord<TType, TValue>;
51
+ $build(input: Omit<InferInput<this>, '$type'>): $Typed<InferOutput<this>, TType>;
56
52
  validateInContext(input: unknown, ctx: ValidationContext): import("../core.js").ValidationFailure | import("../core.js").ValidationSuccess<InferInput<TShape>>;
57
53
  }
58
54
  export type RecordKeySchemaOutput<Key extends LexiconRecordKey> = Key extends 'any' ? string : Key extends 'tid' ? TidString : Key extends 'nsid' ? NsidString : Key extends `literal:${infer L extends string}` ? L : never;
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/schema/record.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/schema/record.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,7 @@ class RecordSchema extends core_js_1.Schema {
29
29
  key;
30
30
  $type;
31
31
  schema;
32
+ type = 'record';
32
33
  keySchema;
33
34
  constructor(key, $type, schema) {
34
35
  super();
@@ -1 +1 @@
1
- {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/schema/record.ts"],"names":[],"mappings":";;;AAoMA,wBAMC;AA1MD,wCAYmB;AACnB,6CAAsC;AACtC,2CAAoC;AAUpC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAa,YAIX,SAAQ,gBAGT;IAIY;IACA;IACA;IALX,SAAS,CAAuB;IAEhC,YACW,GAAS,EACT,KAAY,EACZ,MAAc;QAEvB,KAAK,EAAE,CAAA;QAJE,QAAG,GAAH,GAAG,CAAM;QACT,UAAK,GAAL,KAAK,CAAO;QACZ,WAAM,GAAN,MAAM,CAAQ;QAGvB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;IACjC,CAAC;IAED,QAAQ,CACN,KAAQ;QAIR,OAAO,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAA;IACnC,CAAC;IAED,KAAK,CACH,KAAsC;QAEtC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAA,gBAAM,EAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,CAAC;IAED,SAAS,CAAgC,KAAQ;QAC/C,OAAO,IAAI,CAAC,QAAQ,CAAI,KAAK,CAAC,CAAA;IAChC,CAAC;IAED,MAAM,CAAC,KAAsC;QAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,iBAAiB,CAAC,KAAc,EAAE,GAAsB;QACtD,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAE/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,MAAM,CAAA;QACf,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,OAAO,GAAG,CAAC,yBAAyB,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3E,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAtDD,oCAsDC;AAiBD,MAAM,SAAS,GAAG,IAAA,kBAAM,EAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAA;AAC1C,MAAM,SAAS,GAAG,IAAA,kBAAM,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;AAC3C,MAAM,UAAU,GAAG,IAAA,kBAAM,EAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AAC7C,MAAM,iBAAiB,GAAG,IAAA,oBAAO,EAAC,MAAM,CAAC,CAAA;AAEzC,SAAS,SAAS,CAChB,GAAQ;IAER,gDAAgD;IAChD,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,SAAgB,CAAA;IAC1C,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,SAAgB,CAAA;IAC1C,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,UAAiB,CAAA;IAC5C,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAA+B,CAAA;QACxD,IAAI,KAAK,KAAK,MAAM;YAAE,OAAO,iBAAwB,CAAA;QACrD,OAAO,IAAA,oBAAO,EAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAA;AACxD,CAAC;AA6DD,wBAAwB;AACxB,SAAgB,MAAM,CAIpB,GAAM,EAAE,IAAO,EAAE,SAAY;IAC7B,OAAO,IAAI,YAAY,CAAU,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;AACxD,CAAC","sourcesContent":["import {\n $Typed,\n $typed,\n InferInput,\n InferOutput,\n LexiconRecordKey,\n NsidString,\n Schema,\n TidString,\n Unknown$TypedObject,\n ValidationContext,\n Validator,\n} from '../core.js'\nimport { literal } from './literal.js'\nimport { string } from './string.js'\n\n/**\n * Infers the record key type from a RecordSchema.\n *\n * @template R - The RecordSchema type\n */\nexport type InferRecordKey<R extends RecordSchema> =\n R extends RecordSchema<infer TKey> ? RecordKeySchemaOutput<TKey> : never\n\n/**\n * Schema for AT Protocol records with a type identifier and key constraints.\n *\n * Records are the primary data unit in AT Protocol. Each record has a `$type`\n * field identifying its Lexicon schema, and is stored at a specific key\n * (TID, NSID, or other format) in a repository.\n *\n * @template TKey - The record key type ('tid', 'nsid', 'any', or 'literal:...')\n * @template TType - The NSID string identifying this record type\n * @template TShape - The validator type for the record's data shape\n *\n * @example\n * ```ts\n * const postSchema = new RecordSchema(\n * 'tid',\n * 'app.bsky.feed.post',\n * l.object({ text: l.string(), createdAt: l.string() })\n * )\n * ```\n */\nexport class RecordSchema<\n const TKey extends LexiconRecordKey = any,\n const TType extends NsidString = any,\n const TShape extends Validator<{ [k: string]: unknown }> = any,\n> extends Schema<\n $Typed<InferInput<TShape>, TType>,\n $Typed<InferOutput<TShape>, TType>\n> {\n keySchema: RecordKeySchema<TKey>\n\n constructor(\n readonly key: TKey,\n readonly $type: TType,\n readonly schema: TShape,\n ) {\n super()\n this.keySchema = recordKey(key)\n }\n\n isTypeOf<X extends { $type?: unknown }>(\n value: X,\n ): value is X extends { $type: TType }\n ? X\n : $Typed<Exclude<X, Unknown$TypedObject>, TType> {\n return value.$type === this.$type\n }\n\n build(\n input: Omit<InferInput<this>, '$type'>,\n ): $Typed<InferOutput<this>, TType> {\n return this.parse($typed(input, this.$type))\n }\n\n $isTypeOf<X extends { $type?: unknown }>(value: X) {\n return this.isTypeOf<X>(value)\n }\n\n $build(input: Omit<InferInput<this>, '$type'>) {\n return this.build(input)\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n const result = ctx.validate(input, this.schema)\n\n if (!result.success) {\n return result\n }\n\n if (result.value.$type !== this.$type) {\n return ctx.issueInvalidPropertyValue(result.value, '$type', [this.$type])\n }\n\n return result\n }\n}\n\nexport type RecordKeySchemaOutput<Key extends LexiconRecordKey> =\n Key extends 'any'\n ? string\n : Key extends 'tid'\n ? TidString\n : Key extends 'nsid'\n ? NsidString\n : Key extends `literal:${infer L extends string}`\n ? L\n : never\n\nexport type RecordKeySchema<Key extends LexiconRecordKey> = Schema<\n RecordKeySchemaOutput<Key>\n>\n\nconst keySchema = string({ minLength: 1 })\nconst tidSchema = string({ format: 'tid' })\nconst nsidSchema = string({ format: 'nsid' })\nconst selfLiteralSchema = literal('self')\n\nfunction recordKey<Key extends LexiconRecordKey>(\n key: Key,\n): RecordKeySchema<Key> {\n // @NOTE Use cached instances for common schemas\n if (key === 'any') return keySchema as any\n if (key === 'tid') return tidSchema as any\n if (key === 'nsid') return nsidSchema as any\n if (key.startsWith('literal:')) {\n const value = key.slice(8) as RecordKeySchemaOutput<Key>\n if (value === 'self') return selfLiteralSchema as any\n return literal(value)\n }\n\n throw new Error(`Unsupported record key type: ${key}`)\n}\n\n/**\n * Ensures that a `$type` used in a record is a valid NSID (i.e. no fragment).\n */\ntype AsNsid<T> = T extends `${string}#${string}` ? never : T\n\n/**\n * Creates a record schema for AT Protocol records.\n *\n * Records are the primary data unit in AT Protocol repositories. They have\n * a `$type` field identifying their Lexicon schema, and are stored at keys\n * following a specific format (TID, NSID, etc.).\n *\n * This function offers two overloads:\n * - One that infers the output type from the provided arguments (does not\n * support circular references)\n * - One with an explicitly defined interface for use with codegen and\n * circular references\n *\n * @param key - The record key type: 'tid', 'nsid', 'any', or 'literal:value'\n * @param type - The NSID identifying this record type (e.g., 'app.bsky.feed.post')\n * @param validator - Schema validator for the record's properties\n * @returns A new {@link RecordSchema} instance\n *\n * @example\n * ```ts\n * // Post record with TID key\n * const postSchema = l.record('tid', 'app.bsky.feed.post', l.object({\n * text: l.string({ maxGraphemes: 300 }),\n * createdAt: l.string({ format: 'datetime' }),\n * reply: l.optional(l.object({\n * root: l.ref(() => strongRefSchema),\n * parent: l.ref(() => strongRefSchema),\n * })),\n * }))\n *\n * // Profile record with literal 'self' key\n * const profileSchema = l.record('literal:self', 'app.bsky.actor.profile', l.object({\n * displayName: l.optional(l.string({ maxGraphemes: 64 })),\n * description: l.optional(l.string({ maxGraphemes: 256 })),\n * avatar: l.optional(l.blob({ accept: ['image/*'] })),\n * }))\n *\n * // Build a record with automatic $type injection\n * const post = postSchema.build({ text: 'Hello!', createdAt: new Date().toISOString() })\n * ```\n */\nexport function record<\n const K extends LexiconRecordKey,\n const T extends NsidString,\n const S extends Validator<{ [k: string]: unknown }>,\n>(key: K, type: AsNsid<T>, validator: S): RecordSchema<K, T, S>\nexport function record<\n const K extends LexiconRecordKey,\n const V extends { $type: NsidString },\n>(\n key: K,\n type: AsNsid<V['$type']>,\n validator: Validator<Omit<V, '$type'>>,\n): RecordSchema<K, V['$type'], Validator<Omit<V, '$type'>>>\n/*@__NO_SIDE_EFFECTS__*/\nexport function record<\n const K extends LexiconRecordKey,\n const T extends NsidString,\n const S extends Validator<{ [k: string]: unknown }>,\n>(key: K, type: T, validator: S) {\n return new RecordSchema<K, T, S>(key, type, validator)\n}\n"]}
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/schema/record.ts"],"names":[],"mappings":";;;AA+MA,wBAMC;AArND,wCAYmB;AACnB,6CAAsC;AACtC,2CAAoC;AAiBpC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAa,YAIX,SAAQ,gBAGT;IAMY;IACA;IACA;IAPF,IAAI,GAAG,QAAiB,CAAA;IAEjC,SAAS,CAAuB;IAEhC,YACW,GAAS,EACT,KAAY,EACZ,MAAc;QAEvB,KAAK,EAAE,CAAA;QAJE,QAAG,GAAH,GAAG,CAAM;QACT,UAAK,GAAL,KAAK,CAAO;QACZ,WAAM,GAAN,MAAM,CAAQ;QAGvB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;IACjC,CAAC;IAED,QAAQ,CACN,KAAa;QAEb,OAAO,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAA;IACnC,CAAC;IAED,KAAK,CACH,KAAsC;QAEtC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAA,gBAAM,EAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,CAAC;IAED,SAAS,CACP,KAAa;QAEb,OAAO,IAAI,CAAC,QAAQ,CAAS,KAAK,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,CACJ,KAAsC;QAEtC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,iBAAiB,CAAC,KAAc,EAAE,GAAsB;QACtD,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAE/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,MAAM,CAAA;QACf,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,OAAO,GAAG,CAAC,yBAAyB,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3E,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AA1DD,oCA0DC;AAiBD,MAAM,SAAS,GAAG,IAAA,kBAAM,EAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAA;AAC1C,MAAM,SAAS,GAAG,IAAA,kBAAM,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;AAC3C,MAAM,UAAU,GAAG,IAAA,kBAAM,EAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AAC7C,MAAM,iBAAiB,GAAG,IAAA,oBAAO,EAAC,MAAM,CAAC,CAAA;AAEzC,SAAS,SAAS,CAChB,GAAQ;IAER,gDAAgD;IAChD,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,SAAgB,CAAA;IAC1C,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,SAAgB,CAAA;IAC1C,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,UAAiB,CAAA;IAC5C,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAA+B,CAAA;QACxD,IAAI,KAAK,KAAK,MAAM;YAAE,OAAO,iBAAwB,CAAA;QACrD,OAAO,IAAA,oBAAO,EAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAA;AACxD,CAAC;AA6DD,wBAAwB;AACxB,SAAgB,MAAM,CAIpB,GAAM,EAAE,IAAO,EAAE,SAAY;IAC7B,OAAO,IAAI,YAAY,CAAU,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;AACxD,CAAC","sourcesContent":["import {\n $Typed,\n $typed,\n InferInput,\n InferOutput,\n LexiconRecordKey,\n NsidString,\n Schema,\n TidString,\n Unknown$TypedObject,\n ValidationContext,\n Validator,\n} from '../core.js'\nimport { literal } from './literal.js'\nimport { string } from './string.js'\n\n/**\n * Infers the record key type from a RecordSchema.\n *\n * @template R - The RecordSchema type\n */\nexport type InferRecordKey<R extends RecordSchema> =\n R extends RecordSchema<infer TKey> ? RecordKeySchemaOutput<TKey> : never\n\nexport type TypedRecord<\n TType extends NsidString,\n TValue extends { $type?: unknown } = { $type?: unknown },\n> = TValue extends { $type: TType }\n ? TValue\n : $Typed<Exclude<TValue, Unknown$TypedObject>, TType>\n\n/**\n * Schema for AT Protocol records with a type identifier and key constraints.\n *\n * Records are the primary data unit in AT Protocol. Each record has a `$type`\n * field identifying its Lexicon schema, and is stored at a specific key\n * (TID, NSID, or other format) in a repository.\n *\n * @template TKey - The record key type ('tid', 'nsid', 'any', or 'literal:...')\n * @template TType - The NSID string identifying this record type\n * @template TShape - The validator type for the record's data shape\n *\n * @example\n * ```ts\n * const postSchema = new RecordSchema(\n * 'tid',\n * 'app.bsky.feed.post',\n * l.object({ text: l.string(), createdAt: l.string() })\n * )\n * ```\n */\nexport class RecordSchema<\n const TKey extends LexiconRecordKey = any,\n const TType extends NsidString = any,\n const TShape extends Validator<{ [k: string]: unknown }> = any,\n> extends Schema<\n $Typed<InferInput<TShape>, TType>,\n $Typed<InferOutput<TShape>, TType>\n> {\n readonly type = 'record' as const\n\n keySchema: RecordKeySchema<TKey>\n\n constructor(\n readonly key: TKey,\n readonly $type: TType,\n readonly schema: TShape,\n ) {\n super()\n this.keySchema = recordKey(key)\n }\n\n isTypeOf<TValue extends { $type?: unknown }>(\n value: TValue,\n ): value is TypedRecord<TType, TValue> {\n return value.$type === this.$type\n }\n\n build(\n input: Omit<InferInput<this>, '$type'>,\n ): $Typed<InferOutput<this>, TType> {\n return this.parse($typed(input, this.$type))\n }\n\n $isTypeOf<TValue extends { $type?: unknown }>(\n value: TValue,\n ): value is TypedRecord<TType, TValue> {\n return this.isTypeOf<TValue>(value)\n }\n\n $build(\n input: Omit<InferInput<this>, '$type'>,\n ): $Typed<InferOutput<this>, TType> {\n return this.build(input)\n }\n\n validateInContext(input: unknown, ctx: ValidationContext) {\n const result = ctx.validate(input, this.schema)\n\n if (!result.success) {\n return result\n }\n\n if (result.value.$type !== this.$type) {\n return ctx.issueInvalidPropertyValue(result.value, '$type', [this.$type])\n }\n\n return result\n }\n}\n\nexport type RecordKeySchemaOutput<Key extends LexiconRecordKey> =\n Key extends 'any'\n ? string\n : Key extends 'tid'\n ? TidString\n : Key extends 'nsid'\n ? NsidString\n : Key extends `literal:${infer L extends string}`\n ? L\n : never\n\nexport type RecordKeySchema<Key extends LexiconRecordKey> = Schema<\n RecordKeySchemaOutput<Key>\n>\n\nconst keySchema = string({ minLength: 1 })\nconst tidSchema = string({ format: 'tid' })\nconst nsidSchema = string({ format: 'nsid' })\nconst selfLiteralSchema = literal('self')\n\nfunction recordKey<Key extends LexiconRecordKey>(\n key: Key,\n): RecordKeySchema<Key> {\n // @NOTE Use cached instances for common schemas\n if (key === 'any') return keySchema as any\n if (key === 'tid') return tidSchema as any\n if (key === 'nsid') return nsidSchema as any\n if (key.startsWith('literal:')) {\n const value = key.slice(8) as RecordKeySchemaOutput<Key>\n if (value === 'self') return selfLiteralSchema as any\n return literal(value)\n }\n\n throw new Error(`Unsupported record key type: ${key}`)\n}\n\n/**\n * Ensures that a `$type` used in a record is a valid NSID (i.e. no fragment).\n */\ntype AsNsid<T> = T extends `${string}#${string}` ? never : T\n\n/**\n * Creates a record schema for AT Protocol records.\n *\n * Records are the primary data unit in AT Protocol repositories. They have\n * a `$type` field identifying their Lexicon schema, and are stored at keys\n * following a specific format (TID, NSID, etc.).\n *\n * This function offers two overloads:\n * - One that infers the output type from the provided arguments (does not\n * support circular references)\n * - One with an explicitly defined interface for use with codegen and\n * circular references\n *\n * @param key - The record key type: 'tid', 'nsid', 'any', or 'literal:value'\n * @param type - The NSID identifying this record type (e.g., 'app.bsky.feed.post')\n * @param validator - Schema validator for the record's properties\n * @returns A new {@link RecordSchema} instance\n *\n * @example\n * ```ts\n * // Post record with TID key\n * const postSchema = l.record('tid', 'app.bsky.feed.post', l.object({\n * text: l.string({ maxGraphemes: 300 }),\n * createdAt: l.string({ format: 'datetime' }),\n * reply: l.optional(l.object({\n * root: l.ref(() => strongRefSchema),\n * parent: l.ref(() => strongRefSchema),\n * })),\n * }))\n *\n * // Profile record with literal 'self' key\n * const profileSchema = l.record('literal:self', 'app.bsky.actor.profile', l.object({\n * displayName: l.optional(l.string({ maxGraphemes: 64 })),\n * description: l.optional(l.string({ maxGraphemes: 256 })),\n * avatar: l.optional(l.blob({ accept: ['image/*'] })),\n * }))\n *\n * // Build a record with automatic $type injection\n * const post = postSchema.build({ text: 'Hello!', createdAt: new Date().toISOString() })\n * ```\n */\nexport function record<\n const K extends LexiconRecordKey,\n const T extends NsidString,\n const S extends Validator<{ [k: string]: unknown }>,\n>(key: K, type: AsNsid<T>, validator: S): RecordSchema<K, T, S>\nexport function record<\n const K extends LexiconRecordKey,\n const V extends { $type: NsidString },\n>(\n key: K,\n type: AsNsid<V['$type']>,\n validator: Validator<Omit<V, '$type'>>,\n): RecordSchema<K, V['$type'], Validator<Omit<V, '$type'>>>\n/*@__NO_SIDE_EFFECTS__*/\nexport function record<\n const K extends LexiconRecordKey,\n const T extends NsidString,\n const S extends Validator<{ [k: string]: unknown }>,\n>(key: K, type: T, validator: S) {\n return new RecordSchema<K, T, S>(key, type, validator)\n}\n"]}
@@ -24,6 +24,7 @@ export type RefSchemaGetter<out TValidator extends Validator> = () => TValidator
24
24
  */
25
25
  export declare class RefSchema<const TValidator extends Validator> extends Schema<InferInput<TValidator>, InferOutput<TValidator>, TValidator['__lex']> implements WrappedValidator<TValidator> {
26
26
  #private;
27
+ readonly type: "ref";
27
28
  constructor(getter: RefSchemaGetter<TValidator>);
28
29
  get validator(): TValidator;
29
30
  unwrap(): TValidator;
@@ -1 +1 @@
1
- {"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../../src/schema/ref.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,MAAM,EACN,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAEnB;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,GAAG,CAAC,UAAU,SAAS,SAAS,IAAI,MAAM,UAAU,CAAA;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,SAAS,CAAC,KAAK,CAAC,UAAU,SAAS,SAAS,CACvD,SAAQ,MAAM,CACZ,UAAU,CAAC,UAAU,CAAC,EACtB,WAAW,CAAC,UAAU,CAAC,EACvB,UAAU,CAAC,OAAO,CAAC,CAErB,YAAW,gBAAgB,CAAC,UAAU,CAAC;;gBAI3B,MAAM,EAAE,eAAe,CAAC,UAAU,CAAC;IAS/C,IAAI,SAAS,IAAI,UAAU,CAE1B;IAED,MAAM,IAAI,UAAU;IAIpB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB;CAGzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,wBAAgB,GAAG,CAAC,KAAK,CAAC,UAAU,SAAS,SAAS,EACpD,GAAG,EAAE,eAAe,CAAC,UAAU,CAAC,GAC/B,SAAS,CAAC,UAAU,CAAC,CAAA;AACxB,wBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EACzD,GAAG,EAAE,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC/C,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../../src/schema/ref.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,MAAM,EACN,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAEnB;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,GAAG,CAAC,UAAU,SAAS,SAAS,IAAI,MAAM,UAAU,CAAA;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,SAAS,CAAC,KAAK,CAAC,UAAU,SAAS,SAAS,CACvD,SAAQ,MAAM,CACZ,UAAU,CAAC,UAAU,CAAC,EACtB,WAAW,CAAC,UAAU,CAAC,EACvB,UAAU,CAAC,OAAO,CAAC,CAErB,YAAW,gBAAgB,CAAC,UAAU,CAAC;;IAEvC,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAS;gBAIlB,MAAM,EAAE,eAAe,CAAC,UAAU,CAAC;IAS/C,IAAI,SAAS,IAAI,UAAU,CAE1B;IAED,MAAM,IAAI,UAAU;IAIpB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB;CAGzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,wBAAgB,GAAG,CAAC,KAAK,CAAC,UAAU,SAAS,SAAS,EACpD,GAAG,EAAE,eAAe,CAAC,UAAU,CAAC,GAC/B,SAAS,CAAC,UAAU,CAAC,CAAA;AACxB,wBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EACzD,GAAG,EAAE,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC/C,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA"}
@@ -21,6 +21,7 @@ const core_js_1 = require("../core.js");
21
21
  * ```
22
22
  */
23
23
  class RefSchema extends core_js_1.Schema {
24
+ type = 'ref';
24
25
  #getter;
25
26
  constructor(getter) {
26
27
  // @NOTE In order to avoid circular dependency issues, we don't resolve