An experimental TypeSpec syntax for Lexicon

Compare changes

Choose any two refs to compare.

+1
.gitignore
··· 5 5 dist/ 6 6 tsp-output/ 7 7 generated/ 8 + lexicons/ 8 9 *.tsbuildinfo 9 10 10 11 # Test outputs
+2 -2
packages/cli/package.json
··· 1 1 { 2 2 "name": "@typelex/cli", 3 - "version": "0.2.13", 3 + "version": "0.2.0", 4 + "description": "CLI for typelex - TypeSpec-based IDL for ATProto Lexicons", 4 5 "main": "dist/index.js", 5 6 "type": "module", 6 7 "bin": { ··· 26 27 "license": "MIT", 27 28 "dependencies": { 28 29 "@typespec/compiler": "^1.4.0", 29 - "picocolors": "^1.1.1", 30 30 "yargs": "^18.0.0" 31 31 }, 32 32 "devDependencies": {
+4 -53
packages/cli/src/cli.ts
··· 2 2 import yargs from "yargs"; 3 3 import { hideBin } from "yargs/helpers"; 4 4 import { compileCommand } from "./commands/compile.js"; 5 - import { initCommand } from "./commands/init.js"; 6 5 7 6 async function main() { 8 7 await yargs(hideBin(process.argv)) 9 8 .scriptName("typelex") 10 - .command( 11 - "init", 12 - "Initialize a new typelex project", 13 - (yargs) => { 14 - return yargs.option("setup", { 15 - describe: "Internal: run setup after installation", 16 - type: "boolean", 17 - hidden: true, 18 - default: false, 19 - }); 20 - }, 21 - async (argv) => { 22 - // Extract any unknown flags to pass through to package manager 23 - const flags: string[] = []; 24 - const knownFlags = new Set(["setup", "_", "$0"]); 25 - 26 - for (const [key, value] of Object.entries(argv)) { 27 - if (!knownFlags.has(key)) { 28 - // Single letter = short flag, multiple letters = long flag 29 - const prefix = key.length === 1 ? "-" : "--"; 30 - if (typeof value === "boolean" && value) { 31 - flags.push(`${prefix}${key}`); 32 - } else if (value !== false && value !== undefined) { 33 - flags.push(`${prefix}${key}`, String(value)); 34 - } 35 - } 36 - } 37 - 38 - await initCommand(argv.setup, flags); 39 - } 40 - ) 9 + .usage("$0 compile <namespace>") 41 10 .command( 42 11 "compile <namespace>", 43 12 "Compile TypeSpec files to Lexicon JSON", 44 13 (yargs) => { 45 14 return yargs 46 15 .positional("namespace", { 47 - describe: "Primary namespace pattern (e.g., com.example.*)", 16 + describe: "Primary namespace pattern (e.g., app.bsky.*)", 48 17 type: "string", 49 18 demandOption: true, 50 19 }) 51 20 .option("out", { 52 - describe: "Output directory for generated Lexicon files (must end with 'lexicons')", 21 + describe: "Output directory for generated Lexicon files (relative to cwd)", 53 22 type: "string", 54 23 default: "./lexicons", 55 24 }); 56 25 }, 57 26 async (argv) => { 58 - if (!argv.namespace) { 59 - console.error("Error: namespace is required"); 60 - console.error("Usage: typelex compile <namespace>"); 61 - console.error("Example: typelex compile com.example.*"); 62 - process.exit(1); 63 - } 64 - 65 - if (!argv.namespace.endsWith(".*")) { 66 - console.error("Error: namespace must end with .*"); 67 - console.error(`Got: ${argv.namespace}`); 68 - console.error("Example: typelex compile com.example.*"); 69 - process.exit(1); 70 - } 71 - 72 27 const options: Record<string, unknown> = {}; 73 28 if (argv.watch) { 74 29 options.watch = true; ··· 84 39 type: "boolean", 85 40 default: false, 86 41 }) 87 - .demandCommand(1) 42 + .demandCommand(1, "You must specify a command") 88 43 .help() 89 44 .version() 90 45 .fail((msg, err) => { 91 46 if (err) { 92 47 console.error(err); 93 - } else if (msg.includes("Not enough non-option arguments")) { 94 - console.error("Error: namespace is required"); 95 - console.error("Usage: typelex compile <namespace>"); 96 - console.error("Example: typelex compile com.example.*"); 97 48 } else { 98 49 console.error(msg); 99 50 }
+1 -5
packages/cli/src/commands/compile.ts
··· 33 33 34 34 // Compile TypeSpec using the TypeSpec CLI 35 35 const entrypoint = resolve(cwd, "typelex/main.tsp"); 36 - 37 - // Normalize path for TypeSpec (remove leading ./) 38 - const normalizedOutDir = outDir.replace(/^\.\//, ''); 39 - 40 36 const args = [ 41 37 "compile", 42 38 entrypoint, 43 39 "--emit", 44 40 "@typelex/emitter", 45 41 "--option", 46 - `@typelex/emitter.emitter-output-dir={project-root}/${normalizedOutDir}`, 42 + `@typelex/emitter.emitter-output-dir={project-root}/${outDir}`, 47 43 ]; 48 44 49 45 if (options.watch) {
-277
packages/cli/src/commands/init.ts
··· 1 - import { resolve, relative } from "path"; 2 - import { mkdir, writeFile, readFile, access, stat } from "fs/promises"; 3 - import { spawn } from "child_process"; 4 - import { createInterface } from "readline"; 5 - import pc from "picocolors"; 6 - 7 - function gradientText(text: string): string { 8 - const colors = [ 9 - '\x1b[38;5;33m', 10 - '\x1b[38;5;69m', 11 - '\x1b[38;5;99m', 12 - '\x1b[38;5;133m', 13 - '\x1b[38;5;170m', 14 - '\x1b[38;5;170m', 15 - '\x1b[38;5;133m', 16 - ]; 17 - const reset = '\x1b[0m'; 18 - 19 - return text.split('').map((char, i) => { 20 - const colorIndex = Math.floor((i / text.length) * colors.length); 21 - return colors[colorIndex] + char; 22 - }).join('') + reset; 23 - } 24 - 25 - function createMainTemplate(namespace: string): string { 26 - return `import "@typelex/emitter"; 27 - import "./externals.tsp"; 28 - 29 - namespace ${namespace}.post { 30 - @rec("tid") 31 - model Main { 32 - @required text: string; 33 - @required createdAt: datetime; 34 - } 35 - } 36 - `; 37 - } 38 - 39 - const EXTERNALS_TSP_TEMPLATE = `import "@typelex/emitter"; 40 - 41 - // Generated by typelex 42 - // This file is auto-generated. Do not edit manually. 43 - `; 44 - 45 - async function promptNamespace(): Promise<string> { 46 - const rl = createInterface({ 47 - input: process.stdin, 48 - output: process.stdout, 49 - }); 50 - 51 - return new Promise((resolve) => { 52 - rl.question(`Enter your app's root namespace (e.g. ${pc.cyan("com.example.*")}): `, (answer) => { 53 - rl.close(); 54 - resolve(answer.trim()); 55 - }); 56 - }); 57 - } 58 - 59 - export async function initCommand(isSetup: boolean = false, flags: string[] = []): Promise<void> { 60 - const originalCwd = process.cwd(); 61 - 62 - // Find nearest package.json upward 63 - let projectRoot = originalCwd; 64 - let dir = originalCwd; 65 - while (dir !== resolve(dir, "..")) { 66 - try { 67 - await access(resolve(dir, "package.json")); 68 - projectRoot = dir; 69 - break; 70 - } catch { 71 - dir = resolve(dir, ".."); 72 - } 73 - } 74 - 75 - if (isSetup) { 76 - return initSetup(); 77 - } 78 - 79 - console.log(`Adding ${gradientText("typelex")}...\n`); 80 - 81 - // Detect package manager 82 - let packageManager = "npm"; 83 - dir = projectRoot; 84 - while (dir !== resolve(dir, "..") && packageManager === "npm") { 85 - try { 86 - await access(resolve(dir, "pnpm-lock.yaml")); 87 - packageManager = "pnpm"; 88 - break; 89 - } catch { 90 - // Not found 91 - } 92 - try { 93 - await access(resolve(dir, "yarn.lock")); 94 - packageManager = "yarn"; 95 - break; 96 - } catch { 97 - // Not found 98 - } 99 - dir = resolve(dir, ".."); 100 - } 101 - 102 - // Install dependencies 103 - await new Promise<void>((resolvePromise, reject) => { 104 - const args = packageManager === "npm" 105 - ? ["install", "--save-dev", "@typelex/cli@latest", "@typelex/emitter@latest"] 106 - : ["add", "-D", "@typelex/cli@latest", "@typelex/emitter@latest"]; 107 - 108 - // Add any additional flags 109 - args.push(...flags); 110 - 111 - const install = spawn(packageManager, args, { 112 - cwd: projectRoot, 113 - stdio: "inherit", 114 - }); 115 - 116 - install.on("close", (code) => { 117 - if (code === 0) { 118 - console.log(`\n${pc.green("โœ“")} Installed ${pc.dim("@typelex/cli")} and ${pc.dim("@typelex/emitter")}\n`); 119 - resolvePromise(); 120 - } else { 121 - console.error(pc.red("โœ— Failed to install dependencies")); 122 - process.exit(code ?? 1); 123 - } 124 - }); 125 - 126 - install.on("error", (err) => { 127 - console.error(pc.red("โœ— Failed to install dependencies:"), err); 128 - reject(err); 129 - }); 130 - }); 131 - 132 - // Find node_modules 133 - let nodeModulesDir = resolve(projectRoot, "node_modules"); 134 - let searchDir = projectRoot; 135 - while (searchDir !== resolve(searchDir, "..")) { 136 - try { 137 - const candidatePath = resolve(searchDir, "node_modules/.bin/typelex"); 138 - await access(candidatePath); 139 - nodeModulesDir = resolve(searchDir, "node_modules"); 140 - break; 141 - } catch { 142 - searchDir = resolve(searchDir, ".."); 143 - } 144 - } 145 - 146 - return new Promise((resolvePromise, reject) => { 147 - const localCli = resolve(nodeModulesDir, ".bin/typelex"); 148 - const setup = spawn(localCli, ["init", "--setup"], { 149 - cwd: projectRoot, 150 - stdio: "inherit", 151 - }); 152 - 153 - setup.on("close", (code) => { 154 - if (code === 0) { 155 - resolvePromise(); 156 - } else { 157 - process.exit(code ?? 1); 158 - } 159 - }); 160 - 161 - setup.on("error", (err) => { 162 - console.error(pc.red("โœ— Failed to run setup:"), err); 163 - reject(err); 164 - }); 165 - }); 166 - } 167 - 168 - export async function initSetup(): Promise<void> { 169 - const cwd = process.cwd(); 170 - const typelexDir = resolve(cwd, "typelex"); 171 - const mainTspPath = resolve(typelexDir, "main.tsp"); 172 - const externalsTspPath = resolve(typelexDir, "externals.tsp"); 173 - 174 - // Prompt for namespace 175 - let namespace = await promptNamespace(); 176 - 177 - // Validate namespace format 178 - while (!namespace.endsWith(".*")) { 179 - console.error(pc.red(`Error: namespace must end with ${pc.bold(".*")}`)); 180 - console.error(pc.red(`Got: ${pc.bold(namespace)}\n`)); 181 - namespace = await promptNamespace(); 182 - } 183 - 184 - // Remove the .* suffix for use in template 185 - const namespacePrefix = namespace.slice(0, -2); 186 - 187 - // Detect lexicons directory: check cwd first, then walk up parents 188 - let lexiconsDir: string | null = null; 189 - let hasLocalLexicons = false; 190 - 191 - // Check current directory for lexicons/ (will use default, no --out flag needed) 192 - try { 193 - const localPath = resolve(cwd, "lexicons"); 194 - if ((await stat(localPath)).isDirectory()) { 195 - hasLocalLexicons = true; 196 - } 197 - } catch { 198 - // Not found in current directory, check parent directories 199 - let dir = resolve(cwd, ".."); 200 - while (dir !== resolve(dir, "..")) { 201 - try { 202 - const lexPath = resolve(dir, "lexicons"); 203 - if ((await stat(lexPath)).isDirectory()) { 204 - lexiconsDir = relative(cwd, lexPath); 205 - break; 206 - } 207 - } catch { 208 - // Not found, continue up 209 - } 210 - dir = resolve(dir, ".."); 211 - } 212 - } 213 - 214 - // Determine the actual lexicons path for display 215 - const displayLexiconsPath = hasLocalLexicons 216 - ? "./lexicons" 217 - : lexiconsDir || "./lexicons"; 218 - 219 - // Inform about external lexicons 220 - console.log(`\nLexicons other than ${pc.cyan(namespace)} will be considered external.`); 221 - console.log(`Put them into the ${pc.cyan(displayLexiconsPath)} folder as JSON.\n`); 222 - 223 - // Create typelex directory 224 - await mkdir(typelexDir, { recursive: true }); 225 - 226 - // Check if main.tsp exists and is non-empty 227 - let shouldCreateMain = true; 228 - try { 229 - await access(mainTspPath); 230 - const content = await readFile(mainTspPath, "utf-8"); 231 - if (content.trim().length > 0) { 232 - console.log(`${pc.green("โœ“")} ${pc.cyan("typelex/main.tsp")} already exists, skipping`); 233 - shouldCreateMain = false; 234 - } 235 - } catch { 236 - // File doesn't exist, we'll create it 237 - } 238 - 239 - if (shouldCreateMain) { 240 - await writeFile(mainTspPath, createMainTemplate(namespacePrefix), "utf-8"); 241 - console.log(`${pc.green("โœ“")} Created ${pc.cyan("typelex/main.tsp")}`); 242 - } 243 - 244 - // Always create/overwrite externals.tsp 245 - await writeFile(externalsTspPath, EXTERNALS_TSP_TEMPLATE, "utf-8"); 246 - console.log(`${pc.green("โœ“")} Created ${pc.cyan("typelex/externals.tsp")}`); 247 - 248 - // Add build script to package.json 249 - const packageJsonPath = resolve(cwd, "package.json"); 250 - try { 251 - const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8")); 252 - if (!packageJson.scripts) { 253 - packageJson.scripts = {}; 254 - } 255 - if (!packageJson.scripts["build:typelex"]) { 256 - const outFlag = lexiconsDir ? ` --out ${lexiconsDir}` : ""; 257 - packageJson.scripts["build:typelex"] = `typelex compile ${namespace}${outFlag}`; 258 - await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8"); 259 - console.log(`${pc.green("โœ“")} Added ${pc.cyan("build:typelex")} script to ${pc.cyan("package.json")}`); 260 - if (hasLocalLexicons) { 261 - console.log(pc.dim(` Using existing lexicons directory: ${pc.cyan("./lexicons")}`)); 262 - } else if (lexiconsDir) { 263 - console.log(pc.dim(` Using existing lexicons directory: ${pc.cyan(lexiconsDir)}`)); 264 - } 265 - } else { 266 - console.log(`${pc.green("โœ“")} ${pc.cyan("build:typelex")} script already exists in ${pc.cyan("package.json")}`); 267 - } 268 - } catch (err) { 269 - console.warn(pc.yellow(`โš  Could not update ${pc.cyan("package.json")}:`), (err as Error).message); 270 - } 271 - 272 - console.log(`\n${pc.green("โœ“")} ${pc.bold("All set!")}`); 273 - console.log(`\n${pc.bold("Next steps:")}`); 274 - console.log(` ${pc.dim("1.")} Edit ${pc.cyan("typelex/main.tsp")} to define your lexicons`); 275 - console.log(` ${pc.dim("2.")} Keep putting external lexicons into ${pc.cyan(displayLexiconsPath)}`); 276 - console.log(` ${pc.dim("3.")} Run ${pc.cyan("npm run build:typelex")} to compile to JSON`); 277 - }
+4 -4
packages/cli/src/utils/externals-generator.ts
··· 22 22 /** 23 23 * Generate TypeSpec external definitions from lexicon documents 24 24 */ 25 - function generateExternalsCode(lexicons: Map<string, LexiconDoc>, outDir: string, excludedPrefix: string): string { 25 + function generateExternalsCode(lexicons: Map<string, LexiconDoc>): string { 26 26 const lines: string[] = []; 27 27 28 28 lines.push('import "@typelex/emitter";'); 29 29 lines.push(""); 30 - lines.push(`// Generated by typelex from ${outDir} (excluding ${excludedPrefix}.*)`); 30 + lines.push("// Generated by typelex"); 31 31 lines.push("// This file is auto-generated. Do not edit manually."); 32 32 lines.push(""); 33 33 ··· 89 89 await mkdir(resolve(cwd, "typelex"), { recursive: true }); 90 90 await writeFile( 91 91 outputFile, 92 - `import "@typelex/emitter";\n\n// Generated by typelex from ${outDir} (excluding ${prefix}.*)\n// No external lexicons found\n`, 92 + 'import "@typelex/emitter";\n\n// Generated by typelex\n// No external lexicons found\n', 93 93 "utf-8" 94 94 ); 95 95 return; 96 96 } 97 97 98 - const code = generateExternalsCode(externals, outDir, prefix); 98 + const code = generateExternalsCode(externals); 99 99 await mkdir(resolve(cwd, "typelex"), { recursive: true }); 100 100 await writeFile(outputFile, code, "utf-8"); 101 101 } catch (error) {
+7
packages/example/.gitignore
··· 1 1 # Dependencies 2 2 node_modules/ 3 3 4 + # Generated lexicons 5 + lexicon/ 6 + 7 + # TypeSpec output (if using default config) 8 + tsp-output/ 9 + generated/ 10 + 4 11 # OS 5 12 .DS_Store 6 13
-31
packages/example/lexicons/app/bsky/actor/defs.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "app.bsky.actor.defs", 4 - "defs": { 5 - "profileView": { 6 - "type": "object", 7 - "required": ["did", "handle"], 8 - "properties": { 9 - "did": { "type": "string", "format": "did" }, 10 - "handle": { "type": "string", "format": "handle" }, 11 - "displayName": { 12 - "type": "string", 13 - "maxGraphemes": 64, 14 - "maxLength": 640 15 - }, 16 - "description": { 17 - "type": "string", 18 - "maxGraphemes": 256, 19 - "maxLength": 2560 20 - }, 21 - "avatar": { "type": "string", "format": "uri" }, 22 - "indexedAt": { "type": "string", "format": "datetime" }, 23 - "createdAt": { "type": "string", "format": "datetime" }, 24 - "labels": { 25 - "type": "array", 26 - "items": { "type": "ref", "ref": "com.atproto.label.defs#label" } 27 - } 28 - } 29 - } 30 - } 31 - }
-53
packages/example/lexicons/app/bsky/actor/profile.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "app.bsky.actor.profile", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A declaration of a Bluesky account profile.", 8 - "key": "literal:self", 9 - "record": { 10 - "type": "object", 11 - "properties": { 12 - "displayName": { 13 - "type": "string", 14 - "maxGraphemes": 64, 15 - "maxLength": 640 16 - }, 17 - "description": { 18 - "type": "string", 19 - "description": "Free-form profile description text.", 20 - "maxGraphemes": 256, 21 - "maxLength": 2560 22 - }, 23 - "avatar": { 24 - "type": "blob", 25 - "description": "Small image to be displayed next to posts from account. AKA, 'profile picture'", 26 - "accept": ["image/png", "image/jpeg"], 27 - "maxSize": 1000000 28 - }, 29 - "banner": { 30 - "type": "blob", 31 - "description": "Larger horizontal image to display behind profile view.", 32 - "accept": ["image/png", "image/jpeg"], 33 - "maxSize": 1000000 34 - }, 35 - "labels": { 36 - "type": "union", 37 - "description": "Self-label values, specific to the Bluesky application, on the overall account.", 38 - "refs": ["com.atproto.label.defs#selfLabels"] 39 - }, 40 - "joinedViaStarterPack": { 41 - "type": "ref", 42 - "ref": "com.atproto.repo.strongRef" 43 - }, 44 - "pinnedPost": { 45 - "type": "ref", 46 - "ref": "com.atproto.repo.strongRef" 47 - }, 48 - "createdAt": { "type": "string", "format": "datetime" } 49 - } 50 - } 51 - } 52 - } 53 - }
-156
packages/example/lexicons/com/atproto/label/defs.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.label.defs", 4 - "defs": { 5 - "label": { 6 - "type": "object", 7 - "description": "Metadata tag on an atproto resource (eg, repo or record).", 8 - "required": ["src", "uri", "val", "cts"], 9 - "properties": { 10 - "ver": { 11 - "type": "integer", 12 - "description": "The AT Protocol version of the label object." 13 - }, 14 - "src": { 15 - "type": "string", 16 - "format": "did", 17 - "description": "DID of the actor who created this label." 18 - }, 19 - "uri": { 20 - "type": "string", 21 - "format": "uri", 22 - "description": "AT URI of the record, repository (account), or other resource that this label applies to." 23 - }, 24 - "cid": { 25 - "type": "string", 26 - "format": "cid", 27 - "description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to." 28 - }, 29 - "val": { 30 - "type": "string", 31 - "maxLength": 128, 32 - "description": "The short string name of the value or type of this label." 33 - }, 34 - "neg": { 35 - "type": "boolean", 36 - "description": "If true, this is a negation label, overwriting a previous label." 37 - }, 38 - "cts": { 39 - "type": "string", 40 - "format": "datetime", 41 - "description": "Timestamp when this label was created." 42 - }, 43 - "exp": { 44 - "type": "string", 45 - "format": "datetime", 46 - "description": "Timestamp at which this label expires (no longer applies)." 47 - }, 48 - "sig": { 49 - "type": "bytes", 50 - "description": "Signature of dag-cbor encoded label." 51 - } 52 - } 53 - }, 54 - "selfLabels": { 55 - "type": "object", 56 - "description": "Metadata tags on an atproto record, published by the author within the record.", 57 - "required": ["values"], 58 - "properties": { 59 - "values": { 60 - "type": "array", 61 - "items": { "type": "ref", "ref": "#selfLabel" }, 62 - "maxLength": 10 63 - } 64 - } 65 - }, 66 - "selfLabel": { 67 - "type": "object", 68 - "description": "Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.", 69 - "required": ["val"], 70 - "properties": { 71 - "val": { 72 - "type": "string", 73 - "maxLength": 128, 74 - "description": "The short string name of the value or type of this label." 75 - } 76 - } 77 - }, 78 - "labelValueDefinition": { 79 - "type": "object", 80 - "description": "Declares a label value and its expected interpretations and behaviors.", 81 - "required": ["identifier", "severity", "blurs", "locales"], 82 - "properties": { 83 - "identifier": { 84 - "type": "string", 85 - "description": "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).", 86 - "maxLength": 100, 87 - "maxGraphemes": 100 88 - }, 89 - "severity": { 90 - "type": "string", 91 - "description": "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.", 92 - "knownValues": ["inform", "alert", "none"] 93 - }, 94 - "blurs": { 95 - "type": "string", 96 - "description": "What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing.", 97 - "knownValues": ["content", "media", "none"] 98 - }, 99 - "defaultSetting": { 100 - "type": "string", 101 - "description": "The default setting for this label.", 102 - "knownValues": ["ignore", "warn", "hide"], 103 - "default": "warn" 104 - }, 105 - "adultOnly": { 106 - "type": "boolean", 107 - "description": "Does the user need to have adult content enabled in order to configure this label?" 108 - }, 109 - "locales": { 110 - "type": "array", 111 - "items": { "type": "ref", "ref": "#labelValueDefinitionStrings" } 112 - } 113 - } 114 - }, 115 - "labelValueDefinitionStrings": { 116 - "type": "object", 117 - "description": "Strings which describe the label in the UI, localized into a specific language.", 118 - "required": ["lang", "name", "description"], 119 - "properties": { 120 - "lang": { 121 - "type": "string", 122 - "description": "The code of the language these strings are written in.", 123 - "format": "language" 124 - }, 125 - "name": { 126 - "type": "string", 127 - "description": "A short human-readable name for the label.", 128 - "maxGraphemes": 64, 129 - "maxLength": 640 130 - }, 131 - "description": { 132 - "type": "string", 133 - "description": "A longer description of what the label means and why it might be applied.", 134 - "maxGraphemes": 10000, 135 - "maxLength": 100000 136 - } 137 - } 138 - }, 139 - "labelValue": { 140 - "type": "string", 141 - "knownValues": [ 142 - "!hide", 143 - "!no-promote", 144 - "!warn", 145 - "!no-unauthenticated", 146 - "dmca-violation", 147 - "doxxing", 148 - "porn", 149 - "sexual", 150 - "nudity", 151 - "nsfl", 152 - "gore" 153 - ] 154 - } 155 - } 156 - }
-131
packages/example/lexicons/com/atproto/repo/applyWrites.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.applyWrites", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["repo", "writes"], 13 - "properties": { 14 - "repo": { 15 - "type": "string", 16 - "format": "at-identifier", 17 - "description": "The handle or DID of the repo (aka, current account)." 18 - }, 19 - "validate": { 20 - "type": "boolean", 21 - "description": "Can be set to 'false' to skip Lexicon schema validation of record data across all operations, 'true' to require it, or leave unset to validate only for known Lexicons." 22 - }, 23 - "writes": { 24 - "type": "array", 25 - "items": { 26 - "type": "union", 27 - "refs": ["#create", "#update", "#delete"], 28 - "closed": true 29 - } 30 - }, 31 - "swapCommit": { 32 - "type": "string", 33 - "description": "If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.", 34 - "format": "cid" 35 - } 36 - } 37 - } 38 - }, 39 - "output": { 40 - "encoding": "application/json", 41 - "schema": { 42 - "type": "object", 43 - "required": [], 44 - "properties": { 45 - "commit": { 46 - "type": "ref", 47 - "ref": "com.atproto.repo.defs#commitMeta" 48 - }, 49 - "results": { 50 - "type": "array", 51 - "items": { 52 - "type": "union", 53 - "refs": ["#createResult", "#updateResult", "#deleteResult"], 54 - "closed": true 55 - } 56 - } 57 - } 58 - } 59 - }, 60 - "errors": [ 61 - { 62 - "name": "InvalidSwap", 63 - "description": "Indicates that the 'swapCommit' parameter did not match current commit." 64 - } 65 - ] 66 - }, 67 - "create": { 68 - "type": "object", 69 - "description": "Operation which creates a new record.", 70 - "required": ["collection", "value"], 71 - "properties": { 72 - "collection": { "type": "string", "format": "nsid" }, 73 - "rkey": { 74 - "type": "string", 75 - "maxLength": 512, 76 - "format": "record-key", 77 - "description": "NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility." 78 - }, 79 - "value": { "type": "unknown" } 80 - } 81 - }, 82 - "update": { 83 - "type": "object", 84 - "description": "Operation which updates an existing record.", 85 - "required": ["collection", "rkey", "value"], 86 - "properties": { 87 - "collection": { "type": "string", "format": "nsid" }, 88 - "rkey": { "type": "string", "format": "record-key" }, 89 - "value": { "type": "unknown" } 90 - } 91 - }, 92 - "delete": { 93 - "type": "object", 94 - "description": "Operation which deletes an existing record.", 95 - "required": ["collection", "rkey"], 96 - "properties": { 97 - "collection": { "type": "string", "format": "nsid" }, 98 - "rkey": { "type": "string", "format": "record-key" } 99 - } 100 - }, 101 - "createResult": { 102 - "type": "object", 103 - "required": ["uri", "cid"], 104 - "properties": { 105 - "uri": { "type": "string", "format": "at-uri" }, 106 - "cid": { "type": "string", "format": "cid" }, 107 - "validationStatus": { 108 - "type": "string", 109 - "knownValues": ["valid", "unknown"] 110 - } 111 - } 112 - }, 113 - "updateResult": { 114 - "type": "object", 115 - "required": ["uri", "cid"], 116 - "properties": { 117 - "uri": { "type": "string", "format": "at-uri" }, 118 - "cid": { "type": "string", "format": "cid" }, 119 - "validationStatus": { 120 - "type": "string", 121 - "knownValues": ["valid", "unknown"] 122 - } 123 - } 124 - }, 125 - "deleteResult": { 126 - "type": "object", 127 - "required": [], 128 - "properties": {} 129 - } 130 - } 131 - }
-73
packages/example/lexicons/com/atproto/repo/createRecord.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.createRecord", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Create a single new repository record. Requires auth, implemented by PDS.", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["repo", "collection", "record"], 13 - "properties": { 14 - "repo": { 15 - "type": "string", 16 - "format": "at-identifier", 17 - "description": "The handle or DID of the repo (aka, current account)." 18 - }, 19 - "collection": { 20 - "type": "string", 21 - "format": "nsid", 22 - "description": "The NSID of the record collection." 23 - }, 24 - "rkey": { 25 - "type": "string", 26 - "format": "record-key", 27 - "description": "The Record Key.", 28 - "maxLength": 512 29 - }, 30 - "validate": { 31 - "type": "boolean", 32 - "description": "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons." 33 - }, 34 - "record": { 35 - "type": "unknown", 36 - "description": "The record itself. Must contain a $type field." 37 - }, 38 - "swapCommit": { 39 - "type": "string", 40 - "format": "cid", 41 - "description": "Compare and swap with the previous commit by CID." 42 - } 43 - } 44 - } 45 - }, 46 - "output": { 47 - "encoding": "application/json", 48 - "schema": { 49 - "type": "object", 50 - "required": ["uri", "cid"], 51 - "properties": { 52 - "uri": { "type": "string", "format": "at-uri" }, 53 - "cid": { "type": "string", "format": "cid" }, 54 - "commit": { 55 - "type": "ref", 56 - "ref": "com.atproto.repo.defs#commitMeta" 57 - }, 58 - "validationStatus": { 59 - "type": "string", 60 - "knownValues": ["valid", "unknown"] 61 - } 62 - } 63 - } 64 - }, 65 - "errors": [ 66 - { 67 - "name": "InvalidSwap", 68 - "description": "Indicates that 'swapCommit' didn't match current repo commit." 69 - } 70 - ] 71 - } 72 - } 73 - }
-14
packages/example/lexicons/com/atproto/repo/defs.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.defs", 4 - "defs": { 5 - "commitMeta": { 6 - "type": "object", 7 - "required": ["cid", "rev"], 8 - "properties": { 9 - "cid": { "type": "string", "format": "cid" }, 10 - "rev": { "type": "string", "format": "tid" } 11 - } 12 - } 13 - } 14 - }
-57
packages/example/lexicons/com/atproto/repo/deleteRecord.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.deleteRecord", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["repo", "collection", "rkey"], 13 - "properties": { 14 - "repo": { 15 - "type": "string", 16 - "format": "at-identifier", 17 - "description": "The handle or DID of the repo (aka, current account)." 18 - }, 19 - "collection": { 20 - "type": "string", 21 - "format": "nsid", 22 - "description": "The NSID of the record collection." 23 - }, 24 - "rkey": { 25 - "type": "string", 26 - "format": "record-key", 27 - "description": "The Record Key." 28 - }, 29 - "swapRecord": { 30 - "type": "string", 31 - "format": "cid", 32 - "description": "Compare and swap with the previous record by CID." 33 - }, 34 - "swapCommit": { 35 - "type": "string", 36 - "format": "cid", 37 - "description": "Compare and swap with the previous commit by CID." 38 - } 39 - } 40 - } 41 - }, 42 - "output": { 43 - "encoding": "application/json", 44 - "schema": { 45 - "type": "object", 46 - "properties": { 47 - "commit": { 48 - "type": "ref", 49 - "ref": "com.atproto.repo.defs#commitMeta" 50 - } 51 - } 52 - } 53 - }, 54 - "errors": [{ "name": "InvalidSwap" }] 55 - } 56 - } 57 - }
-51
packages/example/lexicons/com/atproto/repo/describeRepo.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.describeRepo", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Get information about an account and repository, including the list of collections. Does not require auth.", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["repo"], 11 - "properties": { 12 - "repo": { 13 - "type": "string", 14 - "format": "at-identifier", 15 - "description": "The handle or DID of the repo." 16 - } 17 - } 18 - }, 19 - "output": { 20 - "encoding": "application/json", 21 - "schema": { 22 - "type": "object", 23 - "required": [ 24 - "handle", 25 - "did", 26 - "didDoc", 27 - "collections", 28 - "handleIsCorrect" 29 - ], 30 - "properties": { 31 - "handle": { "type": "string", "format": "handle" }, 32 - "did": { "type": "string", "format": "did" }, 33 - "didDoc": { 34 - "type": "unknown", 35 - "description": "The complete DID document for this account." 36 - }, 37 - "collections": { 38 - "type": "array", 39 - "description": "List of all the collections (NSIDs) for which this repo contains at least one record.", 40 - "items": { "type": "string", "format": "nsid" } 41 - }, 42 - "handleIsCorrect": { 43 - "type": "boolean", 44 - "description": "Indicates if handle is currently valid (resolves bi-directionally)" 45 - } 46 - } 47 - } 48 - } 49 - } 50 - } 51 - }
-49
packages/example/lexicons/com/atproto/repo/getRecord.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.getRecord", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Get a single record from a repository. Does not require auth.", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["repo", "collection", "rkey"], 11 - "properties": { 12 - "repo": { 13 - "type": "string", 14 - "format": "at-identifier", 15 - "description": "The handle or DID of the repo." 16 - }, 17 - "collection": { 18 - "type": "string", 19 - "format": "nsid", 20 - "description": "The NSID of the record collection." 21 - }, 22 - "rkey": { 23 - "type": "string", 24 - "description": "The Record Key.", 25 - "format": "record-key" 26 - }, 27 - "cid": { 28 - "type": "string", 29 - "format": "cid", 30 - "description": "The CID of the version of the record. If not specified, then return the most recent version." 31 - } 32 - } 33 - }, 34 - "output": { 35 - "encoding": "application/json", 36 - "schema": { 37 - "type": "object", 38 - "required": ["uri", "value"], 39 - "properties": { 40 - "uri": { "type": "string", "format": "at-uri" }, 41 - "cid": { "type": "string", "format": "cid" }, 42 - "value": { "type": "unknown" } 43 - } 44 - } 45 - }, 46 - "errors": [{ "name": "RecordNotFound" }] 47 - } 48 - } 49 - }
-13
packages/example/lexicons/com/atproto/repo/importRepo.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.importRepo", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.", 8 - "input": { 9 - "encoding": "application/vnd.ipld.car" 10 - } 11 - } 12 - } 13 - }
-44
packages/example/lexicons/com/atproto/repo/listMissingBlobs.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.listMissingBlobs", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.", 8 - "parameters": { 9 - "type": "params", 10 - "properties": { 11 - "limit": { 12 - "type": "integer", 13 - "minimum": 1, 14 - "maximum": 1000, 15 - "default": 500 16 - }, 17 - "cursor": { "type": "string" } 18 - } 19 - }, 20 - "output": { 21 - "encoding": "application/json", 22 - "schema": { 23 - "type": "object", 24 - "required": ["blobs"], 25 - "properties": { 26 - "cursor": { "type": "string" }, 27 - "blobs": { 28 - "type": "array", 29 - "items": { "type": "ref", "ref": "#recordBlob" } 30 - } 31 - } 32 - } 33 - } 34 - }, 35 - "recordBlob": { 36 - "type": "object", 37 - "required": ["cid", "recordUri"], 38 - "properties": { 39 - "cid": { "type": "string", "format": "cid" }, 40 - "recordUri": { "type": "string", "format": "at-uri" } 41 - } 42 - } 43 - } 44 - }
-69
packages/example/lexicons/com/atproto/repo/listRecords.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.listRecords", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "List a range of records in a repository, matching a specific collection. Does not require auth.", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["repo", "collection"], 11 - "properties": { 12 - "repo": { 13 - "type": "string", 14 - "format": "at-identifier", 15 - "description": "The handle or DID of the repo." 16 - }, 17 - "collection": { 18 - "type": "string", 19 - "format": "nsid", 20 - "description": "The NSID of the record type." 21 - }, 22 - "limit": { 23 - "type": "integer", 24 - "minimum": 1, 25 - "maximum": 100, 26 - "default": 50, 27 - "description": "The number of records to return." 28 - }, 29 - "cursor": { "type": "string" }, 30 - "rkeyStart": { 31 - "type": "string", 32 - "description": "DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)" 33 - }, 34 - "rkeyEnd": { 35 - "type": "string", 36 - "description": "DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)" 37 - }, 38 - "reverse": { 39 - "type": "boolean", 40 - "description": "Flag to reverse the order of the returned records." 41 - } 42 - } 43 - }, 44 - "output": { 45 - "encoding": "application/json", 46 - "schema": { 47 - "type": "object", 48 - "required": ["records"], 49 - "properties": { 50 - "cursor": { "type": "string" }, 51 - "records": { 52 - "type": "array", 53 - "items": { "type": "ref", "ref": "#record" } 54 - } 55 - } 56 - } 57 - } 58 - }, 59 - "record": { 60 - "type": "object", 61 - "required": ["uri", "cid", "value"], 62 - "properties": { 63 - "uri": { "type": "string", "format": "at-uri" }, 64 - "cid": { "type": "string", "format": "cid" }, 65 - "value": { "type": "unknown" } 66 - } 67 - } 68 - } 69 - }
-74
packages/example/lexicons/com/atproto/repo/putRecord.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.putRecord", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["repo", "collection", "rkey", "record"], 13 - "nullable": ["swapRecord"], 14 - "properties": { 15 - "repo": { 16 - "type": "string", 17 - "format": "at-identifier", 18 - "description": "The handle or DID of the repo (aka, current account)." 19 - }, 20 - "collection": { 21 - "type": "string", 22 - "format": "nsid", 23 - "description": "The NSID of the record collection." 24 - }, 25 - "rkey": { 26 - "type": "string", 27 - "format": "record-key", 28 - "description": "The Record Key.", 29 - "maxLength": 512 30 - }, 31 - "validate": { 32 - "type": "boolean", 33 - "description": "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons." 34 - }, 35 - "record": { 36 - "type": "unknown", 37 - "description": "The record to write." 38 - }, 39 - "swapRecord": { 40 - "type": "string", 41 - "format": "cid", 42 - "description": "Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation" 43 - }, 44 - "swapCommit": { 45 - "type": "string", 46 - "format": "cid", 47 - "description": "Compare and swap with the previous commit by CID." 48 - } 49 - } 50 - } 51 - }, 52 - "output": { 53 - "encoding": "application/json", 54 - "schema": { 55 - "type": "object", 56 - "required": ["uri", "cid"], 57 - "properties": { 58 - "uri": { "type": "string", "format": "at-uri" }, 59 - "cid": { "type": "string", "format": "cid" }, 60 - "commit": { 61 - "type": "ref", 62 - "ref": "com.atproto.repo.defs#commitMeta" 63 - }, 64 - "validationStatus": { 65 - "type": "string", 66 - "knownValues": ["valid", "unknown"] 67 - } 68 - } 69 - } 70 - }, 71 - "errors": [{ "name": "InvalidSwap" }] 72 - } 73 - } 74 - }
-15
packages/example/lexicons/com/atproto/repo/strongRef.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.strongRef", 4 - "description": "A URI with a content-hash fingerprint.", 5 - "defs": { 6 - "main": { 7 - "type": "object", 8 - "required": ["uri", "cid"], 9 - "properties": { 10 - "uri": { "type": "string", "format": "at-uri" }, 11 - "cid": { "type": "string", "format": "cid" } 12 - } 13 - } 14 - } 15 - }
-23
packages/example/lexicons/com/atproto/repo/uploadBlob.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "com.atproto.repo.uploadBlob", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.", 8 - "input": { 9 - "encoding": "*/*" 10 - }, 11 - "output": { 12 - "encoding": "application/json", 13 - "schema": { 14 - "type": "object", 15 - "required": ["blob"], 16 - "properties": { 17 - "blob": { "type": "blob" } 18 - } 19 - } 20 - } 21 - } 22 - } 23 - }
-52
packages/example/lexicons/xyz/statusphere/defs.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "xyz.statusphere.defs", 4 - "defs": { 5 - "statusView": { 6 - "type": "object", 7 - "properties": { 8 - "uri": { 9 - "type": "string", 10 - "format": "at-uri" 11 - }, 12 - "status": { 13 - "type": "string", 14 - "maxLength": 32, 15 - "minLength": 1, 16 - "maxGraphemes": 1 17 - }, 18 - "createdAt": { 19 - "type": "string", 20 - "format": "datetime" 21 - }, 22 - "profile": { 23 - "type": "ref", 24 - "ref": "#profileView" 25 - } 26 - }, 27 - "required": [ 28 - "uri", 29 - "status", 30 - "createdAt", 31 - "profile" 32 - ] 33 - }, 34 - "profileView": { 35 - "type": "object", 36 - "properties": { 37 - "did": { 38 - "type": "string", 39 - "format": "did" 40 - }, 41 - "handle": { 42 - "type": "string", 43 - "format": "handle" 44 - } 45 - }, 46 - "required": [ 47 - "did", 48 - "handle" 49 - ] 50 - } 51 - } 52 - }
-39
packages/example/lexicons/xyz/statusphere/getStatuses.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "xyz.statusphere.getStatuses", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Get a list of the most recent statuses on the network.", 8 - "parameters": { 9 - "type": "params", 10 - "properties": { 11 - "limit": { 12 - "type": "integer", 13 - "minimum": 1, 14 - "maximum": 100, 15 - "default": 50 16 - } 17 - } 18 - }, 19 - "output": { 20 - "encoding": "application/json", 21 - "schema": { 22 - "type": "object", 23 - "properties": { 24 - "statuses": { 25 - "type": "array", 26 - "items": { 27 - "type": "ref", 28 - "ref": "xyz.statusphere.defs#statusView" 29 - } 30 - } 31 - }, 32 - "required": [ 33 - "statuses" 34 - ] 35 - } 36 - } 37 - } 38 - } 39 - }
-29
packages/example/lexicons/xyz/statusphere/getUser.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "xyz.statusphere.getUser", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Get the current user's profile and status.", 8 - "output": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "properties": { 13 - "profile": { 14 - "type": "ref", 15 - "ref": "app.bsky.actor.defs#profileView" 16 - }, 17 - "status": { 18 - "type": "ref", 19 - "ref": "xyz.statusphere.defs#statusView" 20 - } 21 - }, 22 - "required": [ 23 - "profile" 24 - ] 25 - } 26 - } 27 - } 28 - } 29 - }
-42
packages/example/lexicons/xyz/statusphere/sendStatus.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "xyz.statusphere.sendStatus", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Send a status into the ATmosphere.", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "properties": { 13 - "status": { 14 - "type": "string", 15 - "maxLength": 32, 16 - "minLength": 1, 17 - "maxGraphemes": 1 18 - } 19 - }, 20 - "required": [ 21 - "status" 22 - ] 23 - } 24 - }, 25 - "output": { 26 - "encoding": "application/json", 27 - "schema": { 28 - "type": "object", 29 - "properties": { 30 - "status": { 31 - "type": "ref", 32 - "ref": "xyz.statusphere.defs#statusView" 33 - } 34 - }, 35 - "required": [ 36 - "status" 37 - ] 38 - } 39 - } 40 - } 41 - } 42 - }
-29
packages/example/lexicons/xyz/statusphere/status.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "xyz.statusphere.status", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "key": "tid", 8 - "record": { 9 - "type": "object", 10 - "properties": { 11 - "status": { 12 - "type": "string", 13 - "maxLength": 32, 14 - "minLength": 1, 15 - "maxGraphemes": 1 16 - }, 17 - "createdAt": { 18 - "type": "string", 19 - "format": "datetime" 20 - } 21 - }, 22 - "required": [ 23 - "status", 24 - "createdAt" 25 - ] 26 - } 27 - } 28 - } 29 - }
+2 -2
packages/example/package.json
··· 4 4 "private": true, 5 5 "type": "module", 6 6 "scripts": { 7 - "build": "pnpm run build:typelex && pnpm run build:codegen", 8 - "build:typelex": "typelex compile xyz.statusphere.*", 7 + "build": "pnpm run build:lexicons && pnpm run build:codegen", 8 + "build:lexicons": "typelex compile xyz.statusphere.*", 9 9 "build:codegen": "lex gen-server --yes ./src lexicons/xyz/statusphere/*.json" 10 10 }, 11 11 "dependencies": {
+154 -1
packages/example/typelex/externals.tsp
··· 1 1 import "@typelex/emitter"; 2 2 3 - // Generated by typelex from ./lexicons (excluding xyz.statusphere.*) 3 + // Generated by typelex 4 4 // This file is auto-generated. Do not edit manually. 5 5 6 6 @external 7 7 namespace app.bsky.actor.defs { 8 + model AdultContentPref { } 9 + model BskyAppProgressGuide { } 10 + model BskyAppStatePref { } 11 + model ContentLabelPref { } 12 + model FeedViewPref { } 13 + model HiddenPostsPref { } 14 + model InterestsPref { } 15 + model KnownFollowers { } 16 + model LabelerPrefItem { } 17 + model LabelersPref { } 18 + model MutedWord { } 19 + model MutedWordsPref { } 20 + model MutedWordTarget { } 21 + model Nux { } 22 + model PersonalDetailsPref { } 23 + model PostInteractionSettingsPref { } 24 + model ProfileAssociated { } 25 + model ProfileAssociatedChat { } 8 26 model ProfileView { } 27 + model ProfileViewBasic { } 28 + model ProfileViewDetailed { } 29 + model SavedFeed { } 30 + model SavedFeedsPref { } 31 + model SavedFeedsPrefV2 { } 32 + model ThreadViewPref { } 33 + model ViewerState { } 9 34 } 10 35 11 36 @external 12 37 namespace app.bsky.actor.profile { 13 38 model Main { } 39 + } 40 + 41 + @external 42 + namespace app.bsky.embed.defs { 43 + model AspectRatio { } 44 + } 45 + 46 + @external 47 + namespace app.bsky.embed.external { 48 + model External { } 49 + model Main { } 50 + model View { } 51 + model ViewExternal { } 52 + } 53 + 54 + @external 55 + namespace app.bsky.embed.images { 56 + model Image { } 57 + model Main { } 58 + model View { } 59 + model ViewImage { } 60 + } 61 + 62 + @external 63 + namespace app.bsky.embed.`record` { 64 + model Main { } 65 + model View { } 66 + model ViewBlocked { } 67 + model ViewDetached { } 68 + model ViewNotFound { } 69 + model ViewRecord { } 70 + } 71 + 72 + @external 73 + namespace app.bsky.embed.recordWithMedia { 74 + model Main { } 75 + model View { } 76 + } 77 + 78 + @external 79 + namespace app.bsky.embed.video { 80 + model Caption { } 81 + model Main { } 82 + model View { } 83 + } 84 + 85 + @external 86 + namespace app.bsky.feed.defs { 87 + model BlockedAuthor { } 88 + model BlockedPost { } 89 + @token model ClickthroughAuthor { } 90 + @token model ClickthroughEmbed { } 91 + @token model ClickthroughItem { } 92 + @token model ClickthroughReposter { } 93 + @token model ContentModeUnspecified { } 94 + @token model ContentModeVideo { } 95 + model FeedViewPost { } 96 + model GeneratorView { } 97 + model GeneratorViewerState { } 98 + model Interaction { } 99 + @token model InteractionLike { } 100 + @token model InteractionQuote { } 101 + @token model InteractionReply { } 102 + @token model InteractionRepost { } 103 + @token model InteractionSeen { } 104 + @token model InteractionShare { } 105 + model NotFoundPost { } 106 + model PostView { } 107 + model ReasonPin { } 108 + model ReasonRepost { } 109 + model ReplyRef { } 110 + @token model RequestLess { } 111 + @token model RequestMore { } 112 + model SkeletonFeedPost { } 113 + model SkeletonReasonPin { } 114 + model SkeletonReasonRepost { } 115 + model ThreadContext { } 116 + model ThreadgateView { } 117 + model ThreadViewPost { } 118 + model ViewerState { } 119 + } 120 + 121 + @external 122 + namespace app.bsky.feed.postgate { 123 + model DisableRule { } 124 + model Main { } 125 + } 126 + 127 + @external 128 + namespace app.bsky.feed.threadgate { 129 + model FollowerRule { } 130 + model FollowingRule { } 131 + model ListRule { } 132 + model Main { } 133 + model MentionRule { } 134 + } 135 + 136 + @external 137 + namespace app.bsky.graph.defs { 138 + @token model Curatelist { } 139 + model ListItemView { } 140 + model ListPurpose { } 141 + model ListView { } 142 + model ListViewBasic { } 143 + model ListViewerState { } 144 + @token model Modlist { } 145 + model NotFoundActor { } 146 + @token model Referencelist { } 147 + model Relationship { } 148 + model StarterPackView { } 149 + model StarterPackViewBasic { } 150 + } 151 + 152 + @external 153 + namespace app.bsky.labeler.defs { 154 + model LabelerPolicies { } 155 + model LabelerView { } 156 + model LabelerViewDetailed { } 157 + model LabelerViewerState { } 158 + } 159 + 160 + @external 161 + namespace app.bsky.richtext.facet { 162 + model ByteSlice { } 163 + model Link { } 164 + model Main { } 165 + model Mention { } 166 + model Tag { } 14 167 } 15 168 16 169 @external
-3
pnpm-lock.yaml
··· 20 20 '@typespec/compiler': 21 21 specifier: ^1.4.0 22 22 version: 1.4.0(@types/node@20.19.19) 23 - picocolors: 24 - specifier: ^1.1.1 25 - version: 1.1.1 26 23 yargs: 27 24 specifier: ^18.0.0 28 25 version: 18.0.0