An experimental TypeSpec syntax for Lexicon

Compare changes

Choose any two refs to compare.

Changed files
+3202 -803
packages
cli
emitter
test
integration
atproto
input
app
bsky
actor
bookmark
embed
feed
graph
labeler
notification
unspecced
video
chat
com
tools
lexicon-examples
example
playground
+4
CHANGELOG.md
··· 1 + ### 0.2.0 2 + 3 + - Add `@external` support 4 + 1 5 ### 0.1.6 2 6 3 7 - Rebuild
+2 -1
package.json
··· 10 10 "example": "pnpm --filter @typelex/example build", 11 11 "playground": "pnpm --filter @typelex/playground dev", 12 12 "validate": "pnpm build && pnpm run validate-lexicons && pnpm test", 13 - "validate-lexicons": "node scripts/validate-lexicons.js" 13 + "validate-lexicons": "node scripts/validate-lexicons.js", 14 + "cli": "pnpm --filter @typelex/cli" 14 15 }, 15 16 "repository": { 16 17 "type": "git",
+3
packages/cli/.gitignore
··· 1 + dist 2 + node_modules 3 + *.log
+66
packages/cli/README.md
··· 1 + # @typelex/cli 2 + 3 + Experimental CLI for typelex 4 + 5 + ## Installation 6 + 7 + ```bash 8 + pnpm add -D @typelex/cli @typelex/emitter 9 + ``` 10 + 11 + ## Usage 12 + 13 + ```bash 14 + typelex compile xyz.statusphere.* 15 + ``` 16 + 17 + This command: 18 + 1. Scans `lexicons/` for all external lexicons (not matching `xyz.statusphere`) 19 + 2. Generates `typelex/externals.tsp` with `@external` stubs 20 + 3. Compiles `typelex/main.tsp` to `lexicons/` (or custom output via `--out`) 21 + 22 + Fixed paths: 23 + - Entry point: `typelex/main.tsp` 24 + - Externals: `typelex/externals.tsp` 25 + 26 + ## Example 27 + 28 + ```typescript 29 + // typelex/main.tsp 30 + import "@typelex/emitter"; 31 + import "./externals.tsp"; 32 + 33 + namespace xyz.statusphere.defs { 34 + model StatusView { 35 + @required uri: atUri; 36 + @required status: string; 37 + @required profile: app.bsky.actor.defs.ProfileView; 38 + } 39 + } 40 + ``` 41 + 42 + ```bash 43 + typelex compile 'xyz.statusphere.*' 44 + ``` 45 + 46 + The CLI scans `lexicons/` for external types and auto-generates `typelex/externals.tsp` with stubs 47 + 48 + ### Integration 49 + 50 + ```json 51 + { 52 + "scripts": { 53 + "build:lexicons": "typelex compile 'xyz.statusphere.*'", 54 + "build:codegen": "lex gen-server --yes ./src lexicons/xyz/statusphere/*.json" 55 + } 56 + } 57 + ``` 58 + 59 + ## Options 60 + 61 + - `--out <directory>` - Output directory for generated Lexicon files (default: `./lexicons`) 62 + - `--watch` - Watch mode for continuous compilation 63 + 64 + ## License 65 + 66 + MIT
+40
packages/cli/package.json
··· 1 + { 2 + "name": "@typelex/cli", 3 + "version": "0.2.0", 4 + "description": "CLI for typelex - TypeSpec-based IDL for ATProto Lexicons", 5 + "main": "dist/index.js", 6 + "type": "module", 7 + "bin": { 8 + "typelex": "dist/cli.js" 9 + }, 10 + "files": [ 11 + "dist", 12 + "src" 13 + ], 14 + "scripts": { 15 + "build": "tsc", 16 + "clean": "rm -rf dist", 17 + "watch": "tsc --watch", 18 + "prepublishOnly": "npm run build" 19 + }, 20 + "keywords": [ 21 + "typespec", 22 + "atproto", 23 + "lexicon", 24 + "cli" 25 + ], 26 + "author": "Dan Abramov <dan.abramov@gmail.com>", 27 + "license": "MIT", 28 + "dependencies": { 29 + "@typespec/compiler": "^1.4.0", 30 + "yargs": "^18.0.0" 31 + }, 32 + "devDependencies": { 33 + "@types/node": "^20.0.0", 34 + "@types/yargs": "^17.0.33", 35 + "typescript": "^5.0.0" 36 + }, 37 + "peerDependencies": { 38 + "@typelex/emitter": "^0.2.0" 39 + } 40 + }
+64
packages/cli/src/cli.ts
··· 1 + #!/usr/bin/env node 2 + import yargs from "yargs"; 3 + import { hideBin } from "yargs/helpers"; 4 + import { compileCommand } from "./commands/compile.js"; 5 + 6 + async function main() { 7 + await yargs(hideBin(process.argv)) 8 + .scriptName("typelex") 9 + .usage("$0 compile <namespace>") 10 + .command( 11 + "compile <namespace>", 12 + "Compile TypeSpec files to Lexicon JSON", 13 + (yargs) => { 14 + return yargs 15 + .positional("namespace", { 16 + describe: "Primary namespace pattern (e.g., app.bsky.*)", 17 + type: "string", 18 + demandOption: true, 19 + }) 20 + .option("out", { 21 + describe: "Output directory for generated Lexicon files (relative to cwd)", 22 + type: "string", 23 + default: "./lexicons", 24 + }); 25 + }, 26 + async (argv) => { 27 + const options: Record<string, unknown> = {}; 28 + if (argv.watch) { 29 + options.watch = true; 30 + } 31 + if (argv.out) { 32 + options.out = argv.out; 33 + } 34 + await compileCommand(argv.namespace, options); 35 + } 36 + ) 37 + .option("watch", { 38 + describe: "Watch mode", 39 + type: "boolean", 40 + default: false, 41 + }) 42 + .demandCommand(1, "You must specify a command") 43 + .help() 44 + .version() 45 + .fail((msg, err) => { 46 + if (err) { 47 + console.error(err); 48 + } else { 49 + console.error(msg); 50 + } 51 + process.exit(1); 52 + }).argv; 53 + } 54 + 55 + process.on("unhandledRejection", (error: unknown) => { 56 + console.error("Unhandled promise rejection!"); 57 + console.error(error); 58 + process.exit(1); 59 + }); 60 + 61 + main().catch((error) => { 62 + console.error(error); 63 + process.exit(1); 64 + });
+68
packages/cli/src/commands/compile.ts
··· 1 + import { resolve } from "path"; 2 + import { spawn } from "child_process"; 3 + import { generateExternalsFile } from "../utils/externals-generator.js"; 4 + import { ensureMainImports } from "../utils/ensure-imports.js"; 5 + 6 + /** 7 + * Compile TypeSpec files to Lexicon JSON 8 + * 9 + * @param namespace - Primary namespace pattern (e.g., "app.bsky.*") 10 + * @param options - Additional compiler options 11 + */ 12 + export async function compileCommand( 13 + namespace: string, 14 + options: Record<string, unknown> = {} 15 + ): Promise<void> { 16 + const cwd = process.cwd(); 17 + const outDir = (options.out as string) || "./lexicons"; 18 + 19 + // Validate that output directory ends with 'lexicons' 20 + const normalizedPath = outDir.replace(/\\/g, '/').replace(/\/+$/, ''); 21 + if (!normalizedPath.endsWith('/lexicons') && normalizedPath !== 'lexicons' && normalizedPath !== './lexicons') { 22 + console.error(`Error: Output directory must end with 'lexicons'`); 23 + console.error(`Got: ${outDir}`); 24 + console.error(`Valid examples: ./lexicons, ../../lexicons, /path/to/lexicons`); 25 + process.exit(1); 26 + } 27 + 28 + // Generate externals first (scans the output directory for external lexicons) 29 + await generateExternalsFile(namespace, cwd, outDir); 30 + 31 + // Ensure required imports are present in main.tsp 32 + await ensureMainImports(cwd); 33 + 34 + // Compile TypeSpec using the TypeSpec CLI 35 + const entrypoint = resolve(cwd, "typelex/main.tsp"); 36 + const args = [ 37 + "compile", 38 + entrypoint, 39 + "--emit", 40 + "@typelex/emitter", 41 + "--option", 42 + `@typelex/emitter.emitter-output-dir={project-root}/${outDir}`, 43 + ]; 44 + 45 + if (options.watch) { 46 + args.push("--watch"); 47 + } 48 + 49 + return new Promise((resolve, reject) => { 50 + const tsp = spawn("tsp", args, { 51 + cwd, 52 + stdio: "inherit", 53 + }); 54 + 55 + tsp.on("close", (code) => { 56 + if (code === 0) { 57 + resolve(); 58 + } else { 59 + process.exit(code ?? 1); 60 + } 61 + }); 62 + 63 + tsp.on("error", (err) => { 64 + console.error("Failed to start TypeSpec compiler:", err); 65 + reject(err); 66 + }); 67 + }); 68 + }
+1
packages/cli/src/index.ts
··· 1 + export { compileCommand } from "./commands/compile.js";
+38
packages/cli/src/utils/ensure-imports.ts
··· 1 + import { readFile } from "fs/promises"; 2 + import { resolve } from "path"; 3 + 4 + const REQUIRED_FIRST_LINE = 'import "@typelex/emitter";'; 5 + const REQUIRED_SECOND_LINE = 'import "./externals.tsp";'; 6 + 7 + /** 8 + * Validates that main.tsp starts with the required imports. 9 + * Fails the build if the first two lines are not exactly as expected. 10 + * 11 + * @param cwd - Current working directory 12 + */ 13 + export async function ensureMainImports(cwd: string): Promise<void> { 14 + const mainPath = resolve(cwd, "typelex/main.tsp"); 15 + 16 + try { 17 + const content = await readFile(mainPath, "utf-8"); 18 + const lines = content.split("\n"); 19 + 20 + if (lines[0]?.trim() !== REQUIRED_FIRST_LINE) { 21 + console.error(`Error: main.tsp must start with: ${REQUIRED_FIRST_LINE}`); 22 + console.error(`Found: ${lines[0] || "(empty line)"}`); 23 + process.exit(1); 24 + } 25 + 26 + if (lines[1]?.trim() !== REQUIRED_SECOND_LINE) { 27 + console.error(`Error: Line 2 of main.tsp must be: ${REQUIRED_SECOND_LINE}`); 28 + console.error(`Found: ${lines[1] || "(empty line)"}`); 29 + process.exit(1); 30 + } 31 + } catch (err) { 32 + if ((err as NodeJS.ErrnoException).code === "ENOENT") { 33 + console.error("Error: typelex/main.tsp not found"); 34 + process.exit(1); 35 + } 36 + throw err; 37 + } 38 + }
+105
packages/cli/src/utils/externals-generator.ts
··· 1 + import { resolve } from "path"; 2 + import { writeFile, mkdir } from "fs/promises"; 3 + import { findExternalLexicons, LexiconDoc, isTokenDef, isModelDef } from "./lexicon.js"; 4 + 5 + /** 6 + * Convert camelCase to PascalCase 7 + */ 8 + function toPascalCase(str: string): string { 9 + return str.charAt(0).toUpperCase() + str.slice(1); 10 + } 11 + 12 + /** 13 + * Extract namespace prefix from pattern (e.g., "app.bsky.*" -> "app.bsky") 14 + */ 15 + function getNamespacePrefix(pattern: string): string { 16 + if (!pattern.endsWith(".*")) { 17 + throw new Error(`Namespace pattern must end with .*: ${pattern}`); 18 + } 19 + return pattern.slice(0, -2); 20 + } 21 + 22 + /** 23 + * Generate TypeSpec external definitions from lexicon documents 24 + */ 25 + function generateExternalsCode(lexicons: Map<string, LexiconDoc>): string { 26 + const lines: string[] = []; 27 + 28 + lines.push('import "@typelex/emitter";'); 29 + lines.push(""); 30 + lines.push("// Generated by typelex"); 31 + lines.push("// This file is auto-generated. Do not edit manually."); 32 + lines.push(""); 33 + 34 + // Sort namespaces for consistent output 35 + const sortedNamespaces = Array.from(lexicons.entries()).sort(([a], [b]) => 36 + a.localeCompare(b) 37 + ); 38 + 39 + for (const [nsid, lexicon] of sortedNamespaces) { 40 + lines.push("@external"); 41 + // Escape reserved keywords in namespace (like 'record') 42 + const escapedNsid = nsid.replace(/\b(record|union|enum|interface|namespace|model|op|import|using|extends|is|scalar|alias|if|else|return|void|never|unknown|any|true|false|null)\b/g, '`$1`'); 43 + lines.push(`namespace ${escapedNsid} {`); 44 + 45 + // Sort definitions for consistent output 46 + const sortedDefs = Object.entries(lexicon.defs).sort(([a], [b]) => 47 + a.localeCompare(b) 48 + ); 49 + 50 + for (const [defName, def] of sortedDefs) { 51 + if (!isModelDef(def)) { 52 + continue; 53 + } 54 + 55 + const modelName = toPascalCase(defName); 56 + const isToken = isTokenDef(def); 57 + 58 + if (isToken) { 59 + lines.push(` @token model ${modelName} { }`); 60 + } else { 61 + lines.push(` model ${modelName} { }`); 62 + } 63 + } 64 + 65 + lines.push("}"); 66 + lines.push(""); 67 + } 68 + 69 + return lines.join("\n"); 70 + } 71 + 72 + /** 73 + * Generate externals.tsp file for the given namespace pattern 74 + */ 75 + export async function generateExternalsFile( 76 + namespacePattern: string, 77 + cwd: string, 78 + outDir: string = "./lexicons" 79 + ): Promise<void> { 80 + try { 81 + const prefix = getNamespacePrefix(namespacePattern); 82 + const lexiconsDir = resolve(cwd, outDir); 83 + const outputFile = resolve(cwd, "typelex/externals.tsp"); 84 + 85 + const externals = await findExternalLexicons(lexiconsDir, prefix); 86 + 87 + if (externals.size === 0) { 88 + // No externals, create empty file 89 + await mkdir(resolve(cwd, "typelex"), { recursive: true }); 90 + await writeFile( 91 + outputFile, 92 + 'import "@typelex/emitter";\n\n// Generated by typelex\n// No external lexicons found\n', 93 + "utf-8" 94 + ); 95 + return; 96 + } 97 + 98 + const code = generateExternalsCode(externals); 99 + await mkdir(resolve(cwd, "typelex"), { recursive: true }); 100 + await writeFile(outputFile, code, "utf-8"); 101 + } catch (error) { 102 + // Re-throw with better context 103 + throw new Error(`Failed to generate externals: ${error instanceof Error ? error.message : String(error)}`); 104 + } 105 + }
+78
packages/cli/src/utils/lexicon.ts
··· 1 + import { readFile } from "fs/promises"; 2 + import { resolve } from "path"; 3 + import { globby } from "globby"; 4 + 5 + export interface LexiconDef { 6 + type: string; 7 + [key: string]: unknown; 8 + } 9 + 10 + export interface LexiconDoc { 11 + lexicon: number; 12 + id: string; 13 + defs: Record<string, LexiconDef>; 14 + } 15 + 16 + /** 17 + * Read and parse a lexicon JSON file 18 + */ 19 + export async function readLexicon(path: string): Promise<LexiconDoc> { 20 + const content = await readFile(path, "utf-8"); 21 + return JSON.parse(content); 22 + } 23 + 24 + /** 25 + * Find all lexicon files in a directory 26 + */ 27 + export async function findLexicons(dir: string): Promise<string[]> { 28 + try { 29 + const pattern = resolve(dir, "**/*.json"); 30 + return await globby(pattern); 31 + } catch { 32 + // If directory doesn't exist, return empty array 33 + return []; 34 + } 35 + } 36 + 37 + /** 38 + * Extract external lexicons that don't match the given namespace 39 + */ 40 + export async function findExternalLexicons( 41 + lexiconsDir: string, 42 + primaryNamespace: string 43 + ): Promise<Map<string, LexiconDoc>> { 44 + const files = await findLexicons(lexiconsDir); 45 + const externals = new Map<string, LexiconDoc>(); 46 + 47 + for (const file of files) { 48 + const lexicon = await readLexicon(file); 49 + if (!lexicon.id.startsWith(primaryNamespace)) { 50 + externals.set(lexicon.id, lexicon); 51 + } 52 + } 53 + 54 + return externals; 55 + } 56 + 57 + /** 58 + * Check if a definition is a token type 59 + */ 60 + export function isTokenDef(def: LexiconDef): boolean { 61 + return def.type === "token"; 62 + } 63 + 64 + /** 65 + * Check if a definition should become a model in TypeSpec 66 + */ 67 + export function isModelDef(def: LexiconDef): boolean { 68 + const type = def.type; 69 + return ( 70 + type === "object" || 71 + type === "token" || 72 + type === "record" || 73 + type === "union" || 74 + type === "string" || 75 + type === "bytes" || 76 + type === "cid-link" 77 + ); 78 + }
+20
packages/cli/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "target": "ES2022", 4 + "module": "Node16", 5 + "moduleResolution": "Node16", 6 + "lib": ["ES2022"], 7 + "outDir": "dist", 8 + "rootDir": "src", 9 + "declaration": true, 10 + "declarationMap": true, 11 + "sourceMap": true, 12 + "strict": true, 13 + "esModuleInterop": true, 14 + "skipLibCheck": true, 15 + "forceConsistentCasingInFileNames": true, 16 + "resolveJsonModule": true 17 + }, 18 + "include": ["src/**/*"], 19 + "exclude": ["node_modules", "dist"] 20 + }
+4
packages/cli/typelex/externals.tsp
··· 1 + import "@typelex/emitter"; 2 + 3 + // Generated by typelex 4 + // No external lexicons found
+1 -1
packages/emitter/package.json
··· 1 1 { 2 2 "name": "@typelex/emitter", 3 - "version": "0.1.6", 3 + "version": "0.2.0", 4 4 "description": "TypeSpec emitter for ATProto Lexicon definitions", 5 5 "main": "dist/index.js", 6 6 "type": "module",
+46
packages/emitter/test/integration/atproto/input/app/bsky/actor/defs.tsp
··· 372 372 isActive?: boolean; 373 373 } 374 374 } 375 + 376 + // --- Externals --- 377 + 378 + @external 379 + namespace com.atproto.label.defs { 380 + model Label { } 381 + } 382 + 383 + @external 384 + namespace app.bsky.graph.defs { 385 + model StarterPackViewBasic { } 386 + model ListViewBasic { } 387 + } 388 + 389 + @external 390 + namespace com.atproto.repo.strongRef { 391 + model Main { } 392 + } 393 + 394 + @external 395 + namespace app.bsky.notification.defs { 396 + model ActivitySubscription { } 397 + } 398 + 399 + @external 400 + namespace app.bsky.feed.threadgate { 401 + model MentionRule { } 402 + model FollowerRule { } 403 + model FollowingRule { } 404 + model ListRule { } 405 + } 406 + 407 + @external 408 + namespace app.bsky.feed.postgate { 409 + model DisableRule { } 410 + } 411 + 412 + @external 413 + namespace app.bsky.actor.status { 414 + @token model Live { } 415 + } 416 + 417 + @external 418 + namespace app.bsky.embed.external { 419 + model View { } 420 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getPreferences.tsp
··· 7 7 @required preferences: app.bsky.actor.defs.Preferences; 8 8 }; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace app.bsky.actor.defs { 15 + model Preferences { } 16 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getProfile.tsp
··· 8 8 @required actor: atIdentifier 9 9 ): app.bsky.actor.defs.ProfileViewDetailed; 10 10 } 11 + 12 + // --- Externals --- 13 + 14 + @external 15 + namespace app.bsky.actor.defs { 16 + model ProfileViewDetailed { } 17 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getProfiles.tsp
··· 10 10 @required profiles: app.bsky.actor.defs.ProfileViewDetailed[]; 11 11 }; 12 12 } 13 + 14 + // --- Externals --- 15 + 16 + @external 17 + namespace app.bsky.actor.defs { 18 + model ProfileViewDetailed { } 19 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getSuggestions.tsp
··· 19 19 recId?: int32; 20 20 }; 21 21 } 22 + 23 + // --- Externals --- 24 + 25 + @external 26 + namespace app.bsky.actor.defs { 27 + model ProfileView { } 28 + }
+12
packages/emitter/test/integration/atproto/input/app/bsky/actor/profile.tsp
··· 34 34 createdAt?: datetime; 35 35 } 36 36 } 37 + 38 + // --- Externals --- 39 + 40 + @external 41 + namespace com.atproto.label.defs { 42 + model SelfLabels { } 43 + } 44 + 45 + @external 46 + namespace com.atproto.repo.strongRef { 47 + model Main { } 48 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/putPreferences.tsp
··· 7 7 @required preferences: app.bsky.actor.defs.Preferences; 8 8 }): void; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace app.bsky.actor.defs { 15 + model Preferences { } 16 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/searchActors.tsp
··· 20 20 @required actors: app.bsky.actor.defs.ProfileView[]; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace app.bsky.actor.defs { 28 + model ProfileView { } 29 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/searchActorsTypeahead.tsp
··· 17 17 @required actors: app.bsky.actor.defs.ProfileViewBasic[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace app.bsky.actor.defs { 25 + model ProfileViewBasic { } 26 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/status.tsp
··· 22 22 @token 23 23 model Live {} 24 24 } 25 + 26 + // --- Externals --- 27 + 28 + @external 29 + namespace app.bsky.embed.external { 30 + model Main { } 31 + }
+14
packages/emitter/test/integration/atproto/input/app/bsky/bookmark/defs.tsp
··· 24 24 ); 25 25 } 26 26 } 27 + 28 + // --- Externals --- 29 + 30 + @external 31 + namespace com.atproto.repo.strongRef { 32 + model Main { } 33 + } 34 + 35 + @external 36 + namespace app.bsky.feed.defs { 37 + model BlockedPost { } 38 + model NotFoundPost { } 39 + model PostView { } 40 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/bookmark/getBookmarks.tsp
··· 14 14 @required bookmarks: app.bsky.bookmark.defs.BookmarkView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.bookmark.defs { 22 + model BookmarkView { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/embed/images.tsp
··· 40 40 aspectRatio?: app.bsky.embed.defs.AspectRatio; 41 41 } 42 42 } 43 + 44 + // --- Externals --- 45 + 46 + @external 47 + namespace app.bsky.embed.defs { 48 + model AspectRatio { } 49 + }
+54
packages/emitter/test/integration/atproto/input/app/bsky/embed/record.tsp
··· 74 74 detached: boolean = true; 75 75 } 76 76 } 77 + 78 + // --- Externals --- 79 + 80 + @external 81 + namespace com.atproto.repo.strongRef { 82 + model Main { } 83 + } 84 + 85 + @external 86 + namespace app.bsky.feed.defs { 87 + model GeneratorView { } 88 + model BlockedAuthor { } 89 + } 90 + 91 + @external 92 + namespace app.bsky.graph.defs { 93 + model ListView { } 94 + model StarterPackViewBasic { } 95 + } 96 + 97 + @external 98 + namespace app.bsky.labeler.defs { 99 + model LabelerView { } 100 + } 101 + 102 + @external 103 + namespace app.bsky.actor.defs { 104 + model ProfileViewBasic { } 105 + } 106 + 107 + @external 108 + namespace com.atproto.label.defs { 109 + model Label { } 110 + } 111 + 112 + @external 113 + namespace app.bsky.embed.images { 114 + model View { } 115 + } 116 + 117 + @external 118 + namespace app.bsky.embed.video { 119 + model View { } 120 + } 121 + 122 + @external 123 + namespace app.bsky.embed.external { 124 + model View { } 125 + } 126 + 127 + @external 128 + namespace app.bsky.embed.recordWithMedia { 129 + model View { } 130 + }
+26
packages/emitter/test/integration/atproto/input/app/bsky/embed/recordWithMedia.tsp
··· 26 26 ); 27 27 } 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace app.bsky.embed.`record` { 34 + model Main { } 35 + model View { } 36 + } 37 + 38 + @external 39 + namespace app.bsky.embed.images { 40 + model Main { } 41 + model View { } 42 + } 43 + 44 + @external 45 + namespace app.bsky.embed.video { 46 + model Main { } 47 + model View { } 48 + } 49 + 50 + @external 51 + namespace app.bsky.embed.external { 52 + model Main { } 53 + model View { } 54 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/embed/video.tsp
··· 36 36 aspectRatio?: app.bsky.embed.defs.AspectRatio; 37 37 } 38 38 } 39 + 40 + // --- Externals --- 41 + 42 + @external 43 + namespace app.bsky.embed.defs { 44 + model AspectRatio { } 45 + }
+49
packages/emitter/test/integration/atproto/input/app/bsky/feed/defs.tsp
··· 246 246 @token 247 247 model InteractionShare {} 248 248 } 249 + 250 + // --- Externals --- 251 + 252 + @external 253 + namespace app.bsky.actor.defs { 254 + model ProfileViewBasic { } 255 + model ViewerState { } 256 + model ProfileView { } 257 + } 258 + 259 + @external 260 + namespace app.bsky.embed.images { 261 + model View { } 262 + } 263 + 264 + @external 265 + namespace app.bsky.embed.video { 266 + model View { } 267 + } 268 + 269 + @external 270 + namespace app.bsky.embed.external { 271 + model View { } 272 + } 273 + 274 + @external 275 + namespace app.bsky.embed.`record` { 276 + model View { } 277 + } 278 + 279 + @external 280 + namespace app.bsky.embed.recordWithMedia { 281 + model View { } 282 + } 283 + 284 + @external 285 + namespace com.atproto.label.defs { 286 + model Label { } 287 + } 288 + 289 + @external 290 + namespace app.bsky.richtext.facet { 291 + model Main { } 292 + } 293 + 294 + @external 295 + namespace app.bsky.graph.defs { 296 + model ListViewBasic { } 297 + }
+18
packages/emitter/test/integration/atproto/input/app/bsky/feed/generator.tsp
··· 30 30 @required createdAt: datetime; 31 31 } 32 32 } 33 + 34 + // --- Externals --- 35 + 36 + @external 37 + namespace app.bsky.richtext.facet { 38 + model Main { } 39 + } 40 + 41 + @external 42 + namespace com.atproto.label.defs { 43 + model SelfLabels { } 44 + } 45 + 46 + @external 47 + namespace app.bsky.feed.defs { 48 + @token model ContentModeUnspecified { } 49 + @token model ContentModeVideo { } 50 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getActorFeeds.tsp
··· 16 16 @required feeds: app.bsky.feed.defs.GeneratorView[]; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace app.bsky.feed.defs { 24 + model GeneratorView { } 25 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getActorLikes.tsp
··· 20 20 @required feed: app.bsky.feed.defs.FeedViewPost[]; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace app.bsky.feed.defs { 28 + model FeedViewPost { } 29 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getAuthorFeed.tsp
··· 25 25 @required feed: app.bsky.feed.defs.FeedViewPost[]; 26 26 }; 27 27 } 28 + 29 + // --- Externals --- 30 + 31 + @external 32 + namespace app.bsky.feed.defs { 33 + model FeedViewPost { } 34 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeed.tsp
··· 19 19 @required feed: app.bsky.feed.defs.FeedViewPost[]; 20 20 }; 21 21 } 22 + 23 + // --- Externals --- 24 + 25 + @external 26 + namespace app.bsky.feed.defs { 27 + model FeedViewPost { } 28 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedGenerator.tsp
··· 18 18 isValid: boolean; 19 19 }; 20 20 } 21 + 22 + // --- Externals --- 23 + 24 + @external 25 + namespace app.bsky.feed.defs { 26 + model GeneratorView { } 27 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedGenerators.tsp
··· 9 9 @required feeds: app.bsky.feed.defs.GeneratorView[]; 10 10 }; 11 11 } 12 + 13 + // --- Externals --- 14 + 15 + @external 16 + namespace app.bsky.feed.defs { 17 + model GeneratorView { } 18 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedSkeleton.tsp
··· 26 26 reqId?: string; 27 27 }; 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace app.bsky.feed.defs { 34 + model SkeletonFeedPost { } 35 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getLikes.tsp
··· 28 28 @required actor: app.bsky.actor.defs.ProfileView; 29 29 } 30 30 } 31 + 32 + // --- Externals --- 33 + 34 + @external 35 + namespace app.bsky.actor.defs { 36 + model ProfileView { } 37 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getListFeed.tsp
··· 20 20 @required feed: app.bsky.feed.defs.FeedViewPost[]; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace app.bsky.feed.defs { 28 + model FeedViewPost { } 29 + }
+10
packages/emitter/test/integration/atproto/input/app/bsky/feed/getPostThread.tsp
··· 26 26 threadgate?: app.bsky.feed.defs.ThreadgateView; 27 27 }; 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace app.bsky.feed.defs { 34 + model ThreadViewPost { } 35 + model NotFoundPost { } 36 + model BlockedPost { } 37 + model ThreadgateView { } 38 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getPosts.tsp
··· 11 11 @required posts: app.bsky.feed.defs.PostView[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.feed.defs { 19 + model PostView { } 20 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getQuotes.tsp
··· 22 22 @required posts: app.bsky.feed.defs.PostView[]; 23 23 }; 24 24 } 25 + 26 + // --- Externals --- 27 + 28 + @external 29 + namespace app.bsky.feed.defs { 30 + model PostView { } 31 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getRepostedBy.tsp
··· 22 22 @required repostedBy: app.bsky.actor.defs.ProfileView[]; 23 23 }; 24 24 } 25 + 26 + // --- Externals --- 27 + 28 + @external 29 + namespace app.bsky.actor.defs { 30 + model ProfileView { } 31 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getSuggestedFeeds.tsp
··· 14 14 @required feeds: app.bsky.feed.defs.GeneratorView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.feed.defs { 22 + model GeneratorView { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getTimeline.tsp
··· 17 17 @required feed: app.bsky.feed.defs.FeedViewPost[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace app.bsky.feed.defs { 25 + model FeedViewPost { } 26 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/like.tsp
··· 13 13 via?: com.atproto.repo.strongRef.Main; 14 14 } 15 15 } 16 + 17 + // --- Externals --- 18 + 19 + @external 20 + namespace com.atproto.repo.strongRef { 21 + model Main { } 22 + }
+42
packages/emitter/test/integration/atproto/input/app/bsky/feed/post.tsp
··· 74 74 @maxGraphemes(64) 75 75 @maxLength(640) 76 76 scalar PostTag extends string; 77 + 78 + // --- Externals --- 79 + 80 + @external 81 + namespace app.bsky.richtext.facet { 82 + model Main { } 83 + } 84 + 85 + @external 86 + namespace app.bsky.embed.images { 87 + model Main { } 88 + } 89 + 90 + @external 91 + namespace app.bsky.embed.video { 92 + model Main { } 93 + } 94 + 95 + @external 96 + namespace app.bsky.embed.external { 97 + model Main { } 98 + } 99 + 100 + @external 101 + namespace app.bsky.embed.`record` { 102 + model Main { } 103 + } 104 + 105 + @external 106 + namespace app.bsky.embed.recordWithMedia { 107 + model Main { } 108 + } 109 + 110 + @external 111 + namespace com.atproto.label.defs { 112 + model SelfLabels { } 113 + } 114 + 115 + @external 116 + namespace com.atproto.repo.strongRef { 117 + model Main { } 118 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/repost.tsp
··· 9 9 via?: com.atproto.repo.strongRef.Main; 10 10 } 11 11 } 12 + 13 + // --- Externals --- 14 + 15 + @external 16 + namespace com.atproto.repo.strongRef { 17 + model Main { } 18 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/searchPosts.tsp
··· 56 56 @required posts: app.bsky.feed.defs.PostView[]; 57 57 }; 58 58 } 59 + 60 + // --- Externals --- 61 + 62 + @external 63 + namespace app.bsky.feed.defs { 64 + model PostView { } 65 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/sendInteractions.tsp
··· 7 7 @required interactions: app.bsky.feed.defs.Interaction[]; 8 8 }): {}; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace app.bsky.feed.defs { 15 + model Interaction { } 16 + }
+23
packages/emitter/test/integration/atproto/input/app/bsky/graph/defs.tsp
··· 139 139 followedBy?: atUri; 140 140 } 141 141 } 142 + 143 + // --- Externals --- 144 + 145 + @external 146 + namespace com.atproto.label.defs { 147 + model Label { } 148 + } 149 + 150 + @external 151 + namespace app.bsky.actor.defs { 152 + model ProfileView { } 153 + model ProfileViewBasic { } 154 + } 155 + 156 + @external 157 + namespace app.bsky.richtext.facet { 158 + model Main { } 159 + } 160 + 161 + @external 162 + namespace app.bsky.feed.defs { 163 + model GeneratorView { } 164 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getActorStarterPacks.tsp
··· 16 16 @required starterPacks: app.bsky.graph.defs.StarterPackViewBasic[]; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace app.bsky.graph.defs { 24 + model StarterPackViewBasic { } 25 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getBlocks.tsp
··· 14 14 @required blocks: app.bsky.actor.defs.ProfileView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.actor.defs { 22 + model ProfileView { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getFollowers.tsp
··· 17 17 @required followers: app.bsky.actor.defs.ProfileView[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace app.bsky.actor.defs { 25 + model ProfileView { } 26 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getFollows.tsp
··· 17 17 @required follows: app.bsky.actor.defs.ProfileView[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace app.bsky.actor.defs { 25 + model ProfileView { } 26 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getKnownFollowers.tsp
··· 17 17 @required followers: app.bsky.actor.defs.ProfileView[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace app.bsky.actor.defs { 25 + model ProfileView { } 26 + }
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getList.tsp
··· 18 18 @required items: app.bsky.graph.defs.ListItemView[]; 19 19 }; 20 20 } 21 + 22 + // --- Externals --- 23 + 24 + @external 25 + namespace app.bsky.graph.defs { 26 + model ListView { } 27 + model ListItemView { } 28 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListBlocks.tsp
··· 14 14 @required lists: app.bsky.graph.defs.ListView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.graph.defs { 22 + model ListView { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListMutes.tsp
··· 14 14 @required lists: app.bsky.graph.defs.ListView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.graph.defs { 22 + model ListView { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getLists.tsp
··· 20 20 @required lists: app.bsky.graph.defs.ListView[]; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace app.bsky.graph.defs { 28 + model ListView { } 29 + }
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListsWithMembership.tsp
··· 27 27 listItem?: app.bsky.graph.defs.ListItemView; 28 28 } 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace app.bsky.graph.defs { 35 + model ListView { } 36 + model ListItemView { } 37 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getMutes.tsp
··· 14 14 @required mutes: app.bsky.actor.defs.ProfileView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.actor.defs { 22 + model ProfileView { } 23 + }
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getRelationships.tsp
··· 26 26 /** the primary actor at-identifier could not be resolved */ 27 27 model ActorNotFound {} 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace app.bsky.graph.defs { 34 + model Relationship { } 35 + model NotFoundActor { } 36 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPack.tsp
··· 11 11 @required starterPack: app.bsky.graph.defs.StarterPackView; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.graph.defs { 19 + model StarterPackView { } 20 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPacks.tsp
··· 11 11 @required starterPacks: app.bsky.graph.defs.StarterPackViewBasic[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.graph.defs { 19 + model StarterPackViewBasic { } 20 + }
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPacksWithMembership.tsp
··· 24 24 listItem?: app.bsky.graph.defs.ListItemView; 25 25 } 26 26 } 27 + 28 + // --- Externals --- 29 + 30 + @external 31 + namespace app.bsky.graph.defs { 32 + model StarterPackView { } 33 + model ListItemView { } 34 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getSuggestedFollowsByActor.tsp
··· 16 16 recId?: int32; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace app.bsky.actor.defs { 24 + model ProfileView { } 25 + }
+17
packages/emitter/test/integration/atproto/input/app/bsky/graph/list.tsp
··· 27 27 @required createdAt: datetime; 28 28 } 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace app.bsky.graph.defs { 35 + model ListPurpose { } 36 + } 37 + 38 + @external 39 + namespace app.bsky.richtext.facet { 40 + model Main { } 41 + } 42 + 43 + @external 44 + namespace com.atproto.label.defs { 45 + model SelfLabels { } 46 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/searchStarterPacks.tsp
··· 18 18 @required starterPacks: app.bsky.graph.defs.StarterPackViewBasic[]; 19 19 }; 20 20 } 21 + 22 + // --- Externals --- 23 + 24 + @external 25 + namespace app.bsky.graph.defs { 26 + model StarterPackViewBasic { } 27 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/starterpack.tsp
··· 33 33 uri: atUri; 34 34 } 35 35 } 36 + 37 + // --- Externals --- 38 + 39 + @external 40 + namespace app.bsky.richtext.facet { 41 + model Main { } 42 + }
+20
packages/emitter/test/integration/atproto/input/app/bsky/labeler/defs.tsp
··· 54 54 labelValueDefinitions?: com.atproto.label.defs.LabelValueDefinition[]; 55 55 } 56 56 } 57 + 58 + // --- Externals --- 59 + 60 + @external 61 + namespace app.bsky.actor.defs { 62 + model ProfileView { } 63 + } 64 + 65 + @external 66 + namespace com.atproto.label.defs { 67 + model Label { } 68 + model LabelValue { } 69 + model LabelValueDefinition { } 70 + } 71 + 72 + @external 73 + namespace com.atproto.moderation.defs { 74 + model ReasonType { } 75 + model SubjectType { } 76 + }
+8
packages/emitter/test/integration/atproto/input/app/bsky/labeler/getServices.tsp
··· 15 15 )[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace app.bsky.labeler.defs { 23 + model LabelerView { } 24 + model LabelerViewDetailed { } 25 + }
+18
packages/emitter/test/integration/atproto/input/app/bsky/labeler/service.tsp
··· 20 20 subjectCollections?: nsid[]; 21 21 } 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace app.bsky.labeler.defs { 28 + model LabelerPolicies { } 29 + } 30 + 31 + @external 32 + namespace com.atproto.label.defs { 33 + model SelfLabels { } 34 + } 35 + 36 + @external 37 + namespace com.atproto.moderation.defs { 38 + model ReasonType { } 39 + model SubjectType { } 40 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/getPreferences.tsp
··· 7 7 @required preferences: app.bsky.notification.defs.Preferences; 8 8 }; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace app.bsky.notification.defs { 15 + model Preferences { } 16 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/listActivitySubscriptions.tsp
··· 14 14 @required subscriptions: app.bsky.actor.defs.ProfileView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.actor.defs { 22 + model ProfileView { } 23 + }
+12
packages/emitter/test/integration/atproto/input/app/bsky/notification/listNotifications.tsp
··· 40 40 labels?: com.atproto.label.defs.Label[]; 41 41 }; 42 42 } 43 + 44 + // --- Externals --- 45 + 46 + @external 47 + namespace app.bsky.actor.defs { 48 + model ProfileView { } 49 + } 50 + 51 + @external 52 + namespace com.atproto.label.defs { 53 + model Label { } 54 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/putActivitySubscription.tsp
··· 13 13 activitySubscription?: app.bsky.notification.defs.ActivitySubscription; 14 14 }; 15 15 } 16 + 17 + // --- Externals --- 18 + 19 + @external 20 + namespace app.bsky.notification.defs { 21 + model ActivitySubscription { } 22 + }
+10
packages/emitter/test/integration/atproto/input/app/bsky/notification/putPreferencesV2.tsp
··· 21 21 @required preferences: app.bsky.notification.defs.Preferences; 22 22 }; 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace app.bsky.notification.defs { 29 + model ChatPreference { } 30 + model FilterablePreference { } 31 + model Preference { } 32 + model Preferences { } 33 + }
+13
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/defs.tsp
··· 114 114 completeUa?: string; 115 115 } 116 116 } 117 + 118 + // --- Externals --- 119 + 120 + @external 121 + namespace app.bsky.actor.defs { 122 + model ProfileViewBasic { } 123 + } 124 + 125 + @external 126 + namespace app.bsky.feed.defs { 127 + model PostView { } 128 + model BlockedAuthor { } 129 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getAgeAssuranceState.tsp
··· 5 5 @query 6 6 op main(): app.bsky.unspecced.defs.AgeAssuranceState; 7 7 } 8 + 9 + // --- Externals --- 10 + 11 + @external 12 + namespace app.bsky.unspecced.defs { 13 + model AgeAssuranceState { } 14 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.tsp
··· 11 11 @required starterPacks: app.bsky.graph.defs.StarterPackView[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.graph.defs { 19 + model StarterPackView { } 20 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPopularFeedGenerators.tsp
··· 15 15 @required feeds: app.bsky.feed.defs.GeneratorView[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace app.bsky.feed.defs { 23 + model GeneratorView { } 24 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPostThreadOtherV2.tsp
··· 26 26 @required value: (app.bsky.unspecced.defs.ThreadItemPost | unknown); 27 27 } 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace app.bsky.unspecced.defs { 34 + model ThreadItemPost { } 35 + }
+15
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPostThreadV2.tsp
··· 55 55 ); 56 56 } 57 57 } 58 + 59 + // --- Externals --- 60 + 61 + @external 62 + namespace app.bsky.feed.defs { 63 + model ThreadgateView { } 64 + } 65 + 66 + @external 67 + namespace app.bsky.unspecced.defs { 68 + model ThreadItemPost { } 69 + model ThreadItemNoUnauthenticated { } 70 + model ThreadItemNotFound { } 71 + model ThreadItemBlocked { } 72 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedFeeds.tsp
··· 11 11 @required feeds: app.bsky.feed.defs.GeneratorView[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.feed.defs { 19 + model GeneratorView { } 20 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedStarterPacks.tsp
··· 11 11 @required starterPacks: app.bsky.graph.defs.StarterPackView[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.graph.defs { 19 + model StarterPackView { } 20 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedUsers.tsp
··· 14 14 @required actors: app.bsky.actor.defs.ProfileView[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.actor.defs { 22 + model ProfileView { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestionsSkeleton.tsp
··· 26 26 recId?: integer; 27 27 }; 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace app.bsky.unspecced.defs { 34 + model SkeletonSearchActor { } 35 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrendingTopics.tsp
··· 15 15 @required suggested: app.bsky.unspecced.defs.TrendingTopic[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace app.bsky.unspecced.defs { 23 + model TrendingTopic { } 24 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrends.tsp
··· 11 11 @required trends: app.bsky.unspecced.defs.TrendView[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace app.bsky.unspecced.defs { 19 + model TrendView { } 20 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrendsSkeleton.tsp
··· 14 14 @required trends: app.bsky.unspecced.defs.SkeletonTrend[]; 15 15 }; 16 16 } 17 + 18 + // --- Externals --- 19 + 20 + @external 21 + namespace app.bsky.unspecced.defs { 22 + model SkeletonTrend { } 23 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/initAgeAssurance.tsp
··· 22 22 countryCode: string; 23 23 }): app.bsky.unspecced.defs.AgeAssuranceState; 24 24 } 25 + 26 + // --- Externals --- 27 + 28 + @external 29 + namespace app.bsky.unspecced.defs { 30 + model AgeAssuranceState { } 31 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchActorsSkeleton.tsp
··· 31 31 @required actors: app.bsky.unspecced.defs.SkeletonSearchActor[]; 32 32 }; 33 33 } 34 + 35 + // --- Externals --- 36 + 37 + @external 38 + namespace app.bsky.unspecced.defs { 39 + model SkeletonSearchActor { } 40 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchPostsSkeleton.tsp
··· 59 59 @required posts: app.bsky.unspecced.defs.SkeletonSearchPost[]; 60 60 }; 61 61 } 62 + 63 + // --- Externals --- 64 + 65 + @external 66 + namespace app.bsky.unspecced.defs { 67 + model SkeletonSearchPost { } 68 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchStarterPacksSkeleton.tsp
··· 28 28 @required starterPacks: app.bsky.unspecced.defs.SkeletonSearchStarterPack[]; 29 29 }; 30 30 } 31 + 32 + // --- Externals --- 33 + 34 + @external 35 + namespace app.bsky.unspecced.defs { 36 + model SkeletonSearchStarterPack { } 37 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/video/getJobStatus.tsp
··· 9 9 @required jobStatus: app.bsky.video.defs.JobStatus; 10 10 }; 11 11 } 12 + 13 + // --- Externals --- 14 + 15 + @external 16 + namespace app.bsky.video.defs { 17 + model JobStatus { } 18 + }
+7
packages/emitter/test/integration/atproto/input/app/bsky/video/uploadVideo.tsp
··· 10 10 @required jobStatus: app.bsky.video.defs.JobStatus; 11 11 }; 12 12 } 13 + 14 + // --- Externals --- 15 + 16 + @external 17 + namespace app.bsky.video.defs { 18 + model JobStatus { } 19 + }
+14
packages/emitter/test/integration/atproto/input/chat/bsky/actor/defs.tsp
··· 20 20 verification?: app.bsky.actor.defs.VerificationState; 21 21 } 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace app.bsky.actor.defs { 28 + model ProfileAssociated { } 29 + model ViewerState { } 30 + model VerificationState { } 31 + } 32 + 33 + @external 34 + namespace com.atproto.label.defs { 35 + model Label { } 36 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/addReaction.tsp
··· 27 27 @required message: chat.bsky.convo.defs.MessageView; 28 28 }; 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace chat.bsky.convo.defs { 35 + model MessageView { } 36 + }
+18
packages/emitter/test/integration/atproto/input/chat/bsky/convo/defs.tsp
··· 139 139 @required reaction: ReactionView; 140 140 } 141 141 } 142 + 143 + // --- Externals --- 144 + 145 + @external 146 + namespace app.bsky.richtext.facet { 147 + model Main { } 148 + } 149 + 150 + @external 151 + namespace app.bsky.embed.`record` { 152 + model Main { } 153 + model View { } 154 + } 155 + 156 + @external 157 + namespace chat.bsky.actor.defs { 158 + model ProfileViewBasic { } 159 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/deleteMessageForSelf.tsp
··· 7 7 @required messageId: string; 8 8 }): chat.bsky.convo.defs.DeletedMessageView; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace chat.bsky.convo.defs { 15 + model DeletedMessageView { } 16 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvo.tsp
··· 6 6 @required convo: chat.bsky.convo.defs.ConvoView; 7 7 }; 8 8 } 9 + 10 + // --- Externals --- 11 + 12 + @external 13 + namespace chat.bsky.convo.defs { 14 + model ConvoView { } 15 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvoAvailability.tsp
··· 13 13 convo?: chat.bsky.convo.defs.ConvoView; 14 14 }; 15 15 } 16 + 17 + // --- Externals --- 18 + 19 + @external 20 + namespace chat.bsky.convo.defs { 21 + model ConvoView { } 22 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvoForMembers.tsp
··· 11 11 @required convo: chat.bsky.convo.defs.ConvoView; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace chat.bsky.convo.defs { 19 + model ConvoView { } 20 + }
+16
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getLog.tsp
··· 21 21 )[]; 22 22 }; 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace chat.bsky.convo.defs { 29 + model LogBeginConvo { } 30 + model LogAcceptConvo { } 31 + model LogLeaveConvo { } 32 + model LogMuteConvo { } 33 + model LogUnmuteConvo { } 34 + model LogCreateMessage { } 35 + model LogDeleteMessage { } 36 + model LogReadMessage { } 37 + model LogAddReaction { } 38 + model LogRemoveReaction { } 39 + }
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getMessages.tsp
··· 21 21 )[]; 22 22 }; 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace chat.bsky.convo.defs { 29 + model MessageView { } 30 + model DeletedMessageView { } 31 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/listConvos.tsp
··· 17 17 @required convos: chat.bsky.convo.defs.ConvoView[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace chat.bsky.convo.defs { 25 + model ConvoView { } 26 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/muteConvo.tsp
··· 8 8 @required convo: chat.bsky.convo.defs.ConvoView; 9 9 }; 10 10 } 11 + 12 + // --- Externals --- 13 + 14 + @external 15 + namespace chat.bsky.convo.defs { 16 + model ConvoView { } 17 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/removeReaction.tsp
··· 24 24 @required message: chat.bsky.convo.defs.MessageView; 25 25 }; 26 26 } 27 + 28 + // --- Externals --- 29 + 30 + @external 31 + namespace chat.bsky.convo.defs { 32 + model MessageView { } 33 + }
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/sendMessage.tsp
··· 7 7 @required message: chat.bsky.convo.defs.MessageInput; 8 8 }): chat.bsky.convo.defs.MessageView; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace chat.bsky.convo.defs { 15 + model MessageInput { } 16 + model MessageView { } 17 + }
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/sendMessageBatch.tsp
··· 15 15 @required message: chat.bsky.convo.defs.MessageInput; 16 16 } 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace chat.bsky.convo.defs { 23 + model MessageView { } 24 + model MessageInput { } 25 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/unmuteConvo.tsp
··· 8 8 @required convo: chat.bsky.convo.defs.ConvoView; 9 9 }; 10 10 } 11 + 12 + // --- Externals --- 13 + 14 + @external 15 + namespace chat.bsky.convo.defs { 16 + model ConvoView { } 17 + }
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/updateRead.tsp
··· 9 9 @required convo: chat.bsky.convo.defs.ConvoView; 10 10 }; 11 11 } 12 + 13 + // --- Externals --- 14 + 15 + @external 16 + namespace chat.bsky.convo.defs { 17 + model ConvoView { } 18 + }
+8
packages/emitter/test/integration/atproto/input/chat/bsky/moderation/getMessageContext.tsp
··· 20 20 )[]; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace chat.bsky.convo.defs { 28 + model MessageView { } 29 + model DeletedMessageView { } 30 + }
+8
packages/emitter/test/integration/atproto/input/com/atproto/admin/defs.tsp
··· 38 38 @required value: string; 39 39 } 40 40 } 41 + 42 + // --- Externals --- 43 + 44 + @external 45 + namespace com.atproto.server.defs { 46 + model InviteCode { } 47 + model InviteCodeUse { } 48 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getAccountInfo.tsp
··· 7 7 @required did: did 8 8 ): com.atproto.admin.defs.AccountView; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace com.atproto.admin.defs { 15 + model AccountView { } 16 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getAccountInfos.tsp
··· 9 9 @required infos: com.atproto.admin.defs.AccountView[]; 10 10 }; 11 11 } 12 + 13 + // --- Externals --- 14 + 15 + @external 16 + namespace com.atproto.admin.defs { 17 + model AccountView { } 18 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getInviteCodes.tsp
··· 16 16 @required codes: com.atproto.server.defs.InviteCode[]; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace com.atproto.server.defs { 24 + model InviteCode { } 25 + }
+14
packages/emitter/test/integration/atproto/input/com/atproto/admin/getSubjectStatus.tsp
··· 20 20 deactivated?: com.atproto.admin.defs.StatusAttr; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace com.atproto.admin.defs { 28 + model RepoRef { } 29 + model RepoBlobRef { } 30 + model StatusAttr { } 31 + } 32 + 33 + @external 34 + namespace com.atproto.repo.strongRef { 35 + model Main { } 36 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/searchAccounts.tsp
··· 15 15 @required accounts: com.atproto.admin.defs.AccountView[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace com.atproto.admin.defs { 23 + model AccountView { } 24 + }
+14
packages/emitter/test/integration/atproto/input/com/atproto/admin/updateSubjectStatus.tsp
··· 26 26 takedown?: com.atproto.admin.defs.StatusAttr; 27 27 }; 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace com.atproto.admin.defs { 34 + model RepoRef { } 35 + model RepoBlobRef { } 36 + model StatusAttr { } 37 + } 38 + 39 + @external 40 + namespace com.atproto.repo.strongRef { 41 + model Main { } 42 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/identity/refreshIdentity.tsp
··· 17 17 @required identifier: atIdentifier; 18 18 }): com.atproto.identity.defs.IdentityInfo; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace com.atproto.identity.defs { 25 + model IdentityInfo { } 26 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/identity/resolveIdentity.tsp
··· 19 19 identifier: atIdentifier 20 20 ): com.atproto.identity.defs.IdentityInfo; 21 21 } 22 + 23 + // --- Externals --- 24 + 25 + @external 26 + namespace com.atproto.identity.defs { 27 + model IdentityInfo { } 28 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/label/queryLabels.tsp
··· 21 21 @required labels: com.atproto.label.defs.Label[]; 22 22 }; 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace com.atproto.label.defs { 29 + model Label { } 30 + }
+8
packages/emitter/test/integration/atproto/input/com/atproto/label/subscribeLabels.tsp
··· 21 21 cursor?: integer 22 22 ): (Labels | Info); 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace com.atproto.label.defs { 29 + model Label { } 30 + model Info { } 31 + }
+17
packages/emitter/test/integration/atproto/input/com/atproto/moderation/createReport.tsp
··· 50 50 meta?: unknown; 51 51 } 52 52 } 53 + 54 + // --- Externals --- 55 + 56 + @external 57 + namespace com.atproto.moderation.defs { 58 + model ReasonType { } 59 + } 60 + 61 + @external 62 + namespace com.atproto.admin.defs { 63 + model RepoRef { } 64 + } 65 + 66 + @external 67 + namespace com.atproto.repo.strongRef { 68 + model Main { } 69 + }
+51
packages/emitter/test/integration/atproto/input/com/atproto/moderation/defs.tsp
··· 93 93 string, 94 94 } 95 95 } 96 + 97 + // --- Externals --- 98 + 99 + @external 100 + namespace tools.ozone.report.defs { 101 + @token model ReasonAppeal { } 102 + @token model ReasonChildSafetyCSAM { } 103 + @token model ReasonChildSafetyEndangerment { } 104 + @token model ReasonChildSafetyGroom { } 105 + @token model ReasonChildSafetyHarassment { } 106 + @token model ReasonChildSafetyMinorPrivacy { } 107 + @token model ReasonChildSafetyOther { } 108 + @token model ReasonChildSafetyPromotion { } 109 + @token model ReasonCivicDisclosure { } 110 + @token model ReasonCivicElectoralProcess { } 111 + @token model ReasonCivicImpersonation { } 112 + @token model ReasonCivicInterference { } 113 + @token model ReasonCivicMisinformation { } 114 + @token model ReasonHarassmentDoxxing { } 115 + @token model ReasonHarassmentHateSpeech { } 116 + @token model ReasonHarassmentOther { } 117 + @token model ReasonHarassmentTargeted { } 118 + @token model ReasonHarassmentTroll { } 119 + @token model ReasonMisleadingBot { } 120 + @token model ReasonMisleadingImpersonation { } 121 + @token model ReasonMisleadingMisinformation { } 122 + @token model ReasonMisleadingOther { } 123 + @token model ReasonMisleadingScam { } 124 + @token model ReasonMisleadingSpam { } 125 + @token model ReasonMisleadingSyntheticContent { } 126 + @token model ReasonRuleBanEvasion { } 127 + @token model ReasonRuleOther { } 128 + @token model ReasonRuleProhibitedSales { } 129 + @token model ReasonRuleSiteSecurity { } 130 + @token model ReasonRuleStolenContent { } 131 + @token model ReasonSexualAbuseContent { } 132 + @token model ReasonSexualAnimal { } 133 + @token model ReasonSexualDeepfake { } 134 + @token model ReasonSexualNCII { } 135 + @token model ReasonSexualOther { } 136 + @token model ReasonSexualSextortion { } 137 + @token model ReasonSexualUnlabeled { } 138 + @token model ReasonViolenceAnimalWelfare { } 139 + @token model ReasonViolenceExtremistContent { } 140 + @token model ReasonViolenceGlorification { } 141 + @token model ReasonViolenceGraphicContent { } 142 + @token model ReasonViolenceOther { } 143 + @token model ReasonViolenceSelfHarm { } 144 + @token model ReasonViolenceThreats { } 145 + @token model ReasonViolenceTrafficking { } 146 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/applyWrites.tsp
··· 79 79 80 80 model DeleteResult {} 81 81 } 82 + 83 + // --- Externals --- 84 + 85 + @external 86 + namespace com.atproto.repo.defs { 87 + model CommitMeta { } 88 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/createRecord.tsp
··· 36 36 /** Indicates that 'swapCommit' didn't match current repo commit. */ 37 37 model InvalidSwap {} 38 38 } 39 + 40 + // --- Externals --- 41 + 42 + @external 43 + namespace com.atproto.repo.defs { 44 + model CommitMeta { } 45 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/deleteRecord.tsp
··· 28 28 29 29 model InvalidSwap {} 30 30 } 31 + 32 + // --- Externals --- 33 + 34 + @external 35 + namespace com.atproto.repo.defs { 36 + model CommitMeta { } 37 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/putRecord.tsp
··· 39 39 40 40 model InvalidSwap {} 41 41 } 42 + 43 + // --- Externals --- 44 + 45 + @external 46 + namespace com.atproto.repo.defs { 47 + model CommitMeta { } 48 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/server/getAccountInviteCodes.tsp
··· 15 15 @required codes: com.atproto.server.defs.InviteCode[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace com.atproto.server.defs { 23 + model InviteCode { } 24 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/sync/getHostStatus.tsp
··· 22 22 23 23 model HostNotFound {} 24 24 } 25 + 26 + // --- Externals --- 27 + 28 + @external 29 + namespace com.atproto.sync.defs { 30 + model HostStatus { } 31 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/sync/listHosts.tsp
··· 29 29 status?: com.atproto.sync.defs.HostStatus; 30 30 } 31 31 } 32 + 33 + // --- Externals --- 34 + 35 + @external 36 + namespace com.atproto.sync.defs { 37 + model HostStatus { } 38 + }
+7
packages/emitter/test/integration/atproto/input/com/atproto/temp/fetchLabels.tsp
··· 13 13 @required labels: com.atproto.label.defs.Label[]; 14 14 }; 15 15 } 16 + 17 + // --- Externals --- 18 + 19 + @external 20 + namespace com.atproto.label.defs { 21 + model Label { } 22 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/createTemplate.tsp
··· 26 26 createdBy?: did; 27 27 }): tools.ozone.communication.defs.TemplateView; 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace tools.ozone.communication.defs { 34 + model TemplateView { } 35 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/listTemplates.tsp
··· 7 7 @required communicationTemplates: tools.ozone.communication.defs.TemplateView[]; 8 8 }; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace tools.ozone.communication.defs { 15 + model TemplateView { } 16 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/updateTemplate.tsp
··· 29 29 disabled?: boolean; 30 30 }): tools.ozone.communication.defs.TemplateView; 31 31 } 32 + 33 + // --- Externals --- 34 + 35 + @external 36 + namespace tools.ozone.communication.defs { 37 + model TemplateView { } 38 + }
+34
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/defs.tsp
··· 601 601 @token 602 602 model TimelineEventPlcTombstone {} 603 603 } 604 + 605 + // --- Externals --- 606 + 607 + @external 608 + namespace com.atproto.admin.defs { 609 + model RepoRef { } 610 + model ThreatSignature { } 611 + } 612 + 613 + @external 614 + namespace com.atproto.repo.strongRef { 615 + model Main { } 616 + } 617 + 618 + @external 619 + namespace chat.bsky.convo.defs { 620 + model MessageRef { } 621 + } 622 + 623 + @external 624 + namespace com.atproto.moderation.defs { 625 + model SubjectType { } 626 + model ReasonType { } 627 + } 628 + 629 + @external 630 + namespace com.atproto.server.defs { 631 + model InviteCode { } 632 + } 633 + 634 + @external 635 + namespace com.atproto.label.defs { 636 + model Label { } 637 + }
+40
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/emitEvent.tsp
··· 54 54 externalId?: string; 55 55 }): tools.ozone.moderation.defs.ModEventView; 56 56 } 57 + 58 + // --- Externals --- 59 + 60 + @external 61 + namespace tools.ozone.moderation.defs { 62 + model ModEventTakedown { } 63 + model ModEventAcknowledge { } 64 + model ModEventEscalate { } 65 + model ModEventComment { } 66 + model ModEventLabel { } 67 + model ModEventReport { } 68 + model ModEventMute { } 69 + model ModEventUnmute { } 70 + model ModEventMuteReporter { } 71 + model ModEventUnmuteReporter { } 72 + model ModEventReverseTakedown { } 73 + model ModEventResolveAppeal { } 74 + model ModEventEmail { } 75 + model ModEventDivert { } 76 + model ModEventTag { } 77 + model AccountEvent { } 78 + model IdentityEvent { } 79 + model RecordEvent { } 80 + model ModEventPriorityScore { } 81 + model AgeAssuranceEvent { } 82 + model AgeAssuranceOverrideEvent { } 83 + model RevokeAccountCredentialsEvent { } 84 + model ModTool { } 85 + model ModEventView { } 86 + } 87 + 88 + @external 89 + namespace com.atproto.admin.defs { 90 + model RepoRef { } 91 + } 92 + 93 + @external 94 + namespace com.atproto.repo.strongRef { 95 + model Main { } 96 + }
+39
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getAccountTimeline.tsp
··· 55 55 @required count: integer; 56 56 } 57 57 } 58 + 59 + // --- Externals --- 60 + 61 + @external 62 + namespace tools.ozone.moderation.defs { 63 + model ModEventTakedown { } 64 + model ModEventReverseTakedown { } 65 + model ModEventComment { } 66 + model ModEventReport { } 67 + model ModEventLabel { } 68 + model ModEventAcknowledge { } 69 + model ModEventEscalate { } 70 + model ModEventMute { } 71 + model ModEventUnmute { } 72 + model ModEventMuteReporter { } 73 + model ModEventUnmuteReporter { } 74 + model ModEventEmail { } 75 + model ModEventResolveAppeal { } 76 + model ModEventDivert { } 77 + model ModEventTag { } 78 + model AccountEvent { } 79 + model IdentityEvent { } 80 + model RecordEvent { } 81 + model ModEventPriorityScore { } 82 + model RevokeAccountCredentialsEvent { } 83 + model AgeAssuranceEvent { } 84 + model AgeAssuranceOverrideEvent { } 85 + @token model TimelineEventPlcCreate { } 86 + @token model TimelineEventPlcOperation { } 87 + @token model TimelineEventPlcTombstone { } 88 + } 89 + 90 + @external 91 + namespace tools.ozone.hosting.getAccountHistory { 92 + model AccountCreated { } 93 + model EmailConfirmed { } 94 + model PasswordUpdated { } 95 + model HandleUpdated { } 96 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getEvent.tsp
··· 5 5 @query 6 6 op main(@required id: integer): tools.ozone.moderation.defs.ModEventViewDetail; 7 7 } 8 + 9 + // --- Externals --- 10 + 11 + @external 12 + namespace tools.ozone.moderation.defs { 13 + model ModEventViewDetail { } 14 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRecord.tsp
··· 8 8 @errors(RecordNotFound) 9 9 op main(@required uri: atUri, cid?: cid): tools.ozone.moderation.defs.RecordViewDetail; 10 10 } 11 + 12 + // --- Externals --- 13 + 14 + @external 15 + namespace tools.ozone.moderation.defs { 16 + model RecordViewDetail { } 17 + }
+8
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRecords.tsp
··· 16 16 )[]; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace tools.ozone.moderation.defs { 24 + model RecordViewDetail { } 25 + model RecordViewNotFound { } 26 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRepo.tsp
··· 8 8 @errors(RepoNotFound) 9 9 op main(@required did: did): tools.ozone.moderation.defs.RepoViewDetail; 10 10 } 11 + 12 + // --- Externals --- 13 + 14 + @external 15 + namespace tools.ozone.moderation.defs { 16 + model RepoViewDetail { } 17 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getReporterStats.tsp
··· 11 11 @required stats: tools.ozone.moderation.defs.ReporterStats[]; 12 12 }; 13 13 } 14 + 15 + // --- Externals --- 16 + 17 + @external 18 + namespace tools.ozone.moderation.defs { 19 + model ReporterStats { } 20 + }
+8
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRepos.tsp
··· 16 16 )[]; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace tools.ozone.moderation.defs { 24 + model RepoViewDetail { } 25 + model RepoViewNotFound { } 26 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getSubjects.tsp
··· 12 12 @required subjects: tools.ozone.moderation.defs.SubjectView[]; 13 13 }; 14 14 } 15 + 16 + // --- Externals --- 17 + 18 + @external 19 + namespace tools.ozone.moderation.defs { 20 + model SubjectView { } 21 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/queryEvents.tsp
··· 80 80 @required events: tools.ozone.moderation.defs.ModEventView[]; 81 81 }; 82 82 } 83 + 84 + // --- Externals --- 85 + 86 + @external 87 + namespace tools.ozone.moderation.defs { 88 + model ModEventView { } 89 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/queryStatuses.tsp
··· 131 131 @required subjectStatuses: tools.ozone.moderation.defs.SubjectStatusView[]; 132 132 }; 133 133 } 134 + 135 + // --- Externals --- 136 + 137 + @external 138 + namespace tools.ozone.moderation.defs { 139 + model SubjectStatusView { } 140 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/searchRepos.tsp
··· 20 20 @required repos: tools.ozone.moderation.defs.RepoView[]; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace tools.ozone.moderation.defs { 28 + model RepoView { } 29 + }
+10
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/addRule.tsp
··· 28 28 createdBy?: did; 29 29 }): tools.ozone.safelink.defs.Event; 30 30 } 31 + 32 + // --- Externals --- 33 + 34 + @external 35 + namespace tools.ozone.safelink.defs { 36 + model PatternType { } 37 + model ActionType { } 38 + model ReasonType { } 39 + model Event { } 40 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/queryEvents.tsp
··· 27 27 @required events: tools.ozone.safelink.defs.Event[]; 28 28 }; 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace tools.ozone.safelink.defs { 35 + model Event { } 36 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/queryRules.tsp
··· 36 36 @required rules: tools.ozone.safelink.defs.UrlRule[]; 37 37 }; 38 38 } 39 + 40 + // --- Externals --- 41 + 42 + @external 43 + namespace tools.ozone.safelink.defs { 44 + model UrlRule { } 45 + }
+8
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/removeRule.tsp
··· 21 21 createdBy?: did; 22 22 }): tools.ozone.safelink.defs.Event; 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace tools.ozone.safelink.defs { 29 + model PatternType { } 30 + model Event { } 31 + }
+10
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/updateRule.tsp
··· 25 25 createdBy?: did; 26 26 }): tools.ozone.safelink.defs.Event; 27 27 } 28 + 29 + // --- Externals --- 30 + 31 + @external 32 + namespace tools.ozone.safelink.defs { 33 + model PatternType { } 34 + model ActionType { } 35 + model ReasonType { } 36 + model Event { } 37 + }
+10
packages/emitter/test/integration/atproto/input/tools/ozone/server/getConfig.tsp
··· 27 27 | string; 28 28 } 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace tools.ozone.team.defs { 35 + @token model RoleAdmin { } 36 + @token model RoleModerator { } 37 + @token model RoleTriage { } 38 + @token model RoleVerifier { } 39 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/set/getValues.tsp
··· 23 23 cursor?: string; 24 24 }; 25 25 } 26 + 27 + // --- Externals --- 28 + 29 + @external 30 + namespace tools.ozone.set.defs { 31 + model SetView { } 32 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/set/querySets.tsp
··· 37 37 cursor?: string; 38 38 }; 39 39 } 40 + 41 + // --- Externals --- 42 + 43 + @external 44 + namespace tools.ozone.set.defs { 45 + model SetView { } 46 + }
+8
packages/emitter/test/integration/atproto/input/tools/ozone/set/upsertSet.tsp
··· 5 5 @procedure 6 6 op main(input: tools.ozone.set.defs.Set): tools.ozone.set.defs.SetView; 7 7 } 8 + 9 + // --- Externals --- 10 + 11 + @external 12 + namespace tools.ozone.set.defs { 13 + model Set { } 14 + model SetView { } 15 + }
+10
packages/emitter/test/integration/atproto/input/tools/ozone/setting/defs.tsp
··· 27 27 @required lastUpdatedBy: did; 28 28 } 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace tools.ozone.team.defs { 35 + @token model RoleModerator { } 36 + @token model RoleTriage { } 37 + @token model RoleAdmin { } 38 + @token model RoleVerifier { } 39 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/setting/listOptions.tsp
··· 24 24 @required options: tools.ozone.setting.defs.Option[]; 25 25 }; 26 26 } 27 + 28 + // --- Externals --- 29 + 30 + @external 31 + namespace tools.ozone.setting.defs { 32 + model Option { } 33 + }
+15
packages/emitter/test/integration/atproto/input/tools/ozone/setting/upsertOption.tsp
··· 23 23 @required option: tools.ozone.setting.defs.Option; 24 24 }; 25 25 } 26 + 27 + // --- Externals --- 28 + 29 + @external 30 + namespace tools.ozone.team.defs { 31 + @token model RoleModerator { } 32 + @token model RoleTriage { } 33 + @token model RoleVerifier { } 34 + @token model RoleAdmin { } 35 + } 36 + 37 + @external 38 + namespace tools.ozone.setting.defs { 39 + model Option { } 40 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/signature/findCorrelation.tsp
··· 7 7 @required details: tools.ozone.signature.defs.SigDetail[]; 8 8 }; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace tools.ozone.signature.defs { 15 + model SigDetail { } 16 + }
+12
packages/emitter/test/integration/atproto/input/tools/ozone/signature/findRelatedAccounts.tsp
··· 23 23 similarities?: tools.ozone.signature.defs.SigDetail[]; 24 24 } 25 25 } 26 + 27 + // --- Externals --- 28 + 29 + @external 30 + namespace com.atproto.admin.defs { 31 + model AccountView { } 32 + } 33 + 34 + @external 35 + namespace tools.ozone.signature.defs { 36 + model SigDetail { } 37 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/signature/searchAccounts.tsp
··· 17 17 @required accounts: com.atproto.admin.defs.AccountView[]; 18 18 }; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace com.atproto.admin.defs { 25 + model AccountView { } 26 + }
+11
packages/emitter/test/integration/atproto/input/tools/ozone/team/addMember.tsp
··· 19 19 | string; 20 20 }): tools.ozone.team.defs.Member; 21 21 } 22 + 23 + // --- Externals --- 24 + 25 + @external 26 + namespace tools.ozone.team.defs { 27 + @token model RoleAdmin { } 28 + @token model RoleModerator { } 29 + @token model RoleVerifier { } 30 + @token model RoleTriage { } 31 + model Member { } 32 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/team/defs.tsp
··· 27 27 @token 28 28 model RoleVerifier {} 29 29 } 30 + 31 + // --- Externals --- 32 + 33 + @external 34 + namespace app.bsky.actor.defs { 35 + model ProfileViewDetailed { } 36 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/team/listMembers.tsp
··· 18 18 @required members: tools.ozone.team.defs.Member[]; 19 19 }; 20 20 } 21 + 22 + // --- Externals --- 23 + 24 + @external 25 + namespace tools.ozone.team.defs { 26 + model Member { } 27 + }
+11
packages/emitter/test/integration/atproto/input/tools/ozone/team/updateMember.tsp
··· 19 19 | string; 20 20 }): tools.ozone.team.defs.Member; 21 21 } 22 + 23 + // --- Externals --- 24 + 25 + @external 26 + namespace tools.ozone.team.defs { 27 + @token model RoleAdmin { } 28 + @token model RoleModerator { } 29 + @token model RoleVerifier { } 30 + @token model RoleTriage { } 31 + model Member { } 32 + }
+8
packages/emitter/test/integration/atproto/input/tools/ozone/verification/defs.tsp
··· 52 52 ); 53 53 } 54 54 } 55 + 56 + // --- Externals --- 57 + 58 + @external 59 + namespace tools.ozone.moderation.defs { 60 + model RepoViewDetail { } 61 + model RepoViewNotFound { } 62 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/verification/grantVerifications.tsp
··· 41 41 subject: did; 42 42 } 43 43 } 44 + 45 + // --- Externals --- 46 + 47 + @external 48 + namespace tools.ozone.verification.defs { 49 + model VerificationView { } 50 + }
+7
packages/emitter/test/integration/atproto/input/tools/ozone/verification/listVerifications.tsp
··· 43 43 @required verifications: tools.ozone.verification.defs.VerificationView[]; 44 44 }; 45 45 } 46 + 47 + // --- Externals --- 48 + 49 + @external 50 + namespace tools.ozone.verification.defs { 51 + model VerificationView { } 52 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/defs.tsp
··· 38 38 @required value: string; 39 39 } 40 40 } 41 + 42 + // --- Externals --- 43 + 44 + @external 45 + namespace com.atproto.server.defs { 46 + model InviteCode { } 47 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getAccountInfo.tsp
··· 7 7 @required did: did 8 8 ): com.atproto.admin.defs.AccountView; 9 9 } 10 + 11 + // --- Externals --- 12 + 13 + @external 14 + namespace com.atproto.admin.defs { 15 + model AccountView { } 16 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getAccountInfos.tsp
··· 9 9 @required infos: com.atproto.admin.defs.AccountView[]; 10 10 }; 11 11 } 12 + 13 + // --- Externals --- 14 + 15 + @external 16 + namespace com.atproto.admin.defs { 17 + model AccountView { } 18 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getInviteCodes.tsp
··· 16 16 @required codes: com.atproto.server.defs.InviteCode[]; 17 17 }; 18 18 } 19 + 20 + // --- Externals --- 21 + 22 + @external 23 + namespace com.atproto.server.defs { 24 + model InviteCode { } 25 + }
+14
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getSubjectStatus.tsp
··· 20 20 deactivated?: com.atproto.admin.defs.StatusAttr; 21 21 }; 22 22 } 23 + 24 + // --- Externals --- 25 + 26 + @external 27 + namespace com.atproto.admin.defs { 28 + model RepoRef { } 29 + model RepoBlobRef { } 30 + model StatusAttr { } 31 + } 32 + 33 + @external 34 + namespace com.atproto.repo.strongRef { 35 + model Main { } 36 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/searchAccounts.tsp
··· 15 15 @required accounts: com.atproto.admin.defs.AccountView[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace com.atproto.admin.defs { 23 + model AccountView { } 24 + }
+14
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/updateSubjectStatus.tsp
··· 26 26 takedown?: com.atproto.admin.defs.StatusAttr; 27 27 }; 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace com.atproto.admin.defs { 34 + model RepoRef { } 35 + model RepoBlobRef { } 36 + model StatusAttr { } 37 + } 38 + 39 + @external 40 + namespace com.atproto.repo.strongRef { 41 + model Main { } 42 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/identity/refreshIdentity.tsp
··· 17 17 @required identifier: atIdentifier; 18 18 }): com.atproto.identity.defs.IdentityInfo; 19 19 } 20 + 21 + // --- Externals --- 22 + 23 + @external 24 + namespace com.atproto.identity.defs { 25 + model IdentityInfo { } 26 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/identity/resolveIdentity.tsp
··· 19 19 identifier: atIdentifier 20 20 ): com.atproto.identity.defs.IdentityInfo; 21 21 } 22 + 23 + // --- Externals --- 24 + 25 + @external 26 + namespace com.atproto.identity.defs { 27 + model IdentityInfo { } 28 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/label/queryLabels.tsp
··· 21 21 @required labels: com.atproto.label.defs.Label[]; 22 22 }; 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace com.atproto.label.defs { 29 + model Label { } 30 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/label/subscribeLabels.tsp
··· 21 21 cursor?: integer 22 22 ): (Labels | Info); 23 23 } 24 + 25 + // --- Externals --- 26 + 27 + @external 28 + namespace com.atproto.label.defs { 29 + model Label { } 30 + }
+17
packages/emitter/test/integration/lexicon-examples/input/com/atproto/moderation/createReport.tsp
··· 50 50 meta?: unknown; 51 51 } 52 52 } 53 + 54 + // --- Externals --- 55 + 56 + @external 57 + namespace com.atproto.moderation.defs { 58 + model ReasonType { } 59 + } 60 + 61 + @external 62 + namespace com.atproto.admin.defs { 63 + model RepoRef { } 64 + } 65 + 66 + @external 67 + namespace com.atproto.repo.strongRef { 68 + model Main { } 69 + }
+51
packages/emitter/test/integration/lexicon-examples/input/com/atproto/moderation/defs.tsp
··· 102 102 string, 103 103 } 104 104 } 105 + 106 + // --- Externals --- 107 + 108 + @external 109 + namespace tools.ozone.report.defs { 110 + @token model ReasonAppeal { } 111 + @token model ReasonViolenceAnimalWelfare { } 112 + @token model ReasonViolenceThreats { } 113 + @token model ReasonViolenceGraphicContent { } 114 + @token model ReasonViolenceSelfHarm { } 115 + @token model ReasonViolenceGlorification { } 116 + @token model ReasonViolenceExtremistContent { } 117 + @token model ReasonViolenceTrafficking { } 118 + @token model ReasonViolenceOther { } 119 + @token model ReasonSexualAbuseContent { } 120 + @token model ReasonSexualNCII { } 121 + @token model ReasonSexualSextortion { } 122 + @token model ReasonSexualDeepfake { } 123 + @token model ReasonSexualAnimal { } 124 + @token model ReasonSexualUnlabeled { } 125 + @token model ReasonSexualOther { } 126 + @token model ReasonChildSafetyCSAM { } 127 + @token model ReasonChildSafetyGroom { } 128 + @token model ReasonChildSafetyMinorPrivacy { } 129 + @token model ReasonChildSafetyEndangerment { } 130 + @token model ReasonChildSafetyHarassment { } 131 + @token model ReasonChildSafetyPromotion { } 132 + @token model ReasonChildSafetyOther { } 133 + @token model ReasonHarassmentTroll { } 134 + @token model ReasonHarassmentTargeted { } 135 + @token model ReasonHarassmentHateSpeech { } 136 + @token model ReasonHarassmentDoxxing { } 137 + @token model ReasonHarassmentOther { } 138 + @token model ReasonMisleadingBot { } 139 + @token model ReasonMisleadingImpersonation { } 140 + @token model ReasonMisleadingSpam { } 141 + @token model ReasonMisleadingScam { } 142 + @token model ReasonMisleadingSyntheticContent { } 143 + @token model ReasonMisleadingMisinformation { } 144 + @token model ReasonMisleadingOther { } 145 + @token model ReasonRuleSiteSecurity { } 146 + @token model ReasonRuleStolenContent { } 147 + @token model ReasonRuleProhibitedSales { } 148 + @token model ReasonRuleBanEvasion { } 149 + @token model ReasonRuleOther { } 150 + @token model ReasonCivicElectoralProcess { } 151 + @token model ReasonCivicDisclosure { } 152 + @token model ReasonCivicInterference { } 153 + @token model ReasonCivicMisinformation { } 154 + @token model ReasonCivicImpersonation { } 155 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/applyWrites.tsp
··· 79 79 80 80 model DeleteResult {} 81 81 } 82 + 83 + // --- Externals --- 84 + 85 + @external 86 + namespace com.atproto.repo.defs { 87 + model CommitMeta { } 88 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/createRecord.tsp
··· 36 36 /** Indicates that 'swapCommit' didn't match current repo commit. */ 37 37 model InvalidSwap {} 38 38 } 39 + 40 + // --- Externals --- 41 + 42 + @external 43 + namespace com.atproto.repo.defs { 44 + model CommitMeta { } 45 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/deleteRecord.tsp
··· 28 28 29 29 model InvalidSwap {} 30 30 } 31 + 32 + // --- Externals --- 33 + 34 + @external 35 + namespace com.atproto.repo.defs { 36 + model CommitMeta { } 37 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/putRecord.tsp
··· 39 39 40 40 model InvalidSwap {} 41 41 } 42 + 43 + // --- Externals --- 44 + 45 + @external 46 + namespace com.atproto.repo.defs { 47 + model CommitMeta { } 48 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/server/getAccountInviteCodes.tsp
··· 15 15 @required codes: com.atproto.server.defs.InviteCode[]; 16 16 }; 17 17 } 18 + 19 + // --- Externals --- 20 + 21 + @external 22 + namespace com.atproto.server.defs { 23 + model InviteCode { } 24 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/sync/getHostStatus.tsp
··· 22 22 23 23 model HostNotFound {} 24 24 } 25 + 26 + // --- Externals --- 27 + 28 + @external 29 + namespace com.atproto.sync.defs { 30 + model HostStatus { } 31 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/sync/listHosts.tsp
··· 29 29 status?: com.atproto.sync.defs.HostStatus; 30 30 } 31 31 } 32 + 33 + // --- Externals --- 34 + 35 + @external 36 + namespace com.atproto.sync.defs { 37 + model HostStatus { } 38 + }
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/temp/fetchLabels.tsp
··· 13 13 @required labels: com.atproto.label.defs.Label[]; 14 14 }; 15 15 } 16 + 17 + // --- Externals --- 18 + 19 + @external 20 + namespace com.atproto.label.defs { 21 + model Label { } 22 + }
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/blockquote.tsp
··· 6 6 facets?: `pub`.leaflet.richtext.facet.Main[]; 7 7 } 8 8 } 9 + 10 + // --- Externals --- 11 + 12 + @external 13 + namespace `pub`.leaflet.richtext.facet { 14 + model Main { } 15 + }
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/bskyPost.tsp
··· 5 5 @required postRef: com.atproto.repo.strongRef.Main; 6 6 } 7 7 } 8 + 9 + // --- Externals --- 10 + 11 + @external 12 + namespace com.atproto.repo.strongRef { 13 + model Main { } 14 + }
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/header.tsp
··· 10 10 facets?: `pub`.leaflet.richtext.facet.Main[]; 11 11 } 12 12 } 13 + 14 + // --- Externals --- 15 + 16 + @external 17 + namespace `pub`.leaflet.richtext.facet { 18 + model Main { } 19 + }
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/text.tsp
··· 6 6 facets?: `pub`.leaflet.richtext.facet.Main[]; 7 7 } 8 8 } 9 + 10 + // --- Externals --- 11 + 12 + @external 13 + namespace `pub`.leaflet.richtext.facet { 14 + model Main { } 15 + }
+17
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/unorderedList.tsp
··· 10 10 children?: ListItem[]; 11 11 } 12 12 } 13 + 14 + // --- Externals --- 15 + 16 + @external 17 + namespace `pub`.leaflet.blocks.text { 18 + model Main { } 19 + } 20 + 21 + @external 22 + namespace `pub`.leaflet.blocks.header { 23 + model Main { } 24 + } 25 + 26 + @external 27 + namespace `pub`.leaflet.blocks.image { 28 + model Main { } 29 + }
+12
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/comment.tsp
··· 26 26 @required parent: atUri; 27 27 } 28 28 } 29 + 30 + // --- Externals --- 31 + 32 + @external 33 + namespace `pub`.leaflet.richtext.facet { 34 + model Main { } 35 + } 36 + 37 + @external 38 + namespace `pub`.leaflet.pages.linearDocument { 39 + model Quote { } 40 + }
+12
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/document.tsp
··· 23 23 @required pages: (`pub`.leaflet.pages.linearDocument.Main | unknown)[]; 24 24 } 25 25 } 26 + 27 + // --- Externals --- 28 + 29 + @external 30 + namespace com.atproto.repo.strongRef { 31 + model Main { } 32 + } 33 + 34 + @external 35 + namespace `pub`.leaflet.pages.linearDocument { 36 + model Main { } 37 + }
+57
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/pages/linearDocument.tsp
··· 43 43 @required offset: integer; 44 44 } 45 45 } 46 + 47 + // --- Externals --- 48 + 49 + @external 50 + namespace `pub`.leaflet.blocks.iframe { 51 + model Main { } 52 + } 53 + 54 + @external 55 + namespace `pub`.leaflet.blocks.text { 56 + model Main { } 57 + } 58 + 59 + @external 60 + namespace `pub`.leaflet.blocks.blockquote { 61 + model Main { } 62 + } 63 + 64 + @external 65 + namespace `pub`.leaflet.blocks.header { 66 + model Main { } 67 + } 68 + 69 + @external 70 + namespace `pub`.leaflet.blocks.image { 71 + model Main { } 72 + } 73 + 74 + @external 75 + namespace `pub`.leaflet.blocks.unorderedList { 76 + model Main { } 77 + } 78 + 79 + @external 80 + namespace `pub`.leaflet.blocks.website { 81 + model Main { } 82 + } 83 + 84 + @external 85 + namespace `pub`.leaflet.blocks.math { 86 + model Main { } 87 + } 88 + 89 + @external 90 + namespace `pub`.leaflet.blocks.code { 91 + model Main { } 92 + } 93 + 94 + @external 95 + namespace `pub`.leaflet.blocks.horizontalRule { 96 + model Main { } 97 + } 98 + 99 + @external 100 + namespace `pub`.leaflet.blocks.bskyPost { 101 + model Main { } 102 + }
+13
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/publication.tsp
··· 34 34 accentText?: (`pub`.leaflet.theme.color.Rgba | `pub`.leaflet.theme.color.Rgb | unknown); 35 35 } 36 36 } 37 + 38 + // --- Externals --- 39 + 40 + @external 41 + namespace `pub`.leaflet.theme.color { 42 + model Rgba { } 43 + model Rgb { } 44 + } 45 + 46 + @external 47 + namespace `pub`.leaflet.theme.backgroundImage { 48 + model Main { } 49 + }
+12
packages/emitter/test/integration/lexicon-examples/input/sh/tangled/repo/issue/state.tsp
··· 10 10 state: "sh.tangled.repo.issue.state.open" | "sh.tangled.repo.issue.state.closed" | string = "sh.tangled.repo.issue.state.open"; 11 11 } 12 12 } 13 + 14 + // --- Externals --- 15 + 16 + @external 17 + namespace sh.tangled.repo.issue.state.open { 18 + @token model Main { } 19 + } 20 + 21 + @external 22 + namespace sh.tangled.repo.issue.state.closed { 23 + @token model Main { } 24 + }
+17
packages/emitter/test/integration/lexicon-examples/input/sh/tangled/repo/pull/status.tsp
··· 10 10 status: "sh.tangled.repo.pull.status.open" | "sh.tangled.repo.pull.status.closed" | "sh.tangled.repo.pull.status.merged" | string = "sh.tangled.repo.pull.status.open"; 11 11 } 12 12 } 13 + 14 + // --- Externals --- 15 + 16 + @external 17 + namespace sh.tangled.repo.pull.status.open { 18 + @token model Main { } 19 + } 20 + 21 + @external 22 + namespace sh.tangled.repo.pull.status.closed { 23 + @token model Main { } 24 + } 25 + 26 + @external 27 + namespace sh.tangled.repo.pull.status.merged { 28 + @token model Main { } 29 + }
+4 -18
packages/emitter/test/integration.test.ts
··· 54 54 path.join(scenario, "output"), 55 55 ); 56 56 57 - // Compile all inputs together (for cross-references) 58 - const tspFiles = Object.keys(inputFiles).filter((f) => 59 - f.endsWith(".tsp"), 60 - ); 61 - let emitResult: EmitResult; 62 - 63 - if (tspFiles.length > 0) { 64 - // Create a virtual main.tsp that imports all other files 65 - const mainContent = 66 - 'import "@typelex/emitter";\n' + 67 - tspFiles.map((f) => `import "./${normalizePathToPosix(f)}";`).join("\n"); 68 - const filesWithMain = { ...inputFiles, "main.tsp": mainContent }; 69 - emitResult = await doEmit(filesWithMain, "main.tsp"); 70 - } else { 71 - emitResult = { files: {}, diagnostics: [], inputFiles: {} }; 72 - } 73 - 74 57 // Generate a test for each expected output 75 58 for (const expectedPath of Object.keys(expectedFiles)) { 76 59 if (!expectedPath.endsWith(".json")) continue; ··· 80 63 const hasInput = Object.keys(inputFiles).includes(inputPath); 81 64 82 65 if (hasInput) { 83 - it(`should emit ${expectedPath}`, function () { 66 + it(`should emit ${expectedPath}`, async function () { 67 + // Compile each file in isolation 68 + const emitResult = await doEmit({ [inputPath]: inputFiles[inputPath] }, inputPath); 69 + 84 70 // Check for compilation errors 85 71 if (emitResult.diagnostics.length > 0) { 86 72 const formattedDiagnostics = emitResult.diagnostics.map((diag) =>
+3 -3
packages/example/package.json
··· 5 5 "type": "module", 6 6 "scripts": { 7 7 "build": "pnpm run build:lexicons && pnpm run build:codegen", 8 - "build:lexicons": "tsp compile typelex/main.tsp", 9 - "build:codegen": "lex gen-server --yes ./src lexicons/app/example/*.json" 8 + "build:lexicons": "typelex compile xyz.statusphere.*", 9 + "build:codegen": "lex gen-server --yes ./src lexicons/xyz/statusphere/*.json" 10 10 }, 11 11 "dependencies": { 12 12 "@atproto/lex-cli": "^0.9.5", 13 13 "@atproto/xrpc-server": "^0.9.5", 14 - "@typespec/compiler": "^1.4.0", 14 + "@typelex/cli": "workspace:*", 15 15 "@typelex/emitter": "workspace:*" 16 16 }, 17 17 "devDependencies": {
+45 -6
packages/example/src/index.ts
··· 10 10 createServer as createXrpcServer, 11 11 } from '@atproto/xrpc-server' 12 12 import { schemas } from './lexicons.js' 13 + import * as XyzStatusphereGetStatuses from './types/xyz/statusphere/getStatuses.js' 14 + import * as XyzStatusphereGetUser from './types/xyz/statusphere/getUser.js' 15 + import * as XyzStatusphereSendStatus from './types/xyz/statusphere/sendStatus.js' 13 16 14 17 export function createServer(options?: XrpcOptions): Server { 15 18 return new Server(options) ··· 17 20 18 21 export class Server { 19 22 xrpc: XrpcServer 20 - app: AppNS 23 + xyz: XyzNS 21 24 22 25 constructor(options?: XrpcOptions) { 23 26 this.xrpc = createXrpcServer(schemas, options) 24 - this.app = new AppNS(this) 27 + this.xyz = new XyzNS(this) 25 28 } 26 29 } 27 30 28 - export class AppNS { 31 + export class XyzNS { 29 32 _server: Server 30 - example: AppExampleNS 33 + statusphere: XyzStatusphereNS 31 34 32 35 constructor(server: Server) { 33 36 this._server = server 34 - this.example = new AppExampleNS(server) 37 + this.statusphere = new XyzStatusphereNS(server) 35 38 } 36 39 } 37 40 38 - export class AppExampleNS { 41 + export class XyzStatusphereNS { 39 42 _server: Server 40 43 41 44 constructor(server: Server) { 42 45 this._server = server 46 + } 47 + 48 + getStatuses<A extends Auth = void>( 49 + cfg: MethodConfigOrHandler< 50 + A, 51 + XyzStatusphereGetStatuses.QueryParams, 52 + XyzStatusphereGetStatuses.HandlerInput, 53 + XyzStatusphereGetStatuses.HandlerOutput 54 + >, 55 + ) { 56 + const nsid = 'xyz.statusphere.getStatuses' // @ts-ignore 57 + return this._server.xrpc.method(nsid, cfg) 58 + } 59 + 60 + getUser<A extends Auth = void>( 61 + cfg: MethodConfigOrHandler< 62 + A, 63 + XyzStatusphereGetUser.QueryParams, 64 + XyzStatusphereGetUser.HandlerInput, 65 + XyzStatusphereGetUser.HandlerOutput 66 + >, 67 + ) { 68 + const nsid = 'xyz.statusphere.getUser' // @ts-ignore 69 + return this._server.xrpc.method(nsid, cfg) 70 + } 71 + 72 + sendStatus<A extends Auth = void>( 73 + cfg: MethodConfigOrHandler< 74 + A, 75 + XyzStatusphereSendStatus.QueryParams, 76 + XyzStatusphereSendStatus.HandlerInput, 77 + XyzStatusphereSendStatus.HandlerOutput 78 + >, 79 + ) { 80 + const nsid = 'xyz.statusphere.sendStatus' // @ts-ignore 81 + return this._server.xrpc.method(nsid, cfg) 43 82 } 44 83 }
+100 -153
packages/example/src/lexicons.ts
··· 10 10 import { type $Typed, is$typed, maybe$typed } from './util.js' 11 11 12 12 export const schemaDict = { 13 - AppExampleDefs: { 13 + XyzStatusphereDefs: { 14 14 lexicon: 1, 15 - id: 'app.example.defs', 15 + id: 'xyz.statusphere.defs', 16 16 defs: { 17 - postRef: { 17 + statusView: { 18 18 type: 'object', 19 19 properties: { 20 20 uri: { 21 21 type: 'string', 22 - description: 'AT URI of the post', 22 + format: 'at-uri', 23 23 }, 24 - cid: { 24 + status: { 25 25 type: 'string', 26 - description: 'CID of the post', 26 + maxLength: 32, 27 + minLength: 1, 28 + maxGraphemes: 1, 27 29 }, 28 - }, 29 - description: 'Reference to a post', 30 - required: ['uri', 'cid'], 31 - }, 32 - replyRef: { 33 - type: 'object', 34 - properties: { 35 - root: { 36 - type: 'ref', 37 - ref: 'lex:app.example.defs#postRef', 38 - description: 'Root post in the thread', 30 + createdAt: { 31 + type: 'string', 32 + format: 'datetime', 39 33 }, 40 - parent: { 34 + profile: { 41 35 type: 'ref', 42 - ref: 'lex:app.example.defs#postRef', 43 - description: 'Direct parent post being replied to', 36 + ref: 'lex:xyz.statusphere.defs#profileView', 44 37 }, 45 38 }, 46 - description: 'Reference to a parent post in a reply chain', 47 - required: ['root', 'parent'], 39 + required: ['uri', 'status', 'createdAt', 'profile'], 48 40 }, 49 - entity: { 41 + profileView: { 50 42 type: 'object', 51 43 properties: { 52 - start: { 53 - type: 'integer', 54 - description: 'Start index in text', 55 - }, 56 - end: { 57 - type: 'integer', 58 - description: 'End index in text', 59 - }, 60 - type: { 44 + did: { 61 45 type: 'string', 62 - description: 'Entity type', 46 + format: 'did', 63 47 }, 64 - value: { 48 + handle: { 65 49 type: 'string', 66 - description: 'Entity value (handle, URL, or tag)', 50 + format: 'handle', 67 51 }, 68 52 }, 69 - description: 'Text entity (mention, link, or tag)', 70 - required: ['start', 'end', 'type', 'value'], 71 - }, 72 - notificationType: { 73 - type: 'string', 74 - knownValues: ['like', 'repost', 'follow', 'mention', 'reply'], 75 - description: 'Type of notification', 53 + required: ['did', 'handle'], 76 54 }, 77 55 }, 78 56 }, 79 - AppExampleFollow: { 57 + XyzStatusphereGetStatuses: { 80 58 lexicon: 1, 81 - id: 'app.example.follow', 59 + id: 'xyz.statusphere.getStatuses', 82 60 defs: { 83 61 main: { 84 - type: 'record', 85 - key: 'tid', 86 - record: { 87 - type: 'object', 62 + type: 'query', 63 + description: 'Get a list of the most recent statuses on the network.', 64 + parameters: { 65 + type: 'params', 88 66 properties: { 89 - subject: { 90 - type: 'string', 91 - description: 'DID of the account being followed', 92 - }, 93 - createdAt: { 94 - type: 'string', 95 - format: 'datetime', 96 - description: 'When the follow was created', 67 + limit: { 68 + type: 'integer', 69 + minimum: 1, 70 + maximum: 100, 71 + default: 50, 97 72 }, 98 73 }, 99 - required: ['subject', 'createdAt'], 100 74 }, 101 - description: 'A follow relationship', 102 - }, 103 - }, 104 - }, 105 - AppExampleLike: { 106 - lexicon: 1, 107 - id: 'app.example.like', 108 - defs: { 109 - main: { 110 - type: 'record', 111 - key: 'tid', 112 - record: { 113 - type: 'object', 114 - properties: { 115 - subject: { 116 - type: 'ref', 117 - ref: 'lex:app.example.defs#postRef', 118 - description: 'Post being liked', 75 + output: { 76 + encoding: 'application/json', 77 + schema: { 78 + type: 'object', 79 + properties: { 80 + statuses: { 81 + type: 'array', 82 + items: { 83 + type: 'ref', 84 + ref: 'lex:xyz.statusphere.defs#statusView', 85 + }, 86 + }, 119 87 }, 120 - createdAt: { 121 - type: 'string', 122 - format: 'datetime', 123 - description: 'When the like was created', 124 - }, 88 + required: ['statuses'], 125 89 }, 126 - required: ['subject', 'createdAt'], 127 90 }, 128 - description: 'A like on a post', 129 91 }, 130 92 }, 131 93 }, 132 - AppExamplePost: { 94 + XyzStatusphereGetUser: { 133 95 lexicon: 1, 134 - id: 'app.example.post', 96 + id: 'xyz.statusphere.getUser', 135 97 defs: { 136 98 main: { 137 - type: 'record', 138 - key: 'tid', 139 - record: { 140 - type: 'object', 141 - properties: { 142 - text: { 143 - type: 'string', 144 - description: 'Post text content', 145 - }, 146 - createdAt: { 147 - type: 'string', 148 - format: 'datetime', 149 - description: 'Creation timestamp', 150 - }, 151 - langs: { 152 - type: 'array', 153 - items: { 154 - type: 'string', 99 + type: 'query', 100 + description: "Get the current user's profile and status.", 101 + output: { 102 + encoding: 'application/json', 103 + schema: { 104 + type: 'object', 105 + properties: { 106 + profile: { 107 + type: 'ref', 108 + ref: 'lex:app.bsky.actor.defs#profileView', 155 109 }, 156 - description: 'Languages the post is written in', 157 - }, 158 - entities: { 159 - type: 'array', 160 - items: { 110 + status: { 161 111 type: 'ref', 162 - ref: 'lex:app.example.defs#entity', 112 + ref: 'lex:xyz.statusphere.defs#statusView', 163 113 }, 164 - description: 'Referenced entities in the post', 165 114 }, 166 - reply: { 167 - type: 'ref', 168 - ref: 'lex:app.example.defs#replyRef', 169 - description: 'Post the user is replying to', 170 - }, 115 + required: ['profile'], 171 116 }, 172 - required: ['text', 'createdAt'], 173 117 }, 174 - description: 'A post in the feed', 175 118 }, 176 119 }, 177 120 }, 178 - AppExampleProfile: { 121 + XyzStatusphereSendStatus: { 179 122 lexicon: 1, 180 - id: 'app.example.profile', 123 + id: 'xyz.statusphere.sendStatus', 181 124 defs: { 182 125 main: { 183 - type: 'record', 184 - key: 'self', 185 - record: { 186 - type: 'object', 187 - properties: { 188 - displayName: { 189 - type: 'string', 190 - description: 'Display name', 191 - }, 192 - description: { 193 - type: 'string', 194 - description: 'Profile description', 126 + type: 'procedure', 127 + description: 'Send a status into the ATmosphere.', 128 + input: { 129 + encoding: 'application/json', 130 + schema: { 131 + type: 'object', 132 + properties: { 133 + status: { 134 + type: 'string', 135 + maxLength: 32, 136 + minLength: 1, 137 + maxGraphemes: 1, 138 + }, 195 139 }, 196 - avatar: { 197 - type: 'string', 198 - description: 'Profile avatar image', 140 + required: ['status'], 141 + }, 142 + }, 143 + output: { 144 + encoding: 'application/json', 145 + schema: { 146 + type: 'object', 147 + properties: { 148 + status: { 149 + type: 'ref', 150 + ref: 'lex:xyz.statusphere.defs#statusView', 151 + }, 199 152 }, 200 - banner: { 201 - type: 'string', 202 - description: 'Profile banner image', 203 - }, 153 + required: ['status'], 204 154 }, 205 155 }, 206 - description: 'User profile information', 207 156 }, 208 157 }, 209 158 }, 210 - AppExampleRepost: { 159 + XyzStatusphereStatus: { 211 160 lexicon: 1, 212 - id: 'app.example.repost', 161 + id: 'xyz.statusphere.status', 213 162 defs: { 214 163 main: { 215 164 type: 'record', ··· 217 166 record: { 218 167 type: 'object', 219 168 properties: { 220 - subject: { 221 - type: 'ref', 222 - ref: 'lex:app.example.defs#postRef', 223 - description: 'Post being reposted', 169 + status: { 170 + type: 'string', 171 + maxLength: 32, 172 + minLength: 1, 173 + maxGraphemes: 1, 224 174 }, 225 175 createdAt: { 226 176 type: 'string', 227 177 format: 'datetime', 228 - description: 'When the repost was created', 229 178 }, 230 179 }, 231 - required: ['subject', 'createdAt'], 180 + required: ['status', 'createdAt'], 232 181 }, 233 - description: 'A repost of another post', 234 182 }, 235 183 }, 236 184 }, ··· 267 215 } 268 216 269 217 export const ids = { 270 - AppExampleDefs: 'app.example.defs', 271 - AppExampleFollow: 'app.example.follow', 272 - AppExampleLike: 'app.example.like', 273 - AppExamplePost: 'app.example.post', 274 - AppExampleProfile: 'app.example.profile', 275 - AppExampleRepost: 'app.example.repost', 218 + XyzStatusphereDefs: 'xyz.statusphere.defs', 219 + XyzStatusphereGetStatuses: 'xyz.statusphere.getStatuses', 220 + XyzStatusphereGetUser: 'xyz.statusphere.getUser', 221 + XyzStatusphereSendStatus: 'xyz.statusphere.sendStatus', 222 + XyzStatusphereStatus: 'xyz.statusphere.status', 276 223 } as const
-79
packages/example/src/types/app/example/defs.ts
··· 1 - /** 2 - * GENERATED CODE - DO NOT MODIFY 3 - */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - 9 - const is$typed = _is$typed, 10 - validate = _validate 11 - const id = 'app.example.defs' 12 - 13 - /** Reference to a post */ 14 - export interface PostRef { 15 - $type?: 'app.example.defs#postRef' 16 - /** AT URI of the post */ 17 - uri: string 18 - /** CID of the post */ 19 - cid: string 20 - } 21 - 22 - const hashPostRef = 'postRef' 23 - 24 - export function isPostRef<V>(v: V) { 25 - return is$typed(v, id, hashPostRef) 26 - } 27 - 28 - export function validatePostRef<V>(v: V) { 29 - return validate<PostRef & V>(v, id, hashPostRef) 30 - } 31 - 32 - /** Reference to a parent post in a reply chain */ 33 - export interface ReplyRef { 34 - $type?: 'app.example.defs#replyRef' 35 - root: PostRef 36 - parent: PostRef 37 - } 38 - 39 - const hashReplyRef = 'replyRef' 40 - 41 - export function isReplyRef<V>(v: V) { 42 - return is$typed(v, id, hashReplyRef) 43 - } 44 - 45 - export function validateReplyRef<V>(v: V) { 46 - return validate<ReplyRef & V>(v, id, hashReplyRef) 47 - } 48 - 49 - /** Text entity (mention, link, or tag) */ 50 - export interface Entity { 51 - $type?: 'app.example.defs#entity' 52 - /** Start index in text */ 53 - start: number 54 - /** End index in text */ 55 - end: number 56 - /** Entity type */ 57 - type: string 58 - /** Entity value (handle, URL, or tag) */ 59 - value: string 60 - } 61 - 62 - const hashEntity = 'entity' 63 - 64 - export function isEntity<V>(v: V) { 65 - return is$typed(v, id, hashEntity) 66 - } 67 - 68 - export function validateEntity<V>(v: V) { 69 - return validate<Entity & V>(v, id, hashEntity) 70 - } 71 - 72 - /** Type of notification */ 73 - export type NotificationType = 74 - | 'like' 75 - | 'repost' 76 - | 'follow' 77 - | 'mention' 78 - | 'reply' 79 - | (string & {})
-30
packages/example/src/types/app/example/follow.ts
··· 1 - /** 2 - * GENERATED CODE - DO NOT MODIFY 3 - */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - 9 - const is$typed = _is$typed, 10 - validate = _validate 11 - const id = 'app.example.follow' 12 - 13 - export interface Record { 14 - $type: 'app.example.follow' 15 - /** DID of the account being followed */ 16 - subject: string 17 - /** When the follow was created */ 18 - createdAt: string 19 - [k: string]: unknown 20 - } 21 - 22 - const hashRecord = 'main' 23 - 24 - export function isRecord<V>(v: V) { 25 - return is$typed(v, id, hashRecord) 26 - } 27 - 28 - export function validateRecord<V>(v: V) { 29 - return validate<Record & V>(v, id, hashRecord, true) 30 - }
-30
packages/example/src/types/app/example/like.ts
··· 1 - /** 2 - * GENERATED CODE - DO NOT MODIFY 3 - */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - import type * as AppExampleDefs from './defs.js' 9 - 10 - const is$typed = _is$typed, 11 - validate = _validate 12 - const id = 'app.example.like' 13 - 14 - export interface Record { 15 - $type: 'app.example.like' 16 - subject: AppExampleDefs.PostRef 17 - /** When the like was created */ 18 - createdAt: string 19 - [k: string]: unknown 20 - } 21 - 22 - const hashRecord = 'main' 23 - 24 - export function isRecord<V>(v: V) { 25 - return is$typed(v, id, hashRecord) 26 - } 27 - 28 - export function validateRecord<V>(v: V) { 29 - return validate<Record & V>(v, id, hashRecord, true) 30 - }
-36
packages/example/src/types/app/example/post.ts
··· 1 - /** 2 - * GENERATED CODE - DO NOT MODIFY 3 - */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - import type * as AppExampleDefs from './defs.js' 9 - 10 - const is$typed = _is$typed, 11 - validate = _validate 12 - const id = 'app.example.post' 13 - 14 - export interface Record { 15 - $type: 'app.example.post' 16 - /** Post text content */ 17 - text: string 18 - /** Creation timestamp */ 19 - createdAt: string 20 - /** Languages the post is written in */ 21 - langs?: string[] 22 - /** Referenced entities in the post */ 23 - entities?: AppExampleDefs.Entity[] 24 - reply?: AppExampleDefs.ReplyRef 25 - [k: string]: unknown 26 - } 27 - 28 - const hashRecord = 'main' 29 - 30 - export function isRecord<V>(v: V) { 31 - return is$typed(v, id, hashRecord) 32 - } 33 - 34 - export function validateRecord<V>(v: V) { 35 - return validate<Record & V>(v, id, hashRecord, true) 36 - }
-34
packages/example/src/types/app/example/profile.ts
··· 1 - /** 2 - * GENERATED CODE - DO NOT MODIFY 3 - */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - 9 - const is$typed = _is$typed, 10 - validate = _validate 11 - const id = 'app.example.profile' 12 - 13 - export interface Record { 14 - $type: 'app.example.profile' 15 - /** Display name */ 16 - displayName?: string 17 - /** Profile description */ 18 - description?: string 19 - /** Profile avatar image */ 20 - avatar?: string 21 - /** Profile banner image */ 22 - banner?: string 23 - [k: string]: unknown 24 - } 25 - 26 - const hashRecord = 'main' 27 - 28 - export function isRecord<V>(v: V) { 29 - return is$typed(v, id, hashRecord) 30 - } 31 - 32 - export function validateRecord<V>(v: V) { 33 - return validate<Record & V>(v, id, hashRecord, true) 34 - }
-30
packages/example/src/types/app/example/repost.ts
··· 1 - /** 2 - * GENERATED CODE - DO NOT MODIFY 3 - */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - import type * as AppExampleDefs from './defs.js' 9 - 10 - const is$typed = _is$typed, 11 - validate = _validate 12 - const id = 'app.example.repost' 13 - 14 - export interface Record { 15 - $type: 'app.example.repost' 16 - subject: AppExampleDefs.PostRef 17 - /** When the repost was created */ 18 - createdAt: string 19 - [k: string]: unknown 20 - } 21 - 22 - const hashRecord = 'main' 23 - 24 - export function isRecord<V>(v: V) { 25 - return is$typed(v, id, hashRecord) 26 - } 27 - 28 - export function validateRecord<V>(v: V) { 29 - return validate<Record & V>(v, id, hashRecord, true) 30 - }
+45
packages/example/src/types/xyz/statusphere/defs.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'xyz.statusphere.defs' 12 + 13 + export interface StatusView { 14 + $type?: 'xyz.statusphere.defs#statusView' 15 + uri: string 16 + status: string 17 + createdAt: string 18 + profile: ProfileView 19 + } 20 + 21 + const hashStatusView = 'statusView' 22 + 23 + export function isStatusView<V>(v: V) { 24 + return is$typed(v, id, hashStatusView) 25 + } 26 + 27 + export function validateStatusView<V>(v: V) { 28 + return validate<StatusView & V>(v, id, hashStatusView) 29 + } 30 + 31 + export interface ProfileView { 32 + $type?: 'xyz.statusphere.defs#profileView' 33 + did: string 34 + handle: string 35 + } 36 + 37 + const hashProfileView = 'profileView' 38 + 39 + export function isProfileView<V>(v: V) { 40 + return is$typed(v, id, hashProfileView) 41 + } 42 + 43 + export function validateProfileView<V>(v: V) { 44 + return validate<ProfileView & V>(v, id, hashProfileView) 45 + }
+36
packages/example/src/types/xyz/statusphere/getStatuses.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 + import type * as XyzStatusphereDefs from './defs.js' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'xyz.statusphere.getStatuses' 13 + 14 + export type QueryParams = { 15 + limit: number 16 + } 17 + export type InputSchema = undefined 18 + 19 + export interface OutputSchema { 20 + statuses: XyzStatusphereDefs.StatusView[] 21 + } 22 + 23 + export type HandlerInput = void 24 + 25 + export interface HandlerSuccess { 26 + encoding: 'application/json' 27 + body: OutputSchema 28 + headers?: { [key: string]: string } 29 + } 30 + 31 + export interface HandlerError { 32 + status: number 33 + message?: string 34 + } 35 + 36 + export type HandlerOutput = HandlerError | HandlerSuccess
+36
packages/example/src/types/xyz/statusphere/getUser.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 + import type * as AppBskyActorDefs from '../../app/bsky/actor/defs.js' 9 + import type * as XyzStatusphereDefs from './defs.js' 10 + 11 + const is$typed = _is$typed, 12 + validate = _validate 13 + const id = 'xyz.statusphere.getUser' 14 + 15 + export type QueryParams = {} 16 + export type InputSchema = undefined 17 + 18 + export interface OutputSchema { 19 + profile: AppBskyActorDefs.ProfileView 20 + status?: XyzStatusphereDefs.StatusView 21 + } 22 + 23 + export type HandlerInput = void 24 + 25 + export interface HandlerSuccess { 26 + encoding: 'application/json' 27 + body: OutputSchema 28 + headers?: { [key: string]: string } 29 + } 30 + 31 + export interface HandlerError { 32 + status: number 33 + message?: string 34 + } 35 + 36 + export type HandlerOutput = HandlerError | HandlerSuccess
+40
packages/example/src/types/xyz/statusphere/sendStatus.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 + import type * as XyzStatusphereDefs from './defs.js' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'xyz.statusphere.sendStatus' 13 + 14 + export type QueryParams = {} 15 + 16 + export interface InputSchema { 17 + status: string 18 + } 19 + 20 + export interface OutputSchema { 21 + status: XyzStatusphereDefs.StatusView 22 + } 23 + 24 + export interface HandlerInput { 25 + encoding: 'application/json' 26 + body: InputSchema 27 + } 28 + 29 + export interface HandlerSuccess { 30 + encoding: 'application/json' 31 + body: OutputSchema 32 + headers?: { [key: string]: string } 33 + } 34 + 35 + export interface HandlerError { 36 + status: number 37 + message?: string 38 + } 39 + 40 + export type HandlerOutput = HandlerError | HandlerSuccess
+28
packages/example/src/types/xyz/statusphere/status.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'xyz.statusphere.status' 12 + 13 + export interface Record { 14 + $type: 'xyz.statusphere.status' 15 + status: string 16 + createdAt: string 17 + [k: string]: unknown 18 + } 19 + 20 + const hashRecord = 'main' 21 + 22 + export function isRecord<V>(v: V) { 23 + return is$typed(v, id, hashRecord) 24 + } 25 + 26 + export function validateRecord<V>(v: V) { 27 + return validate<Record & V>(v, id, hashRecord, true) 28 + }
-5
packages/example/tspconfig.yaml
··· 1 - emit: 2 - - "@typelex/emitter" 3 - options: 4 - "@typelex/emitter": 5 - output-dir: "./lexicons"
+235
packages/example/typelex/externals.tsp
··· 1 + import "@typelex/emitter"; 2 + 3 + // Generated by typelex 4 + // This file is auto-generated. Do not edit manually. 5 + 6 + @external 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 { } 26 + model ProfileView { } 27 + model ProfileViewBasic { } 28 + model ProfileViewDetailed { } 29 + model SavedFeed { } 30 + model SavedFeedsPref { } 31 + model SavedFeedsPrefV2 { } 32 + model ThreadViewPref { } 33 + model ViewerState { } 34 + } 35 + 36 + @external 37 + namespace app.bsky.actor.profile { 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 { } 167 + } 168 + 169 + @external 170 + namespace com.atproto.label.defs { 171 + model Label { } 172 + model LabelValue { } 173 + model LabelValueDefinition { } 174 + model LabelValueDefinitionStrings { } 175 + model SelfLabel { } 176 + model SelfLabels { } 177 + } 178 + 179 + @external 180 + namespace com.atproto.repo.applyWrites { 181 + model Create { } 182 + model CreateResult { } 183 + model Delete { } 184 + model DeleteResult { } 185 + model Update { } 186 + model UpdateResult { } 187 + } 188 + 189 + @external 190 + namespace com.atproto.repo.createRecord { 191 + } 192 + 193 + @external 194 + namespace com.atproto.repo.defs { 195 + model CommitMeta { } 196 + } 197 + 198 + @external 199 + namespace com.atproto.repo.deleteRecord { 200 + } 201 + 202 + @external 203 + namespace com.atproto.repo.describeRepo { 204 + } 205 + 206 + @external 207 + namespace com.atproto.repo.getRecord { 208 + } 209 + 210 + @external 211 + namespace com.atproto.repo.importRepo { 212 + } 213 + 214 + @external 215 + namespace com.atproto.repo.listMissingBlobs { 216 + model RecordBlob { } 217 + } 218 + 219 + @external 220 + namespace com.atproto.repo.listRecords { 221 + model Record { } 222 + } 223 + 224 + @external 225 + namespace com.atproto.repo.putRecord { 226 + } 227 + 228 + @external 229 + namespace com.atproto.repo.strongRef { 230 + model Main { } 231 + } 232 + 233 + @external 234 + namespace com.atproto.repo.uploadBlob { 235 + }
+46 -122
packages/example/typelex/main.tsp
··· 1 1 import "@typelex/emitter"; 2 - 3 - // Example showing typelex as source of truth for atproto lexicons 4 - 5 - // ============ Common Types ============ 6 - 7 - namespace app.example.defs { 8 - @doc("Type of notification") 9 - union notificationType { 10 - string, 11 - 12 - Like: "like", 13 - Repost: "repost", 14 - Follow: "follow", 15 - Mention: "mention", 16 - Reply: "reply", 17 - } 18 - 19 - @doc("Reference to a post") 20 - model PostRef { 21 - @doc("AT URI of the post") 22 - @required 23 - uri: string; 24 - 25 - @doc("CID of the post") 26 - @required 27 - cid: string; 28 - } 29 - 30 - @doc("Reference to a parent post in a reply chain") 31 - model ReplyRef { 32 - @doc("Root post in the thread") 33 - @required 34 - root: PostRef; 35 - 36 - @doc("Direct parent post being replied to") 37 - @required 38 - parent: PostRef; 39 - } 40 - 41 - @doc("Text entity (mention, link, or tag)") 42 - model Entity { 43 - @doc("Start index in text") 44 - @required 45 - start: int32; 2 + import "./externals.tsp"; 46 3 47 - @doc("End index in text") 48 - @required 49 - end: int32; 4 + namespace xyz.statusphere.defs { 5 + model StatusView { 6 + @required uri: atUri; 50 7 51 - @doc("Entity type") 52 8 @required 53 - type: string; 9 + @minLength(1) 10 + @maxGraphemes(1) 11 + @maxLength(32) 12 + status: string; 54 13 55 - @doc("Entity value (handle, URL, or tag)") 56 - @required 57 - value: string; 14 + @required createdAt: datetime; 15 + @required profile: ProfileView; 58 16 } 59 - } 60 17 61 - // ============ Records ============ 62 - 63 - namespace app.example.post { 64 - @rec("tid") 65 - @doc("A post in the feed") 66 - model Main { 67 - @doc("Post text content") 68 - @required 69 - text: string; 70 - 71 - @doc("Creation timestamp") 72 - @required 73 - createdAt: datetime; 74 - 75 - @doc("Languages the post is written in") 76 - langs?: string[]; 77 - 78 - @doc("Referenced entities in the post") 79 - entities?: app.example.defs.Entity[]; 80 - 81 - @doc("Post the user is replying to") 82 - reply?: app.example.defs.ReplyRef; 18 + model ProfileView { 19 + @required did: did; 20 + @required handle: handle; 83 21 } 84 22 } 85 23 86 - namespace app.example.follow { 24 + namespace xyz.statusphere.status { 87 25 @rec("tid") 88 - @doc("A follow relationship") 89 26 model Main { 90 - @doc("DID of the account being followed") 91 27 @required 92 - subject: string; 28 + @minLength(1) 29 + @maxGraphemes(1) 30 + @maxLength(32) 31 + status: string; 93 32 94 - @doc("When the follow was created") 95 - @required 96 - createdAt: datetime; 33 + @required createdAt: datetime; 97 34 } 98 35 } 99 36 100 - namespace app.example.like { 101 - @rec("tid") 102 - @doc("A like on a post") 103 - model Main { 104 - @doc("Post being liked") 105 - @required 106 - subject: app.example.defs.PostRef; 107 - 108 - @doc("When the like was created") 109 - @required 110 - createdAt: datetime; 111 - } 37 + namespace xyz.statusphere.sendStatus { 38 + @procedure 39 + @doc("Send a status into the ATmosphere.") 40 + op main( 41 + input: { 42 + @required 43 + @minLength(1) 44 + @maxGraphemes(1) 45 + @maxLength(32) 46 + status: string; 47 + }, 48 + ): { 49 + @required status: xyz.statusphere.defs.StatusView; 50 + }; 112 51 } 113 52 114 - namespace app.example.repost { 115 - @rec("tid") 116 - @doc("A repost of another post") 117 - model Main { 118 - @doc("Post being reposted") 119 - @required 120 - subject: app.example.defs.PostRef; 121 - 122 - @doc("When the repost was created") 123 - @required 124 - createdAt: datetime; 125 - } 53 + namespace xyz.statusphere.getStatuses { 54 + @query 55 + @doc("Get a list of the most recent statuses on the network.") 56 + op main(@minValue(1) @maxValue(100) limit?: integer = 50): { 57 + @required statuses: xyz.statusphere.defs.StatusView[]; 58 + }; 126 59 } 127 60 128 - namespace app.example.profile { 129 - @rec("self") 130 - @doc("User profile information") 131 - model Main { 132 - @doc("Display name") 133 - displayName?: string; 134 - 135 - @doc("Profile description") 136 - description?: string; 137 - 138 - @doc("Profile avatar image") 139 - avatar?: string; 140 - 141 - @doc("Profile banner image") 142 - banner?: string; 143 - } 61 + namespace xyz.statusphere.getUser { 62 + @query 63 + @doc("Get the current user's profile and status.") 64 + op main(): { 65 + @required profile: app.bsky.actor.defs.ProfileView; 66 + status?: xyz.statusphere.defs.StatusView; 67 + }; 144 68 }
+2 -3
packages/playground/package.json
··· 4 4 "private": true, 5 5 "type": "module", 6 6 "scripts": { 7 - "build:samples": "node samples/build.js", 8 - "dev": "npm run build:samples && vite", 9 - "build": "npm run build:samples && vite build", 7 + "dev": "vite", 8 + "build": "vite build", 10 9 "preview": "vite preview" 11 10 }, 12 11 "dependencies": {
-96
packages/playground/samples/build.js
··· 1 - // @ts-check 2 - import { writeFileSync, mkdirSync, readFileSync } from "fs"; 3 - import { dirname, resolve, join } from "path"; 4 - import { fileURLToPath } from "url"; 5 - import { deepStrictEqual } from "assert"; 6 - import { lexicons, bundleLexicon } from "./index.js"; 7 - import { createTestHost, findTestPackageRoot, resolveVirtualPath } from "@typespec/compiler/testing"; 8 - 9 - const __dirname = dirname(fileURLToPath(import.meta.url)); 10 - const outputDir = resolve(__dirname, "dist"); 11 - const pkgRoot = await findTestPackageRoot(import.meta.url); 12 - 13 - // TypeSpec library setup for testing 14 - const TypelexTestLibrary = { 15 - name: "@typelex/emitter", 16 - packageRoot: pkgRoot.replace("/playground", "/emitter"), 17 - files: [ 18 - { realDir: "", pattern: "package.json", virtualPath: "./node_modules/@typelex/emitter" }, 19 - { realDir: "dist", pattern: "**/*.js", virtualPath: "./node_modules/@typelex/emitter/dist" }, 20 - { realDir: "lib/", pattern: "*.tsp", virtualPath: "./node_modules/@typelex/emitter/lib" }, 21 - ], 22 - }; 23 - 24 - // Create output directory 25 - mkdirSync(outputDir, { recursive: true }); 26 - 27 - // Write each bundled lexicon to disk and verify it compiles correctly 28 - const samplesList = {}; 29 - 30 - for (const [namespace, lexicon] of lexicons) { 31 - const bundled = bundleLexicon(namespace); 32 - const filename = `${namespace}.tsp`; 33 - const filepath = join(outputDir, filename); 34 - 35 - writeFileSync(filepath, bundled); 36 - 37 - const host = await createTestHost({ libraries: [TypelexTestLibrary] }); 38 - host.addTypeSpecFile("main.tsp", bundled); 39 - 40 - const baseOutputPath = resolveVirtualPath("test-output/"); 41 - const [, diagnostics] = await host.compileAndDiagnose("main.tsp", { 42 - outputDir: baseOutputPath, 43 - noEmit: false, 44 - emit: ["@typelex/emitter"], 45 - }); 46 - 47 - if (diagnostics.length > 0) { 48 - console.error(`โŒ ${namespace}: Compilation errors`); 49 - diagnostics.forEach(d => console.error(` ${d.message}`)); 50 - process.exit(1); 51 - } 52 - 53 - // Get emitted JSON 54 - const outputFiles = [...host.fs.entries()] 55 - .filter(([name]) => name.startsWith(baseOutputPath)) 56 - .map(([name, value]) => { 57 - let relativePath = name.replace(baseOutputPath, ""); 58 - if (relativePath.startsWith("@typelex/emitter/")) { 59 - relativePath = relativePath.replace("@typelex/emitter/", ""); 60 - } 61 - return [relativePath, value]; 62 - }); 63 - 64 - const expectedJsonPath = namespace.replace(/\./g, "/") + ".json"; 65 - const emittedJson = outputFiles.find(([path]) => path === expectedJsonPath); 66 - 67 - if (!emittedJson) { 68 - console.error(`โŒ ${namespace}: No JSON output found (expected ${expectedJsonPath})`); 69 - process.exit(1); 70 - } 71 - 72 - // Compare with expected JSON 73 - const expectedJsonFile = join( 74 - pkgRoot.replace("/playground", "/emitter"), 75 - "test/integration", 76 - lexicon.suite, 77 - "output", 78 - lexicon.file.replace(".tsp", ".json") 79 - ); 80 - 81 - const expectedJson = JSON.parse(readFileSync(expectedJsonFile, "utf-8")); 82 - const actualJson = JSON.parse(emittedJson[1]); 83 - 84 - deepStrictEqual(actualJson, expectedJson); 85 - 86 - samplesList[namespace] = { 87 - filename: `samples/dist/${filename}`, 88 - preferredEmitter: "@typelex/emitter", 89 - }; 90 - } 91 - 92 - // Write the samples index 93 - const samplesIndex = `export default ${JSON.stringify(samplesList, null, 2)};`; 94 - writeFileSync(join(outputDir, "samples.js"), samplesIndex); 95 - 96 - console.log(`\nโœ… ${lexicons.size} samples verified successfully`);
+15 -152
packages/playground/samples/index.js
··· 5 5 6 6 const __dirname = dirname(fileURLToPath(import.meta.url)); 7 7 8 - // Get all tsp and json files 8 + // Get all tsp files 9 9 function getAllFiles(dir, baseDir = dir) { 10 10 const files = []; 11 11 const entries = readdirSync(dir); ··· 16 16 17 17 if (stat.isDirectory()) { 18 18 files.push(...getAllFiles(fullPath, baseDir)); 19 - } else if (entry.endsWith(".tsp") || entry.endsWith(".json")) { 19 + } else if (entry.endsWith(".tsp")) { 20 20 files.push(relative(baseDir, fullPath)); 21 21 } 22 22 } ··· 24 24 return files.sort(); 25 25 } 26 26 27 - // Extract all refs from JSON (recursively search for strings with #) 28 - function extractRefsFromJson(obj, refs = new Map()) { 29 - if (typeof obj === "string") { 30 - // Match pattern like "foo.bar#baz" or "foo.barCamel#baz" (must have # to be a ref) 31 - const match = obj.match(/^([a-z][a-zA-Z.]+)#([a-z][a-zA-Z]*)$/); 32 - if (match) { 33 - const ns = match[1]; 34 - const def = match[2]; 35 - const modelName = def.charAt(0).toUpperCase() + def.slice(1); 36 - if (!refs.has(ns)) { 37 - refs.set(ns, new Set()); 38 - } 39 - refs.get(ns).add(modelName); 40 - } else { 41 - // Also match plain namespace refs like "foo.bar.baz" or "foo.bar.bazCamel" (must have at least 2 dots) 42 - const nsMatch = obj.match(/^([a-z][a-zA-Z]*(?:\.[a-z][a-zA-Z]*){2,})$/); 43 - if (nsMatch) { 44 - const ns = nsMatch[1]; 45 - if (!refs.has(ns)) { 46 - refs.set(ns, new Set()); 47 - } 48 - refs.get(ns).add("Main"); 49 - } 50 - } 51 - } else if (Array.isArray(obj)) { 52 - for (const item of obj) { 53 - extractRefsFromJson(item, refs); 54 - } 55 - } else if (obj && typeof obj === "object") { 56 - for (const value of Object.values(obj)) { 57 - extractRefsFromJson(value, refs); 58 - } 59 - } 60 - return refs; 61 - } 62 - 63 27 const integrationDir = join(__dirname, "../../emitter/test/integration"); 64 28 65 29 // Get all test suite directories ··· 68 32 return statSync(fullPath).isDirectory() && !name.startsWith("."); 69 33 }); 70 34 71 - // Build lexicons with refs extracted from JSON 72 - const lexicons = new Map(); // namespace -> { file, content, refs, suite } 35 + // Load all lexicons from test suites 36 + const lexicons = new Map(); // namespace -> { file, content, suite } 73 37 74 - // Process all test suites 75 38 for (const suite of testSuites) { 76 39 const inputDir = join(integrationDir, suite, "input"); 77 - const outputDir = join(integrationDir, suite, "output"); 78 - 79 40 const inputFiles = getAllFiles(inputDir).filter((f) => f.endsWith(".tsp")); 80 41 81 42 for (const file of inputFiles) { ··· 83 44 const content = readFileSync(fullPath, "utf-8"); 84 45 const namespace = file.replace(/\.tsp$/, "").replace(/\//g, "."); 85 46 86 - // Find corresponding JSON output 87 - const jsonFile = file.replace(/\.tsp$/, ".json"); 88 - const jsonPath = join(outputDir, jsonFile); 89 - const jsonContent = readFileSync(jsonPath, "utf-8"); 90 - const jsonData = JSON.parse(jsonContent); 91 - const refs = extractRefsFromJson(jsonData); 92 - 93 - lexicons.set(namespace, { file, content, refs, suite }); 47 + lexicons.set(namespace, { file, content, suite, fullPath }); 94 48 } 95 49 } 96 50 97 - // TypeSpec reserved keywords that need escaping 98 - const TYPESPEC_KEYWORDS = new Set([ 99 - "record", 100 - "pub", 101 - "interface", 102 - "model", 103 - "namespace", 104 - "op", 105 - "import", 106 - "export", 107 - "using", 108 - "alias", 109 - "enum", 110 - "union", 111 - "scalar", 112 - "extends", 113 - ]); 114 - 115 - // Escape a namespace part if it's a reserved keyword 116 - function escapeNamespacePart(part) { 117 - return TYPESPEC_KEYWORDS.has(part) ? `\`${part}\`` : part; 51 + // Build samples list for playground 52 + const samplesList = {}; 53 + for (const [namespace, lexicon] of lexicons) { 54 + samplesList[namespace] = { 55 + filename: relative(join(__dirname, ".."), lexicon.fullPath), 56 + preferredEmitter: "@typelex/emitter", 57 + }; 118 58 } 119 59 120 - // Escape a full namespace path 121 - function escapeNamespace(namespace) { 122 - return namespace.split(".").map(escapeNamespacePart).join("."); 123 - } 124 - 125 - // Get the JSON for a lexicon to check its definitions 126 - function getLexiconJson(namespace) { 127 - const lexicon = lexicons.get(namespace); 128 - if (!lexicon) return null; 129 - 130 - const jsonPath = join( 131 - integrationDir, 132 - lexicon.suite, 133 - "output", 134 - lexicon.file.replace(".tsp", ".json"), 135 - ); 136 - 137 - try { 138 - return JSON.parse(readFileSync(jsonPath, "utf-8")); 139 - } catch { 140 - return null; 141 - } 142 - } 60 + export { lexicons }; 61 + export default samplesList; 143 62 144 - // Check if a definition in JSON is a token 145 - function isToken(lexiconJson, defName) { 146 - if (!lexiconJson || !lexiconJson.defs) return false; 147 - const def = lexiconJson.defs[defName]; 148 - return def && def.type === "token"; 149 - } 150 - 151 - // Bundle a lexicon with stubs for referenced types (from JSON) 152 - function bundleLexicon(namespace) { 153 - const mainLexicon = lexicons.get(namespace); 154 - if (!mainLexicon) return ""; 155 - 156 - let bundled = mainLexicon.content; 157 - 158 - // Add stubs from refs extracted from JSON output (excluding self-references) 159 - if (mainLexicon.refs.size > 0) { 160 - let hasExternalRefs = false; 161 - for (const [ns] of mainLexicon.refs) { 162 - if (ns !== namespace) { 163 - hasExternalRefs = true; 164 - break; 165 - } 166 - } 167 - 168 - if (hasExternalRefs) { 169 - bundled += "\n// --- Externals ---\n"; 170 - } 171 - 172 - for (const [ns, models] of mainLexicon.refs) { 173 - // Skip if this is the current namespace 174 - if (ns === namespace) continue; 175 - 176 - // Get the JSON for this referenced namespace to check for tokens 177 - const refJson = getLexiconJson(ns); 178 - 179 - const escapedNs = escapeNamespace(ns); 180 - bundled += `\n@external\nnamespace ${escapedNs} {\n`; 181 - for (const model of models) { 182 - // Check if this definition exists in the JSON and is a token 183 - const defName = model.charAt(0).toLowerCase() + model.slice(1); 184 - if (refJson && isToken(refJson, defName)) { 185 - bundled += ` @token model ${model} { }\n`; 186 - } else { 187 - bundled += ` model ${model} { }\n`; 188 - } 189 - } 190 - bundled += `}\n`; 191 - } 192 - } 193 - 194 - return bundled; 195 - } 196 - 197 - // Export for build script 198 - export { lexicons, bundleLexicon }; 199 - 200 - console.log(`Loaded ${lexicons.size} lexicons for bundling`); 63 + console.log(`Loaded ${lexicons.size} lexicons`);
+1 -1
packages/playground/vite.config.ts
··· 1 1 import { definePlaygroundViteConfig } from "@typespec/playground/vite"; 2 2 import { defineConfig } from "vite"; 3 - import samples from "./samples/dist/samples.js"; 3 + import samples from "./samples/index.js"; 4 4 5 5 const playgroundConfig = definePlaygroundViteConfig({ 6 6 defaultEmitter: "@typelex/emitter",
+46 -3
pnpm-lock.yaml
··· 12 12 specifier: ^5.0.0 13 13 version: 5.9.3 14 14 15 + packages/cli: 16 + dependencies: 17 + '@typelex/emitter': 18 + specifier: ^0.2.0 19 + version: 0.2.0(@typespec/compiler@1.4.0(@types/node@20.19.19)) 20 + '@typespec/compiler': 21 + specifier: ^1.4.0 22 + version: 1.4.0(@types/node@20.19.19) 23 + yargs: 24 + specifier: ^18.0.0 25 + version: 18.0.0 26 + devDependencies: 27 + '@types/node': 28 + specifier: ^20.0.0 29 + version: 20.19.19 30 + '@types/yargs': 31 + specifier: ^17.0.33 32 + version: 17.0.33 33 + typescript: 34 + specifier: ^5.0.0 35 + version: 5.9.3 36 + 15 37 packages/emitter: 16 38 dependencies: 17 39 '@typespec/compiler': ··· 48 70 '@atproto/xrpc-server': 49 71 specifier: ^0.9.5 50 72 version: 0.9.5 73 + '@typelex/cli': 74 + specifier: workspace:* 75 + version: link:../cli 51 76 '@typelex/emitter': 52 77 specifier: workspace:* 53 78 version: link:../emitter 54 - '@typespec/compiler': 55 - specifier: ^1.4.0 56 - version: 1.4.0(@types/node@20.19.19) 57 79 devDependencies: 58 80 typescript: 59 81 specifier: ^5.0.0 ··· 1645 1667 '@ts-morph/common@0.25.0': 1646 1668 resolution: {integrity: sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==} 1647 1669 1670 + '@typelex/emitter@0.2.0': 1671 + resolution: {integrity: sha512-4Iw6VAnd9nCFGOkJcu9utWdmu9ZyPeAb1QX/B7KerGBmfc2FuIDqgZZ/mZ6c56atcZd62pb2oYF/3RgSFhEsoQ==} 1672 + peerDependencies: 1673 + '@typespec/compiler': ^1.4.0 1674 + 1648 1675 '@types/babel__core@7.20.5': 1649 1676 resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 1650 1677 ··· 1705 1732 1706 1733 '@types/unist@3.0.3': 1707 1734 resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} 1735 + 1736 + '@types/yargs-parser@21.0.3': 1737 + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} 1738 + 1739 + '@types/yargs@17.0.33': 1740 + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} 1708 1741 1709 1742 '@typespec/asset-emitter@0.74.0': 1710 1743 resolution: {integrity: sha512-DWIdlSNhRgBeZ8exfqubfUn0H6mRg4gr0s7zLTdBMUEDHL3Yh0ljnRPkd8AXTZhoW3maTFT69loWTrqx09T5oQ==} ··· 7411 7444 path-browserify: 1.0.1 7412 7445 tinyglobby: 0.2.15 7413 7446 7447 + '@typelex/emitter@0.2.0(@typespec/compiler@1.4.0(@types/node@20.19.19))': 7448 + dependencies: 7449 + '@typespec/compiler': 1.4.0(@types/node@20.19.19) 7450 + 7414 7451 '@types/babel__core@7.20.5': 7415 7452 dependencies: 7416 7453 '@babel/parser': 7.28.4 ··· 7482 7519 csstype: 3.1.3 7483 7520 7484 7521 '@types/unist@3.0.3': {} 7522 + 7523 + '@types/yargs-parser@21.0.3': {} 7524 + 7525 + '@types/yargs@17.0.33': 7526 + dependencies: 7527 + '@types/yargs-parser': 21.0.3 7485 7528 7486 7529 '@typespec/asset-emitter@0.74.0(@typespec/compiler@1.4.0(@types/node@20.19.19))': 7487 7530 dependencies: