diff --git a/lexicons/com/atproto/server/createAccount.json b/lexicons/com/atproto/server/createAccount.json index 4db1f31e040..d9549624741 100644 --- a/lexicons/com/atproto/server/createAccount.json +++ b/lexicons/com/atproto/server/createAccount.json @@ -17,7 +17,7 @@ "inviteCode": { "type": "string" }, "password": { "type": "string" }, "recoveryKey": { "type": "string" }, - "plcOp": { "type": "bytes" } + "plcOp": { "type": "unknown" } } } }, diff --git a/packages/api/src/client/lexicons.ts b/packages/api/src/client/lexicons.ts index df696e5d06b..4030fea961a 100644 --- a/packages/api/src/client/lexicons.ts +++ b/packages/api/src/client/lexicons.ts @@ -2512,7 +2512,7 @@ export const schemaDict = { type: 'string', }, plcOp: { - type: 'bytes', + type: 'unknown', }, }, }, diff --git a/packages/api/src/client/types/com/atproto/server/createAccount.ts b/packages/api/src/client/types/com/atproto/server/createAccount.ts index 4281128cae0..b5fb32fe90b 100644 --- a/packages/api/src/client/types/com/atproto/server/createAccount.ts +++ b/packages/api/src/client/types/com/atproto/server/createAccount.ts @@ -16,7 +16,7 @@ export interface InputSchema { inviteCode?: string password: string recoveryKey?: string - plcOp?: Uint8Array + plcOp?: {} [k: string]: unknown } diff --git a/packages/bsky/src/lexicon/lexicons.ts b/packages/bsky/src/lexicon/lexicons.ts index df696e5d06b..4030fea961a 100644 --- a/packages/bsky/src/lexicon/lexicons.ts +++ b/packages/bsky/src/lexicon/lexicons.ts @@ -2512,7 +2512,7 @@ export const schemaDict = { type: 'string', }, plcOp: { - type: 'bytes', + type: 'unknown', }, }, }, diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts index bd138919101..f82fe9ed82a 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts @@ -17,7 +17,7 @@ export interface InputSchema { inviteCode?: string password: string recoveryKey?: string - plcOp?: Uint8Array + plcOp?: {} [k: string]: unknown } diff --git a/packages/lex-cli/src/util.ts b/packages/lex-cli/src/util.ts index 6c399ab9bd8..b3fc5668a52 100644 --- a/packages/lex-cli/src/util.ts +++ b/packages/lex-cli/src/util.ts @@ -1,6 +1,6 @@ import fs from 'fs' import { join } from 'path' -import { lexiconDoc, LexiconDoc } from '@atproto/lexicon' +import { parseLexiconDoc, LexiconDoc } from '@atproto/lexicon' import { ZodError, ZodFormattedError } from 'zod' import chalk from 'chalk' import { GeneratedAPI, FileDiff } from './types' @@ -41,8 +41,7 @@ export function readLexicon(path: string): LexiconDoc { typeof (obj as LexiconDoc).lexicon === 'number' ) { try { - lexiconDoc.parse(obj) - return obj as LexiconDoc + return parseLexiconDoc(obj) } catch (e) { console.error(`Invalid lexicon`, path) if (e instanceof ZodError) { diff --git a/packages/lexicon/src/lexicons.ts b/packages/lexicon/src/lexicons.ts index 72d4ef0d5b2..29998140816 100644 --- a/packages/lexicon/src/lexicons.ts +++ b/packages/lexicon/src/lexicons.ts @@ -1,12 +1,9 @@ -import { ZodError } from 'zod' import { LexiconDoc, - lexiconDoc, LexRecord, LexXrpcProcedure, LexXrpcQuery, LexUserType, - LexiconDocMalformedError, LexiconDefNotFoundError, InvalidLexiconError, ValidationResult, @@ -32,7 +29,7 @@ export class Lexicons { docs: Map = new Map() defs: Map = new Map() - constructor(docs?: unknown[]) { + constructor(docs?: LexiconDoc[]) { if (docs?.length) { for (const doc of docs) { this.add(doc) @@ -43,24 +40,8 @@ export class Lexicons { /** * Add a lexicon doc. */ - add(doc: unknown): void { - try { - lexiconDoc.parse(doc) - } catch (e) { - if (e instanceof ZodError) { - throw new LexiconDocMalformedError( - `Failed to parse schema definition ${ - (doc as Record).id - }`, - doc, - e.issues, - ) - } else { - throw e - } - } - const validatedDoc = doc as LexiconDoc - const uri = toLexUri(validatedDoc.id) + add(doc: LexiconDoc): void { + const uri = toLexUri(doc.id) if (this.docs.has(uri)) { throw new Error(`${uri} has already been registered`) } @@ -68,10 +49,10 @@ export class Lexicons { // WARNING // mutates the object // -prf - resolveRefUris(validatedDoc, uri) + resolveRefUris(doc, uri) - this.docs.set(uri, validatedDoc) - for (const [defUri, def] of iterDefs(validatedDoc)) { + this.docs.set(uri, doc) + for (const [defUri, def] of iterDefs(doc)) { this.defs.set(defUri, def) } } diff --git a/packages/lexicon/src/types.ts b/packages/lexicon/src/types.ts index 906cd353328..5d7ed1f4a2a 100644 --- a/packages/lexicon/src/types.ts +++ b/packages/lexicon/src/types.ts @@ -415,16 +415,9 @@ export function isDiscriminatedObject( return discriminatedObject.safeParse(value).success } -export class LexiconDocMalformedError extends Error { - constructor( - message: string, - public schemaDef: unknown, - public issues?: z.ZodIssue[], - ) { - super(message) - this.schemaDef = schemaDef - this.issues = issues - } +export function parseLexiconDoc(v: unknown): LexiconDoc { + lexiconDoc.parse(v) + return v as LexiconDoc } export type ValidationResult = diff --git a/packages/lexicon/tests/_scaffolds/lexicons.ts b/packages/lexicon/tests/_scaffolds/lexicons.ts index 4057c1efd50..d0cf414ccef 100644 --- a/packages/lexicon/tests/_scaffolds/lexicons.ts +++ b/packages/lexicon/tests/_scaffolds/lexicons.ts @@ -1,4 +1,6 @@ -export default [ +import { LexiconDoc } from '../../src/index' + +const lexicons: LexiconDoc[] = [ { lexicon: 1, id: 'com.example.kitchenSink', @@ -521,3 +523,5 @@ export default [ }, }, ] + +export default lexicons diff --git a/packages/lexicon/tests/general.test.ts b/packages/lexicon/tests/general.test.ts index 5217ad49c52..685c99f40e0 100644 --- a/packages/lexicon/tests/general.test.ts +++ b/packages/lexicon/tests/general.test.ts @@ -1,5 +1,5 @@ import { CID } from 'multiformats/cid' -import { lexiconDoc, Lexicons } from '../src/index' +import { LexiconDoc, Lexicons, parseLexiconDoc } from '../src/index' import LexiconDocs from './_scaffolds/lexicons' describe('Lexicons collection', () => { @@ -97,7 +97,7 @@ describe('General validation', () => { }, } expect(() => { - lexiconDoc.parse(schema) + parseLexiconDoc(schema) }).toThrow('Required field \\"foo\\" not defined') }) it('fails when unknown fields are present', () => { @@ -113,11 +113,11 @@ describe('General validation', () => { } expect(() => { - lexiconDoc.parse(schema) + parseLexiconDoc(schema) }).toThrow("Unrecognized key(s) in object: 'foo'") }) it('fails lexicon parsing when uri is invalid', () => { - const schema = { + const schema: LexiconDoc = { lexicon: 1, id: 'com.example.invalidUri', defs: { @@ -135,7 +135,7 @@ describe('General validation', () => { }).toThrow('Uri can only have one hash segment') }) it('fails validation when ref uri has multiple hash segments', () => { - const schema = { + const schema: LexiconDoc = { lexicon: 1, id: 'com.example.invalidUri', defs: { @@ -168,7 +168,7 @@ describe('General validation', () => { }).toThrow('Uri can only have one hash segment') }) it('union handles both implicit and explicit #main', () => { - const schemas = [ + const schemas: LexiconDoc[] = [ { lexicon: 1, id: 'com.example.implicitMain', diff --git a/packages/pds/src/lexicon/lexicons.ts b/packages/pds/src/lexicon/lexicons.ts index 38af4475fb8..4030fea961a 100644 --- a/packages/pds/src/lexicon/lexicons.ts +++ b/packages/pds/src/lexicon/lexicons.ts @@ -1826,6 +1826,8 @@ export const schemaDict = { }, reason: { type: 'string', + maxGraphemes: 2000, + maxLength: 20000, }, subject: { type: 'union', @@ -2510,7 +2512,7 @@ export const schemaDict = { type: 'string', }, plcOp: { - type: 'bytes', + type: 'unknown', }, }, }, diff --git a/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts b/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts index bd138919101..f82fe9ed82a 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts @@ -17,7 +17,7 @@ export interface InputSchema { inviteCode?: string password: string recoveryKey?: string - plcOp?: Uint8Array + plcOp?: {} [k: string]: unknown } diff --git a/packages/xrpc-server/src/server.ts b/packages/xrpc-server/src/server.ts index 4e0a84ce4b7..1a258097d66 100644 --- a/packages/xrpc-server/src/server.ts +++ b/packages/xrpc-server/src/server.ts @@ -5,6 +5,7 @@ import express, { RequestHandler, } from 'express' import { + LexiconDoc, Lexicons, lexToJson, LexXrpcProcedure, @@ -45,7 +46,7 @@ import { import log from './logger' import { consumeMany } from './rate-limiter' -export function createServer(lexicons?: unknown[], options?: Options) { +export function createServer(lexicons?: LexiconDoc[], options?: Options) { return new Server(lexicons, options) } @@ -60,7 +61,7 @@ export class Server { sharedRateLimiters: Record routeRateLimiterFns: Record - constructor(lexicons?: unknown[], opts?: Options) { + constructor(lexicons?: LexiconDoc[], opts?: Options) { if (lexicons) { this.addLexicons(lexicons) } @@ -140,11 +141,11 @@ export class Server { // schemas // = - addLexicon(doc: unknown) { + addLexicon(doc: LexiconDoc) { this.lex.add(doc) } - addLexicons(docs: unknown[]) { + addLexicons(docs: LexiconDoc[]) { for (const doc of docs) { this.addLexicon(doc) } diff --git a/packages/xrpc/src/client.ts b/packages/xrpc/src/client.ts index fbb5d33662c..6603345608a 100644 --- a/packages/xrpc/src/client.ts +++ b/packages/xrpc/src/client.ts @@ -1,4 +1,4 @@ -import { Lexicons, ValidationError } from '@atproto/lexicon' +import { LexiconDoc, Lexicons, ValidationError } from '@atproto/lexicon' import { getMethodSchemaHTTPMethod, constructMethodCallUri, @@ -46,11 +46,11 @@ export class Client { // schemas // = - addLexicon(doc: unknown) { + addLexicon(doc: LexiconDoc) { this.lex.add(doc) } - addLexicons(docs: unknown[]) { + addLexicons(docs: LexiconDoc[]) { for (const doc of docs) { this.addLexicon(doc) }