@bigmistqke/lexicon-to-valibot 0.1.0

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.
@@ -0,0 +1,221 @@
1
+ import * as v from 'valibot';
2
+ export { InferOutput } from 'valibot';
3
+ export { LexUserType, LexiconDoc } from '@atproto/lexicon';
4
+
5
+ interface QueryValidators {
6
+ parameters: v.GenericSchema;
7
+ output: v.GenericSchema;
8
+ }
9
+ interface ProcedureValidators {
10
+ parameters: v.GenericSchema;
11
+ input: v.GenericSchema;
12
+ output: v.GenericSchema;
13
+ }
14
+ interface SubscriptionValidators {
15
+ parameters: v.GenericSchema;
16
+ message: v.GenericSchema;
17
+ }
18
+
19
+ type Prettify<T> = {
20
+ [K in keyof T]: T[K];
21
+ } & {};
22
+ type TypedBlobRef = {
23
+ $type: "blob";
24
+ ref: {
25
+ $link: string;
26
+ };
27
+ mimeType: string;
28
+ size: number;
29
+ };
30
+ type UntypedBlobRef = {
31
+ cid: string;
32
+ mimeType: string;
33
+ };
34
+ type BlobRef = TypedBlobRef | UntypedBlobRef;
35
+ type CidLink = {
36
+ $link: string;
37
+ };
38
+ type ExternalRefsMap = Record<string, unknown>;
39
+ type InferLexType<T, Defs = {}, ExtRefs extends ExternalRefsMap = {}> = T extends {
40
+ type: "boolean";
41
+ } ? T extends {
42
+ const: infer C extends boolean;
43
+ } ? C : boolean : T extends {
44
+ type: "integer";
45
+ } ? T extends {
46
+ const: infer C extends number;
47
+ } ? C : T extends {
48
+ enum: infer E extends readonly number[];
49
+ } ? E[number] : number : T extends {
50
+ type: "string";
51
+ } ? T extends {
52
+ const: infer C extends string;
53
+ } ? C : T extends {
54
+ enum: infer E extends readonly string[];
55
+ } ? E[number] : string : T extends {
56
+ type: "unknown";
57
+ } ? unknown : T extends {
58
+ type: "bytes";
59
+ } ? Uint8Array : T extends {
60
+ type: "blob";
61
+ } ? BlobRef : T extends {
62
+ type: "cid-link";
63
+ } ? CidLink : T extends {
64
+ type: "token";
65
+ } ? string : T extends {
66
+ type: "array";
67
+ items: infer Items;
68
+ } ? InferLexType<Items, Defs, ExtRefs>[] : T extends {
69
+ type: "object";
70
+ properties?: infer Props;
71
+ } ? InferLexObject<Props, T, Defs, ExtRefs> : T extends {
72
+ type: "ref";
73
+ ref: infer R extends string;
74
+ } ? InferLexRef<R, Defs, ExtRefs> : T extends {
75
+ type: "union";
76
+ refs: infer Refs extends readonly string[];
77
+ } ? InferLexUnion<Refs, Defs, ExtRefs> : T extends {
78
+ type: "record";
79
+ record: infer Rec;
80
+ } ? InferLexType<Rec, Defs, ExtRefs> : unknown;
81
+ type InferLexObject<Props, Schema, Defs, ExtRefs extends ExternalRefsMap = {}> = Props extends Record<string, unknown> ? Prettify<{
82
+ [K in keyof Props as K extends RequiredKeys<Schema> ? K extends NullableKeys<Schema> ? never : K : never]: InferLexType<Props[K], Defs, ExtRefs>;
83
+ } & {
84
+ [K in keyof Props as K extends RequiredKeys<Schema> ? K extends NullableKeys<Schema> ? K : never : never]: InferLexType<Props[K], Defs, ExtRefs> | null;
85
+ } & {
86
+ [K in keyof Props as K extends RequiredKeys<Schema> ? never : K extends NullableKeys<Schema> ? never : K]?: InferLexType<Props[K], Defs, ExtRefs>;
87
+ } & {
88
+ [K in keyof Props as K extends RequiredKeys<Schema> ? never : K extends NullableKeys<Schema> ? K : never]?: InferLexType<Props[K], Defs, ExtRefs> | null;
89
+ }> : {};
90
+ type RequiredKeys<T> = T extends {
91
+ required: infer R extends readonly string[];
92
+ } ? R[number] : never;
93
+ type NullableKeys<T> = T extends {
94
+ nullable: infer N extends readonly string[];
95
+ } ? N[number] : never;
96
+ type InferLexRef<R extends string, Defs, ExtRefs extends ExternalRefsMap = {}> = R extends `#${infer DefName}` ? DefName extends keyof Defs ? InferLexType<Defs[DefName], Defs, ExtRefs> : unknown : R extends keyof ExtRefs ? ExtRefs[R] : `${R}#main` extends keyof ExtRefs ? ExtRefs[`${R}#main`] : unknown;
97
+ type InferLexUnion<Refs extends readonly string[], Defs, ExtRefs extends ExternalRefsMap = {}> = Refs extends readonly [
98
+ infer First extends string,
99
+ ...infer Rest extends readonly string[]
100
+ ] ? InferLexRef<First, Defs, ExtRefs> | InferLexUnion<Rest, Defs, ExtRefs> : never;
101
+ type InferLexParams<T, Defs, ExtRefs extends ExternalRefsMap = {}> = T extends {
102
+ type: "params";
103
+ properties?: infer Props;
104
+ required?: infer R extends readonly string[];
105
+ } ? Props extends Record<string, unknown> ? Prettify<{
106
+ [K in keyof Props as K extends R[number] ? K : never]: InferLexType<Props[K], Defs, ExtRefs>;
107
+ } & {
108
+ [K in keyof Props as K extends R[number] ? never : K]?: InferLexType<Props[K], Defs, ExtRefs>;
109
+ }> : {} : {};
110
+ type InferLexBody<T, Defs, ExtRefs extends ExternalRefsMap = {}> = T extends {
111
+ schema: infer S;
112
+ } ? InferLexType<S, Defs, ExtRefs> : unknown;
113
+ type InferQueryValidators<T, Defs, ExtRefs extends ExternalRefsMap = {}> = T extends {
114
+ type: "query";
115
+ } ? {
116
+ parameters: v.GenericSchema<InferLexParams<T extends {
117
+ parameters: infer P;
118
+ } ? P : never, Defs, ExtRefs>>;
119
+ output: v.GenericSchema<InferLexBody<T extends {
120
+ output: infer O;
121
+ } ? O : never, Defs, ExtRefs>>;
122
+ } : never;
123
+ type InferProcedureValidators<T, Defs, ExtRefs extends ExternalRefsMap = {}> = T extends {
124
+ type: "procedure";
125
+ } ? {
126
+ parameters: v.GenericSchema<InferLexParams<T extends {
127
+ parameters: infer P;
128
+ } ? P : never, Defs, ExtRefs>>;
129
+ input: v.GenericSchema<InferLexBody<T extends {
130
+ input: infer I;
131
+ } ? I : never, Defs, ExtRefs>>;
132
+ output: v.GenericSchema<InferLexBody<T extends {
133
+ output: infer O;
134
+ } ? O : never, Defs, ExtRefs>>;
135
+ } : never;
136
+ type InferSubscriptionValidators<T, Defs, ExtRefs extends ExternalRefsMap = {}> = T extends {
137
+ type: "subscription";
138
+ } ? {
139
+ parameters: v.GenericSchema<InferLexParams<T extends {
140
+ parameters: infer P;
141
+ } ? P : never, Defs, ExtRefs>>;
142
+ message: v.GenericSchema<InferLexBody<T extends {
143
+ message: infer M;
144
+ } ? M : never, Defs, ExtRefs>>;
145
+ } : never;
146
+ type IsXrpcType<T> = T extends {
147
+ type: "query" | "procedure" | "subscription";
148
+ } ? true : false;
149
+ type InferSchemaValidator<T, Defs, ExtRefs extends ExternalRefsMap = {}> = v.GenericSchema<InferLexType<T, Defs, ExtRefs>>;
150
+ type InferXrpcValidator<T, Defs, ExtRefs extends ExternalRefsMap = {}> = T extends {
151
+ type: "query";
152
+ } ? InferQueryValidators<T, Defs, ExtRefs> : T extends {
153
+ type: "procedure";
154
+ } ? InferProcedureValidators<T, Defs, ExtRefs> : T extends {
155
+ type: "subscription";
156
+ } ? InferSubscriptionValidators<T, Defs, ExtRefs> : never;
157
+ type InferLexiconValidators<T extends {
158
+ defs: Record<string, unknown>;
159
+ }, ExtRefs extends ExternalRefsMap = {}> = {
160
+ [K in keyof T["defs"] as IsXrpcType<T["defs"][K]> extends true ? never : K]: InferSchemaValidator<T["defs"][K], T["defs"], ExtRefs>;
161
+ };
162
+ type InferXrpcValidators<T extends {
163
+ defs: Record<string, unknown>;
164
+ }, ExtRefs extends ExternalRefsMap = {}> = {
165
+ [K in keyof T["defs"] as IsXrpcType<T["defs"][K]> extends true ? K : never]: InferXrpcValidator<T["defs"][K], T["defs"], ExtRefs>;
166
+ };
167
+ type InferLexiconOutput<T extends {
168
+ defs: Record<string, unknown>;
169
+ }, K extends keyof T["defs"], ExtRefs extends ExternalRefsMap = {}> = InferLexType<T["defs"][K], T["defs"], ExtRefs>;
170
+
171
+ declare const atprotoRefs: {
172
+ readonly "com.atproto.repo.strongRef": v.ObjectSchema<{
173
+ readonly uri: v.StringSchema<undefined>;
174
+ readonly cid: v.StringSchema<undefined>;
175
+ }, undefined>;
176
+ readonly "com.atproto.repo.strongRef#main": v.ObjectSchema<{
177
+ readonly uri: v.StringSchema<undefined>;
178
+ readonly cid: v.StringSchema<undefined>;
179
+ }, undefined>;
180
+ readonly "com.atproto.label.defs#selfLabel": v.ObjectSchema<{
181
+ readonly val: v.StringSchema<undefined>;
182
+ }, undefined>;
183
+ readonly "com.atproto.label.defs#selfLabels": v.ObjectSchema<{
184
+ readonly values: v.ArraySchema<v.ObjectSchema<{
185
+ readonly val: v.StringSchema<undefined>;
186
+ }, undefined>, undefined>;
187
+ }, undefined>;
188
+ };
189
+ type AtprotoRefs = typeof atprotoRefs;
190
+
191
+ interface LexiconInput {
192
+ lexicon: 1;
193
+ id: string;
194
+ defs: Record<string, unknown>;
195
+ description?: string;
196
+ revision?: number;
197
+ }
198
+ interface LexiconToValibotOptions {
199
+ /** External ref schemas (e.g., com.atproto.repo.strongRef) */
200
+ externalRefs?: Record<string, v.GenericSchema>;
201
+ }
202
+
203
+ type InferSchemaOutputs<T extends Record<string, v.GenericSchema>> = {
204
+ [K in keyof T]: v.InferOutput<T[K]>;
205
+ };
206
+ /**
207
+ * Convert a lexicon to valibot schemas for records and objects.
208
+ * Skips XRPC types (query, procedure, subscription) - use xrpcToValibot for those.
209
+ */
210
+ declare function lexiconToValibot<T extends LexiconInput, ExtRefs extends Record<string, v.GenericSchema> = {}>(lexicon: T, options?: {
211
+ externalRefs?: ExtRefs;
212
+ }): InferLexiconValidators<T, InferSchemaOutputs<ExtRefs>>;
213
+ /**
214
+ * Convert a lexicon to valibot validators for XRPC endpoints.
215
+ * Only handles query, procedure, and subscription types.
216
+ */
217
+ declare function xrpcToValibot<T extends LexiconInput, ExtRefs extends Record<string, v.GenericSchema> = {}>(lexicon: T, options?: {
218
+ externalRefs?: ExtRefs;
219
+ }): InferXrpcValidators<T, InferSchemaOutputs<ExtRefs>>;
220
+
221
+ export { type AtprotoRefs, type InferLexType, type InferLexiconOutput, type InferLexiconValidators, type LexiconInput, type LexiconToValibotOptions, type ProcedureValidators, type QueryValidators, type SubscriptionValidators, atprotoRefs, lexiconToValibot, xrpcToValibot };
package/dist/index.js ADDED
@@ -0,0 +1,412 @@
1
+ // src/index.ts
2
+ import * as v6 from "valibot";
3
+
4
+ // src/converters/atproto.ts
5
+ import * as v from "valibot";
6
+ var typedBlobRef = v.object({
7
+ $type: v.literal("blob"),
8
+ ref: v.object({ $link: v.string() }),
9
+ mimeType: v.string(),
10
+ size: v.number()
11
+ });
12
+ var untypedBlobRef = v.object({
13
+ cid: v.string(),
14
+ mimeType: v.string()
15
+ });
16
+ var blobRefSchema = v.union([typedBlobRef, untypedBlobRef]);
17
+ function convertBlob(schema) {
18
+ return blobRefSchema;
19
+ }
20
+ var cidLinkSchema = v.object({
21
+ $link: v.string()
22
+ });
23
+ function convertCidLink(_schema) {
24
+ return cidLinkSchema;
25
+ }
26
+ function convertToken(schema) {
27
+ return v.string();
28
+ }
29
+
30
+ // src/converters/complex.ts
31
+ import * as v2 from "valibot";
32
+ function convertArray(schema, ctx, convertType2) {
33
+ const itemsSchema = convertType2(schema.items, ctx);
34
+ const checks = [];
35
+ if (schema.minLength !== void 0) {
36
+ checks.push(v2.minLength(schema.minLength));
37
+ }
38
+ if (schema.maxLength !== void 0) {
39
+ checks.push(v2.maxLength(schema.maxLength));
40
+ }
41
+ if (checks.length === 0) {
42
+ return v2.array(itemsSchema);
43
+ }
44
+ return v2.pipe(v2.array(itemsSchema), ...checks);
45
+ }
46
+ function convertObject(schema, ctx, convertType2) {
47
+ const properties = {};
48
+ const requiredSet = new Set(schema.required ?? []);
49
+ const nullableSet = new Set(schema.nullable ?? []);
50
+ if (schema.properties) {
51
+ for (const [key, prop] of Object.entries(schema.properties)) {
52
+ let propSchema = convertType2(prop, ctx);
53
+ if (nullableSet.has(key)) {
54
+ propSchema = v2.nullable(propSchema);
55
+ }
56
+ if (!requiredSet.has(key)) {
57
+ propSchema = v2.optional(propSchema);
58
+ }
59
+ properties[key] = propSchema;
60
+ }
61
+ }
62
+ return v2.object(properties);
63
+ }
64
+ function convertRef(schema, ctx) {
65
+ return v2.lazy(() => ctx.resolveRef(schema.ref));
66
+ }
67
+ function convertUnion(schema, ctx) {
68
+ if (schema.refs.length === 0) {
69
+ return v2.never();
70
+ }
71
+ if (schema.refs.length === 1) {
72
+ return v2.lazy(() => ctx.resolveRef(schema.refs[0]));
73
+ }
74
+ const [first, second, ...rest] = schema.refs.map(
75
+ (ref) => v2.lazy(() => ctx.resolveRef(ref))
76
+ );
77
+ return v2.union([first, second, ...rest]);
78
+ }
79
+
80
+ // src/converters/primitives.ts
81
+ import * as v3 from "valibot";
82
+ function convertBoolean(schema) {
83
+ if (schema.const !== void 0) {
84
+ return v3.literal(schema.const);
85
+ }
86
+ return v3.boolean();
87
+ }
88
+ function convertInteger(schema) {
89
+ const checks = [v3.integer()];
90
+ if (schema.minimum !== void 0) {
91
+ checks.push(v3.minValue(schema.minimum));
92
+ }
93
+ if (schema.maximum !== void 0) {
94
+ checks.push(v3.maxValue(schema.maximum));
95
+ }
96
+ if (schema.enum !== void 0 && schema.enum.length > 0) {
97
+ return v3.picklist(schema.enum);
98
+ }
99
+ if (schema.const !== void 0) {
100
+ return v3.literal(schema.const);
101
+ }
102
+ return v3.pipe(v3.number(), ...checks);
103
+ }
104
+ var graphemeSegmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
105
+ function countGraphemes(str) {
106
+ return [...graphemeSegmenter.segment(str)].length;
107
+ }
108
+ function convertString(schema) {
109
+ const checks = [];
110
+ if (schema.minLength !== void 0) {
111
+ checks.push(v3.minLength(schema.minLength));
112
+ }
113
+ if (schema.maxLength !== void 0) {
114
+ checks.push(v3.maxLength(schema.maxLength));
115
+ }
116
+ if (schema.minGraphemes !== void 0) {
117
+ const min = schema.minGraphemes;
118
+ checks.push(
119
+ v3.check(
120
+ (value) => countGraphemes(value) >= min,
121
+ `String must have at least ${min} grapheme(s)`
122
+ )
123
+ );
124
+ }
125
+ if (schema.maxGraphemes !== void 0) {
126
+ const max = schema.maxGraphemes;
127
+ checks.push(
128
+ v3.check(
129
+ (value) => countGraphemes(value) <= max,
130
+ `String must have at most ${max} grapheme(s)`
131
+ )
132
+ );
133
+ }
134
+ if (schema.enum !== void 0 && schema.enum.length > 0) {
135
+ return v3.picklist(schema.enum);
136
+ }
137
+ if (schema.const !== void 0) {
138
+ return v3.literal(schema.const);
139
+ }
140
+ if (schema.format !== void 0) {
141
+ switch (schema.format) {
142
+ case "datetime":
143
+ checks.push(v3.isoTimestamp());
144
+ break;
145
+ case "uri":
146
+ checks.push(v3.url());
147
+ break;
148
+ case "at-uri":
149
+ checks.push(v3.regex(/^at:\/\/[a-zA-Z0-9._:%-]+\/[a-zA-Z0-9.]+\/[a-zA-Z0-9._~:@!$&')(*+,;=-]+$/));
150
+ break;
151
+ case "did":
152
+ checks.push(v3.regex(/^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$/));
153
+ break;
154
+ case "handle":
155
+ checks.push(v3.regex(/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/));
156
+ break;
157
+ case "nsid":
158
+ checks.push(v3.regex(/^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z]{0,61}[a-zA-Z])?)$/));
159
+ break;
160
+ case "cid":
161
+ checks.push(v3.regex(/^[a-zA-Z0-9+/=]+$/));
162
+ break;
163
+ case "tid":
164
+ checks.push(v3.regex(/^[234567abcdefghijklmnopqrstuvwxyz]{13}$/));
165
+ break;
166
+ case "record-key":
167
+ checks.push(v3.regex(/^[a-zA-Z0-9._:~-]+$/));
168
+ break;
169
+ case "language":
170
+ checks.push(v3.regex(/^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/));
171
+ break;
172
+ case "at-identifier":
173
+ checks.push(v3.regex(/^(did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]|([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)$/));
174
+ break;
175
+ }
176
+ }
177
+ if (checks.length === 0) {
178
+ return v3.string();
179
+ }
180
+ return v3.pipe(v3.string(), ...checks);
181
+ }
182
+ function convertUnknown(_schema) {
183
+ return v3.unknown();
184
+ }
185
+ function convertBytes(schema) {
186
+ const baseSchema = v3.instance(Uint8Array);
187
+ if (schema.minLength === void 0 && schema.maxLength === void 0) {
188
+ return baseSchema;
189
+ }
190
+ return v3.pipe(
191
+ baseSchema,
192
+ v3.check((value) => {
193
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
194
+ return false;
195
+ }
196
+ if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
197
+ return false;
198
+ }
199
+ return true;
200
+ }, `Bytes length must be between ${schema.minLength ?? 0} and ${schema.maxLength ?? "\u221E"}`)
201
+ );
202
+ }
203
+
204
+ // src/converters/xrpc.ts
205
+ import * as v4 from "valibot";
206
+ function convertParams(params, ctx, convertType2) {
207
+ if (!params?.properties) {
208
+ return v4.object({});
209
+ }
210
+ const properties = {};
211
+ const requiredSet = new Set(params.required ?? []);
212
+ for (const [key, prop] of Object.entries(params.properties)) {
213
+ let propSchema = convertType2(prop, ctx);
214
+ if (!requiredSet.has(key)) {
215
+ propSchema = v4.optional(propSchema);
216
+ }
217
+ properties[key] = propSchema;
218
+ }
219
+ return v4.object(properties);
220
+ }
221
+ function convertBody(body, ctx, convertType2) {
222
+ if (!body?.schema) {
223
+ return v4.unknown();
224
+ }
225
+ return convertType2(body.schema, ctx);
226
+ }
227
+ function convertQuery(schema, ctx, convertType2) {
228
+ return {
229
+ parameters: convertParams(schema.parameters, ctx, convertType2),
230
+ output: convertBody(schema.output, ctx, convertType2)
231
+ };
232
+ }
233
+ function convertProcedure(schema, ctx, convertType2) {
234
+ return {
235
+ parameters: convertParams(schema.parameters, ctx, convertType2),
236
+ input: convertBody(schema.input, ctx, convertType2),
237
+ output: convertBody(schema.output, ctx, convertType2)
238
+ };
239
+ }
240
+ function convertSubscription(schema, ctx, convertType2) {
241
+ return {
242
+ parameters: convertParams(schema.parameters, ctx, convertType2),
243
+ message: convertBody(schema.message, ctx, convertType2)
244
+ };
245
+ }
246
+
247
+ // src/atproto-refs.ts
248
+ import * as v5 from "valibot";
249
+ var strongRef = v5.object({
250
+ uri: v5.string(),
251
+ cid: v5.string()
252
+ });
253
+ var selfLabel = v5.object({
254
+ val: v5.string()
255
+ });
256
+ var selfLabels = v5.object({
257
+ values: v5.array(selfLabel)
258
+ });
259
+ var atprotoRefs = {
260
+ "com.atproto.repo.strongRef": strongRef,
261
+ "com.atproto.repo.strongRef#main": strongRef,
262
+ "com.atproto.label.defs#selfLabel": selfLabel,
263
+ "com.atproto.label.defs#selfLabels": selfLabels
264
+ };
265
+
266
+ // src/index.ts
267
+ function convertType(schema, ctx) {
268
+ if (typeof schema !== "object" || schema === null) {
269
+ throw new Error(`Invalid schema: expected object, got ${typeof schema}`);
270
+ }
271
+ const schemaObj = schema;
272
+ switch (schemaObj.type) {
273
+ // Primitives
274
+ case "boolean":
275
+ return convertBoolean(schema);
276
+ case "integer":
277
+ return convertInteger(schema);
278
+ case "string":
279
+ return convertString(schema);
280
+ case "unknown":
281
+ return convertUnknown(schema);
282
+ // IPLD types
283
+ case "bytes":
284
+ return convertBytes(schema);
285
+ case "cid-link":
286
+ return convertCidLink(schema);
287
+ // AT Protocol types
288
+ case "blob":
289
+ return convertBlob(schema);
290
+ case "token":
291
+ return convertToken(schema);
292
+ // Complex types
293
+ case "array":
294
+ return convertArray(schema, ctx, convertType);
295
+ case "object":
296
+ return convertObject(schema, ctx, convertType);
297
+ case "ref":
298
+ return convertRef(schema, ctx);
299
+ case "union":
300
+ return convertUnion(schema, ctx);
301
+ // Record type
302
+ case "record":
303
+ return convertObject(schema.record, ctx, convertType);
304
+ default:
305
+ throw new Error(`Unknown schema type: ${schemaObj.type}`);
306
+ }
307
+ }
308
+ function convertXrpcDef(schema, ctx) {
309
+ if (typeof schema !== "object" || schema === null) {
310
+ throw new Error(`Invalid schema: expected object, got ${typeof schema}`);
311
+ }
312
+ const schemaObj = schema;
313
+ switch (schemaObj.type) {
314
+ case "query":
315
+ return convertQuery(schema, ctx, convertType);
316
+ case "procedure":
317
+ return convertProcedure(schema, ctx, convertType);
318
+ case "subscription":
319
+ return convertSubscription(schema, ctx, convertType);
320
+ default:
321
+ throw new Error(`Not an XRPC type: ${schemaObj.type}`);
322
+ }
323
+ }
324
+ function isXrpcDef(schema) {
325
+ if (typeof schema !== "object" || schema === null) return false;
326
+ const type = schema.type;
327
+ return type === "query" || type === "procedure" || type === "subscription";
328
+ }
329
+ function createRefResolver(lexiconId, defs, cache, externalRefs = {}) {
330
+ return (ref) => {
331
+ let resolvedRef = ref;
332
+ if (ref.startsWith("#")) {
333
+ resolvedRef = `${lexiconId}${ref}`;
334
+ } else if (!ref.includes("#")) {
335
+ resolvedRef = `${ref}#main`;
336
+ }
337
+ if (cache.has(resolvedRef)) {
338
+ return cache.get(resolvedRef);
339
+ }
340
+ if (externalRefs[ref]) {
341
+ cache.set(resolvedRef, externalRefs[ref]);
342
+ return externalRefs[ref];
343
+ }
344
+ if (externalRefs[resolvedRef]) {
345
+ cache.set(resolvedRef, externalRefs[resolvedRef]);
346
+ return externalRefs[resolvedRef];
347
+ }
348
+ const [nsid, defName] = resolvedRef.includes("#") ? resolvedRef.split("#") : [resolvedRef, "main"];
349
+ if (nsid !== lexiconId) {
350
+ console.warn(`External ref not resolved: ${ref} - provide it in externalRefs option`);
351
+ return v6.unknown();
352
+ }
353
+ const def = defs[defName];
354
+ if (!def) {
355
+ throw new Error(`Ref not found: ${ref} (resolved to ${resolvedRef})`);
356
+ }
357
+ const ctx = {
358
+ lexiconId,
359
+ defs,
360
+ resolveRef: createRefResolver(lexiconId, defs, cache, externalRefs)
361
+ };
362
+ const schema = convertType(def, ctx);
363
+ cache.set(resolvedRef, schema);
364
+ return schema;
365
+ };
366
+ }
367
+ function lexiconToValibot(lexicon, options = {}) {
368
+ const cache = /* @__PURE__ */ new Map();
369
+ const resolveRef = createRefResolver(
370
+ lexicon.id,
371
+ lexicon.defs,
372
+ cache,
373
+ options.externalRefs ?? {}
374
+ );
375
+ const ctx = {
376
+ lexiconId: lexicon.id,
377
+ defs: lexicon.defs,
378
+ resolveRef
379
+ };
380
+ const result = {};
381
+ for (const [defName, def] of Object.entries(lexicon.defs)) {
382
+ if (isXrpcDef(def)) continue;
383
+ result[defName] = convertType(def, ctx);
384
+ }
385
+ return result;
386
+ }
387
+ function xrpcToValibot(lexicon, options = {}) {
388
+ const cache = /* @__PURE__ */ new Map();
389
+ const resolveRef = createRefResolver(
390
+ lexicon.id,
391
+ lexicon.defs,
392
+ cache,
393
+ options.externalRefs ?? {}
394
+ );
395
+ const ctx = {
396
+ lexiconId: lexicon.id,
397
+ defs: lexicon.defs,
398
+ resolveRef
399
+ };
400
+ const result = {};
401
+ for (const [defName, def] of Object.entries(lexicon.defs)) {
402
+ if (!isXrpcDef(def)) continue;
403
+ result[defName] = convertXrpcDef(def, ctx);
404
+ }
405
+ return result;
406
+ }
407
+ export {
408
+ atprotoRefs,
409
+ lexiconToValibot,
410
+ xrpcToValibot
411
+ };
412
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/converters/atproto.ts","../src/converters/complex.ts","../src/converters/primitives.ts","../src/converters/xrpc.ts","../src/atproto-refs.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport { convertBlob, convertCidLink, convertToken } from \"./converters/atproto.js\";\nimport { convertArray, convertObject, convertRef, convertUnion } from \"./converters/complex.js\";\nimport {\n convertBoolean,\n convertBytes,\n convertInteger,\n convertString,\n convertUnknown,\n} from \"./converters/primitives.js\";\nimport {\n convertProcedure,\n convertQuery,\n convertSubscription,\n type ProcedureValidators,\n type QueryValidators,\n type SubscriptionValidators,\n} from \"./converters/xrpc.js\";\nimport type {\n ConverterContext,\n LexArray,\n LexBlob,\n LexBoolean,\n LexBytes,\n LexCidLink,\n LexInteger,\n LexObject,\n LexRecord,\n LexRef,\n LexRefUnion,\n LexString,\n LexToken,\n LexUnknown,\n LexUserType,\n LexXrpcProcedure,\n LexXrpcQuery,\n LexXrpcSubscription\n} from \"./types.js\";\n\n// Flexible input type that accepts both LexiconDoc and const objects\nexport interface LexiconInput {\n lexicon: 1;\n id: string;\n defs: Record<string, unknown>;\n description?: string;\n revision?: number;\n}\n\n// Options for lexiconToValibot\nexport interface LexiconToValibotOptions {\n /** External ref schemas (e.g., com.atproto.repo.strongRef) */\n externalRefs?: Record<string, v.GenericSchema>;\n}\n\nexport type { ProcedureValidators, QueryValidators, SubscriptionValidators };\n\ntype XrpcResult = QueryValidators | ProcedureValidators | SubscriptionValidators;\n\nfunction convertType(schema: unknown, ctx: ConverterContext): v.GenericSchema {\n if (typeof schema !== \"object\" || schema === null) {\n throw new Error(`Invalid schema: expected object, got ${typeof schema}`);\n }\n\n const schemaObj = schema as { type?: string };\n\n switch (schemaObj.type) {\n // Primitives\n case \"boolean\":\n return convertBoolean(schema as LexBoolean);\n case \"integer\":\n return convertInteger(schema as LexInteger);\n case \"string\":\n return convertString(schema as LexString);\n case \"unknown\":\n return convertUnknown(schema as LexUnknown);\n\n // IPLD types\n case \"bytes\":\n return convertBytes(schema as LexBytes);\n case \"cid-link\":\n return convertCidLink(schema as LexCidLink);\n\n // AT Protocol types\n case \"blob\":\n return convertBlob(schema as LexBlob);\n case \"token\":\n return convertToken(schema as LexToken);\n\n // Complex types\n case \"array\":\n return convertArray(schema as LexArray, ctx, convertType);\n case \"object\":\n return convertObject(schema as LexObject, ctx, convertType);\n case \"ref\":\n return convertRef(schema as LexRef, ctx);\n case \"union\":\n return convertUnion(schema as LexRefUnion, ctx);\n\n // Record type\n case \"record\":\n return convertObject((schema as LexRecord).record, ctx, convertType);\n\n default:\n throw new Error(`Unknown schema type: ${schemaObj.type}`);\n }\n}\n\n// Convert XRPC def - returns validators object\nfunction convertXrpcDef(schema: unknown, ctx: ConverterContext): XrpcResult {\n if (typeof schema !== \"object\" || schema === null) {\n throw new Error(`Invalid schema: expected object, got ${typeof schema}`);\n }\n\n const schemaObj = schema as { type?: string };\n\n switch (schemaObj.type) {\n case \"query\":\n return convertQuery(schema as LexXrpcQuery, ctx, convertType);\n case \"procedure\":\n return convertProcedure(schema as LexXrpcProcedure, ctx, convertType);\n case \"subscription\":\n return convertSubscription(schema as LexXrpcSubscription, ctx, convertType);\n default:\n throw new Error(`Not an XRPC type: ${schemaObj.type}`);\n }\n}\n\n// Check if a def is an XRPC type\nfunction isXrpcDef(schema: unknown): boolean {\n if (typeof schema !== \"object\" || schema === null) return false;\n const type = (schema as { type?: string }).type;\n return type === \"query\" || type === \"procedure\" || type === \"subscription\";\n}\n\nfunction createRefResolver(\n lexiconId: string,\n defs: Record<string, LexUserType>,\n cache: Map<string, v.GenericSchema>,\n externalRefs: Record<string, v.GenericSchema> = {}\n): (ref: string) => v.GenericSchema {\n return (ref: string) => {\n // Parse the ref - could be:\n // - \"#defName\" (local ref)\n // - \"com.example.lexicon#defName\" (external ref)\n // - \"com.example.lexicon\" (main def of external lexicon)\n\n let resolvedRef = ref;\n\n if (ref.startsWith(\"#\")) {\n // Local ref\n resolvedRef = `${lexiconId}${ref}`;\n } else if (!ref.includes(\"#\")) {\n // External ref to main def\n resolvedRef = `${ref}#main`;\n }\n\n // Check cache first\n if (cache.has(resolvedRef)) {\n return cache.get(resolvedRef)!;\n }\n\n // Check external refs (try both original and resolved)\n if (externalRefs[ref]) {\n cache.set(resolvedRef, externalRefs[ref]);\n return externalRefs[ref];\n }\n if (externalRefs[resolvedRef]) {\n cache.set(resolvedRef, externalRefs[resolvedRef]);\n return externalRefs[resolvedRef];\n }\n\n // Parse the full ref\n const [nsid, defName] = resolvedRef.includes(\"#\")\n ? resolvedRef.split(\"#\")\n : [resolvedRef, \"main\"];\n\n // Only handle local refs\n if (nsid !== lexiconId) {\n // External ref not found in externalRefs\n console.warn(`External ref not resolved: ${ref} - provide it in externalRefs option`);\n return v.unknown();\n }\n\n const def = defs[defName];\n if (!def) {\n throw new Error(`Ref not found: ${ref} (resolved to ${resolvedRef})`);\n }\n\n // Create context for conversion\n const ctx: ConverterContext = {\n lexiconId,\n defs,\n resolveRef: createRefResolver(lexiconId, defs, cache, externalRefs),\n };\n\n // Convert and cache\n const schema = convertType(def, ctx);\n cache.set(resolvedRef, schema);\n return schema;\n };\n}\n\nimport type { InferLexiconValidators, InferXrpcValidators } from \"./infer.js\";\n\n// Helper type to convert schema map to output type map\ntype InferSchemaOutputs<T extends Record<string, v.GenericSchema>> = {\n [K in keyof T]: v.InferOutput<T[K]>;\n};\n\n/**\n * Convert a lexicon to valibot schemas for records and objects.\n * Skips XRPC types (query, procedure, subscription) - use xrpcToValibot for those.\n */\nexport function lexiconToValibot<\n T extends LexiconInput,\n ExtRefs extends Record<string, v.GenericSchema> = {}\n>(\n lexicon: T,\n options: { externalRefs?: ExtRefs } = {}\n): InferLexiconValidators<T, InferSchemaOutputs<ExtRefs>> {\n const cache = new Map<string, v.GenericSchema>();\n const resolveRef = createRefResolver(\n lexicon.id,\n lexicon.defs as Record<string, LexUserType>,\n cache,\n options.externalRefs ?? {}\n );\n\n const ctx: ConverterContext = {\n lexiconId: lexicon.id,\n defs: lexicon.defs,\n resolveRef,\n };\n\n const result: Record<string, v.GenericSchema> = {};\n\n for (const [defName, def] of Object.entries(lexicon.defs)) {\n // Skip XRPC types\n if (isXrpcDef(def)) continue;\n result[defName] = convertType(def, ctx);\n }\n\n return result as InferLexiconValidators<T, InferSchemaOutputs<ExtRefs>>;\n}\n\n/**\n * Convert a lexicon to valibot validators for XRPC endpoints.\n * Only handles query, procedure, and subscription types.\n */\nexport function xrpcToValibot<\n T extends LexiconInput,\n ExtRefs extends Record<string, v.GenericSchema> = {}\n>(\n lexicon: T,\n options: { externalRefs?: ExtRefs } = {}\n): InferXrpcValidators<T, InferSchemaOutputs<ExtRefs>> {\n const cache = new Map<string, v.GenericSchema>();\n const resolveRef = createRefResolver(\n lexicon.id,\n lexicon.defs as Record<string, LexUserType>,\n cache,\n options.externalRefs ?? {}\n );\n\n const ctx: ConverterContext = {\n lexiconId: lexicon.id,\n defs: lexicon.defs,\n resolveRef,\n };\n\n const result: Record<string, XrpcResult> = {};\n\n for (const [defName, def] of Object.entries(lexicon.defs)) {\n // Only handle XRPC types\n if (!isXrpcDef(def)) continue;\n result[defName] = convertXrpcDef(def, ctx);\n }\n\n return result as InferXrpcValidators<T, InferSchemaOutputs<ExtRefs>>;\n}\n\n// Re-export valibot's InferOutput for convenience\nexport type { InferOutput } from \"valibot\";\n// Re-export built-in AT Protocol refs\nexport { atprotoRefs, type AtprotoRefs } from \"./atproto-refs.js\";\n\n// Re-export inference types\nexport type { InferLexiconOutput, InferLexiconValidators, InferLexType } from \"./infer.js\";\n// Re-export types\nexport type { LexiconDoc, LexUserType } from \"./types.js\";\n","import * as v from \"valibot\";\nimport type { LexBlob, LexCidLink, LexToken } from \"../types.js\";\n\n// Blob reference structure used by AT Protocol\n// Can be either typed (with $type: \"blob\") or untyped (legacy format)\nconst typedBlobRef = v.object({\n $type: v.literal(\"blob\"),\n ref: v.object({ $link: v.string() }),\n mimeType: v.string(),\n size: v.number(),\n});\n\nconst untypedBlobRef = v.object({\n cid: v.string(),\n mimeType: v.string(),\n});\n\nconst blobRefSchema = v.union([typedBlobRef, untypedBlobRef]);\n\nexport function convertBlob(schema: LexBlob): v.GenericSchema {\n // For now, we validate the structure but don't enforce accept/maxSize at runtime\n // Those would require access to the actual blob data\n return blobRefSchema;\n}\n\n// CID link is represented as an object with $link property containing the CID string\nconst cidLinkSchema = v.object({\n $link: v.string(),\n});\n\nexport function convertCidLink(_schema: LexCidLink): v.GenericSchema {\n return cidLinkSchema;\n}\n\nexport function convertToken(schema: LexToken): v.GenericSchema {\n // Token is essentially a string literal representing a constant identifier\n // The value should be the full NSID#name reference\n return v.string();\n}\n","import * as v from \"valibot\";\nimport type { LexArray, LexObject, LexRef, LexRefUnion, ConverterContext } from \"../types.js\";\n\nexport function convertArray(\n schema: LexArray,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): v.GenericSchema {\n const itemsSchema = convertType(schema.items, ctx);\n\n const checks: v.PipeItem<unknown[], unknown[], v.BaseIssue<unknown>>[] = [];\n\n if (schema.minLength !== undefined) {\n checks.push(v.minLength(schema.minLength));\n }\n if (schema.maxLength !== undefined) {\n checks.push(v.maxLength(schema.maxLength));\n }\n\n if (checks.length === 0) {\n return v.array(itemsSchema);\n }\n\n return v.pipe(v.array(itemsSchema), ...checks);\n}\n\nexport function convertObject(\n schema: LexObject,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): v.GenericSchema {\n const properties: Record<string, v.GenericSchema> = {};\n const requiredSet = new Set(schema.required ?? []);\n const nullableSet = new Set(schema.nullable ?? []);\n\n if (schema.properties) {\n for (const [key, prop] of Object.entries(schema.properties)) {\n let propSchema = convertType(prop, ctx);\n\n // Handle nullable\n if (nullableSet.has(key)) {\n propSchema = v.nullable(propSchema);\n }\n\n // Handle optional (not in required list)\n if (!requiredSet.has(key)) {\n propSchema = v.optional(propSchema);\n }\n\n properties[key] = propSchema;\n }\n }\n\n return v.object(properties);\n}\n\nexport function convertRef(schema: LexRef, ctx: ConverterContext): v.GenericSchema {\n return v.lazy(() => ctx.resolveRef(schema.ref));\n}\n\nexport function convertUnion(\n schema: LexRefUnion,\n ctx: ConverterContext\n): v.GenericSchema {\n if (schema.refs.length === 0) {\n return v.never();\n }\n\n if (schema.refs.length === 1) {\n return v.lazy(() => ctx.resolveRef(schema.refs[0]));\n }\n\n // Create a union of lazy refs - we know there are at least 2 refs from the check above\n const [first, second, ...rest] = schema.refs.map((ref) =>\n v.lazy(() => ctx.resolveRef(ref))\n );\n\n return v.union([first, second, ...rest]);\n}\n","import * as v from \"valibot\";\nimport type { LexBoolean, LexInteger, LexString, LexUnknown, LexBytes } from \"../types.js\";\n\nexport function convertBoolean(schema: LexBoolean): v.GenericSchema {\n if (schema.const !== undefined) {\n return v.literal(schema.const);\n }\n return v.boolean();\n}\n\nexport function convertInteger(schema: LexInteger): v.GenericSchema {\n const checks: v.PipeItem<number, number, v.BaseIssue<unknown>>[] = [v.integer()];\n\n if (schema.minimum !== undefined) {\n checks.push(v.minValue(schema.minimum));\n }\n if (schema.maximum !== undefined) {\n checks.push(v.maxValue(schema.maximum));\n }\n\n if (schema.enum !== undefined && schema.enum.length > 0) {\n return v.picklist(schema.enum);\n }\n\n if (schema.const !== undefined) {\n return v.literal(schema.const);\n }\n\n return v.pipe(v.number(), ...checks);\n}\n\nconst graphemeSegmenter = new Intl.Segmenter(\"en\", { granularity: \"grapheme\" });\n\nfunction countGraphemes(str: string): number {\n return [...graphemeSegmenter.segment(str)].length;\n}\n\nexport function convertString(schema: LexString): v.GenericSchema {\n const checks: v.PipeItem<string, string, v.BaseIssue<unknown>>[] = [];\n\n if (schema.minLength !== undefined) {\n checks.push(v.minLength(schema.minLength));\n }\n if (schema.maxLength !== undefined) {\n checks.push(v.maxLength(schema.maxLength));\n }\n\n if (schema.minGraphemes !== undefined) {\n const min = schema.minGraphemes;\n checks.push(\n v.check(\n (value) => countGraphemes(value) >= min,\n `String must have at least ${min} grapheme(s)`\n )\n );\n }\n if (schema.maxGraphemes !== undefined) {\n const max = schema.maxGraphemes;\n checks.push(\n v.check(\n (value) => countGraphemes(value) <= max,\n `String must have at most ${max} grapheme(s)`\n )\n );\n }\n\n if (schema.enum !== undefined && schema.enum.length > 0) {\n return v.picklist(schema.enum);\n }\n\n if (schema.const !== undefined) {\n return v.literal(schema.const);\n }\n\n if (schema.format !== undefined) {\n switch (schema.format) {\n case \"datetime\":\n checks.push(v.isoTimestamp());\n break;\n case \"uri\":\n checks.push(v.url());\n break;\n case \"at-uri\":\n checks.push(v.regex(/^at:\\/\\/[a-zA-Z0-9._:%-]+\\/[a-zA-Z0-9.]+\\/[a-zA-Z0-9._~:@!$&')(*+,;=-]+$/));\n break;\n case \"did\":\n checks.push(v.regex(/^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$/));\n break;\n case \"handle\":\n checks.push(v.regex(/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/));\n break;\n case \"nsid\":\n checks.push(v.regex(/^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\\.[a-zA-Z]([a-zA-Z]{0,61}[a-zA-Z])?)$/));\n break;\n case \"cid\":\n checks.push(v.regex(/^[a-zA-Z0-9+/=]+$/));\n break;\n case \"tid\":\n checks.push(v.regex(/^[234567abcdefghijklmnopqrstuvwxyz]{13}$/));\n break;\n case \"record-key\":\n checks.push(v.regex(/^[a-zA-Z0-9._:~-]+$/));\n break;\n case \"language\":\n checks.push(v.regex(/^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/));\n break;\n case \"at-identifier\":\n // at-identifier can be a handle or a DID\n checks.push(v.regex(/^(did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]|([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)$/));\n break;\n }\n }\n\n if (checks.length === 0) {\n return v.string();\n }\n\n return v.pipe(v.string(), ...checks);\n}\n\nexport function convertUnknown(_schema: LexUnknown): v.GenericSchema {\n return v.unknown();\n}\n\nexport function convertBytes(schema: LexBytes): v.GenericSchema {\n const baseSchema = v.instance(Uint8Array);\n\n if (schema.minLength === undefined && schema.maxLength === undefined) {\n return baseSchema;\n }\n\n return v.pipe(\n baseSchema,\n v.check((value) => {\n if (schema.minLength !== undefined && value.length < schema.minLength) {\n return false;\n }\n if (schema.maxLength !== undefined && value.length > schema.maxLength) {\n return false;\n }\n return true;\n }, `Bytes length must be between ${schema.minLength ?? 0} and ${schema.maxLength ?? \"∞\"}`)\n );\n}\n","import * as v from \"valibot\";\nimport type { LexXrpcQuery, LexXrpcProcedure, LexXrpcSubscription, ConverterContext } from \"../types.js\";\n\nexport interface QueryValidators {\n parameters: v.GenericSchema;\n output: v.GenericSchema;\n}\n\nexport interface ProcedureValidators {\n parameters: v.GenericSchema;\n input: v.GenericSchema;\n output: v.GenericSchema;\n}\n\nexport interface SubscriptionValidators {\n parameters: v.GenericSchema;\n message: v.GenericSchema;\n}\n\n// Convert params object to valibot schema\nfunction convertParams(\n params: { type: \"params\"; required?: string[]; properties?: Record<string, unknown> } | undefined,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): v.GenericSchema {\n if (!params?.properties) {\n return v.object({});\n }\n\n const properties: Record<string, v.GenericSchema> = {};\n const requiredSet = new Set(params.required ?? []);\n\n for (const [key, prop] of Object.entries(params.properties)) {\n let propSchema = convertType(prop, ctx);\n\n if (!requiredSet.has(key)) {\n propSchema = v.optional(propSchema);\n }\n\n properties[key] = propSchema;\n }\n\n return v.object(properties);\n}\n\n// Convert body (input/output/message) to valibot schema\nfunction convertBody(\n body: { schema?: unknown } | undefined,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): v.GenericSchema {\n if (!body?.schema) {\n return v.unknown();\n }\n return convertType(body.schema, ctx);\n}\n\nexport function convertQuery(\n schema: LexXrpcQuery,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): QueryValidators {\n return {\n parameters: convertParams(schema.parameters, ctx, convertType),\n output: convertBody(schema.output, ctx, convertType),\n };\n}\n\nexport function convertProcedure(\n schema: LexXrpcProcedure,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): ProcedureValidators {\n return {\n parameters: convertParams(schema.parameters, ctx, convertType),\n input: convertBody(schema.input, ctx, convertType),\n output: convertBody(schema.output, ctx, convertType),\n };\n}\n\nexport function convertSubscription(\n schema: LexXrpcSubscription,\n ctx: ConverterContext,\n convertType: (type: unknown, ctx: ConverterContext) => v.GenericSchema\n): SubscriptionValidators {\n return {\n parameters: convertParams(schema.parameters, ctx, convertType),\n message: convertBody(schema.message, ctx, convertType),\n };\n}\n","// Built-in AT Protocol type validators\n// Users can spread these into externalRefs option\n\nimport * as v from \"valibot\";\n\n// com.atproto.repo.strongRef - reference to another record\nconst strongRef = v.object({\n uri: v.string(),\n cid: v.string(),\n});\n\n// com.atproto.label.selfLabel\nconst selfLabel = v.object({\n val: v.string(),\n});\n\n// com.atproto.label.selfLabels\nconst selfLabels = v.object({\n values: v.array(selfLabel),\n});\n\nexport const atprotoRefs = {\n \"com.atproto.repo.strongRef\": strongRef,\n \"com.atproto.repo.strongRef#main\": strongRef,\n \"com.atproto.label.defs#selfLabel\": selfLabel,\n \"com.atproto.label.defs#selfLabels\": selfLabels,\n} as const;\n\nexport type AtprotoRefs = typeof atprotoRefs;"],"mappings":"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","names":["v","v","convertType","v","v","convertType","v"]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@bigmistqke/lexicon-to-valibot",
3
+ "version": "0.1.0",
4
+ "description": "Convert AT Protocol Lexicon schemas to Valibot validators",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "keywords": [
18
+ "lexicon",
19
+ "valibot",
20
+ "atproto",
21
+ "bluesky",
22
+ "validation"
23
+ ],
24
+ "license": "MIT",
25
+ "peerDependencies": {
26
+ "valibot": ">=1.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@atproto/lexicon": "^0.4.0",
30
+ "tsup": "^8.0.0",
31
+ "typescript": "^5.0.0",
32
+ "valibot": "^1.0.0",
33
+ "vitest": "^2.0.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsup",
37
+ "dev": "tsup --watch",
38
+ "test": "vitest run",
39
+ "test:watch": "vitest"
40
+ }
41
+ }