+4
CHANGELOG.md
+4
CHANGELOG.md
+2
-1
package.json
+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",
+66
packages/cli/README.md
+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
+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
+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
+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
packages/cli/src/index.ts
···
1
+
export { compileCommand } from "./commands/compile.js";
+38
packages/cli/src/utils/ensure-imports.ts
+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
+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
+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
+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
+4
packages/cli/typelex/externals.tsp
+1
-1
packages/emitter/package.json
+1
-1
packages/emitter/package.json
+46
packages/emitter/test/integration/atproto/input/app/bsky/actor/defs.tsp
+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
packages/emitter/test/integration/atproto/input/app/bsky/actor/getPreferences.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getProfile.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getProfile.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getProfiles.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getProfiles.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getSuggestions.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/getSuggestions.tsp
+12
packages/emitter/test/integration/atproto/input/app/bsky/actor/profile.tsp
+12
packages/emitter/test/integration/atproto/input/app/bsky/actor/profile.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/putPreferences.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/putPreferences.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/searchActors.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/searchActors.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/searchActorsTypeahead.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/searchActorsTypeahead.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/status.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/actor/status.tsp
+14
packages/emitter/test/integration/atproto/input/app/bsky/bookmark/defs.tsp
+14
packages/emitter/test/integration/atproto/input/app/bsky/bookmark/defs.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/bookmark/getBookmarks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/bookmark/getBookmarks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/embed/images.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/embed/images.tsp
+54
packages/emitter/test/integration/atproto/input/app/bsky/embed/record.tsp
+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
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
+7
packages/emitter/test/integration/atproto/input/app/bsky/embed/video.tsp
+49
packages/emitter/test/integration/atproto/input/app/bsky/feed/defs.tsp
+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
+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
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getActorFeeds.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getActorLikes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getActorLikes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getAuthorFeed.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getAuthorFeed.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeed.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeed.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedGenerator.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedGenerator.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedGenerators.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedGenerators.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getFeedSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getLikes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getLikes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getListFeed.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getListFeed.tsp
+10
packages/emitter/test/integration/atproto/input/app/bsky/feed/getPostThread.tsp
+10
packages/emitter/test/integration/atproto/input/app/bsky/feed/getPostThread.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getPosts.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getPosts.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getQuotes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getQuotes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getRepostedBy.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getRepostedBy.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getSuggestedFeeds.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getSuggestedFeeds.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getTimeline.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/getTimeline.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/like.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/like.tsp
+42
packages/emitter/test/integration/atproto/input/app/bsky/feed/post.tsp
+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
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/repost.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/searchPosts.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/searchPosts.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/sendInteractions.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/feed/sendInteractions.tsp
+23
packages/emitter/test/integration/atproto/input/app/bsky/graph/defs.tsp
+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
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getActorStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getBlocks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getBlocks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getFollowers.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getFollowers.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getFollows.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getFollows.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getKnownFollowers.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getKnownFollowers.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getList.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getList.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListBlocks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListBlocks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListMutes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListMutes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getLists.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getLists.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListsWithMembership.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getListsWithMembership.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getMutes.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getMutes.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getRelationships.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getRelationships.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPack.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPack.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPacks.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPacksWithMembership.tsp
+8
packages/emitter/test/integration/atproto/input/app/bsky/graph/getStarterPacksWithMembership.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getSuggestedFollowsByActor.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/getSuggestedFollowsByActor.tsp
+17
packages/emitter/test/integration/atproto/input/app/bsky/graph/list.tsp
+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
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/searchStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/starterpack.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/graph/starterpack.tsp
+20
packages/emitter/test/integration/atproto/input/app/bsky/labeler/defs.tsp
+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
+8
packages/emitter/test/integration/atproto/input/app/bsky/labeler/getServices.tsp
+18
packages/emitter/test/integration/atproto/input/app/bsky/labeler/service.tsp
+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
packages/emitter/test/integration/atproto/input/app/bsky/notification/getPreferences.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/listActivitySubscriptions.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/listActivitySubscriptions.tsp
+12
packages/emitter/test/integration/atproto/input/app/bsky/notification/listNotifications.tsp
+12
packages/emitter/test/integration/atproto/input/app/bsky/notification/listNotifications.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/putActivitySubscription.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/notification/putActivitySubscription.tsp
+10
packages/emitter/test/integration/atproto/input/app/bsky/notification/putPreferencesV2.tsp
+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
+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
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getAgeAssuranceState.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPopularFeedGenerators.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPopularFeedGenerators.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPostThreadOtherV2.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPostThreadOtherV2.tsp
+15
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getPostThreadV2.tsp
+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
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedFeeds.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedStarterPacks.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedUsers.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestedUsers.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestionsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getSuggestionsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrendingTopics.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrendingTopics.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrends.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrends.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrendsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/getTrendsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/initAgeAssurance.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/initAgeAssurance.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchActorsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchActorsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchPostsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchPostsSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchStarterPacksSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/unspecced/searchStarterPacksSkeleton.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/video/getJobStatus.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/video/getJobStatus.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/video/uploadVideo.tsp
+7
packages/emitter/test/integration/atproto/input/app/bsky/video/uploadVideo.tsp
+14
packages/emitter/test/integration/atproto/input/chat/bsky/actor/defs.tsp
+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
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/addReaction.tsp
+18
packages/emitter/test/integration/atproto/input/chat/bsky/convo/defs.tsp
+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
packages/emitter/test/integration/atproto/input/chat/bsky/convo/deleteMessageForSelf.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvo.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvo.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvoAvailability.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvoAvailability.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvoForMembers.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getConvoForMembers.tsp
+16
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getLog.tsp
+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
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/getMessages.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/listConvos.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/listConvos.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/muteConvo.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/muteConvo.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/removeReaction.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/removeReaction.tsp
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/sendMessage.tsp
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/sendMessage.tsp
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/sendMessageBatch.tsp
+8
packages/emitter/test/integration/atproto/input/chat/bsky/convo/sendMessageBatch.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/unmuteConvo.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/unmuteConvo.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/updateRead.tsp
+7
packages/emitter/test/integration/atproto/input/chat/bsky/convo/updateRead.tsp
+8
packages/emitter/test/integration/atproto/input/chat/bsky/moderation/getMessageContext.tsp
+8
packages/emitter/test/integration/atproto/input/chat/bsky/moderation/getMessageContext.tsp
+8
packages/emitter/test/integration/atproto/input/com/atproto/admin/defs.tsp
+8
packages/emitter/test/integration/atproto/input/com/atproto/admin/defs.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getAccountInfo.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getAccountInfo.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getAccountInfos.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getAccountInfos.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getInviteCodes.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/getInviteCodes.tsp
+14
packages/emitter/test/integration/atproto/input/com/atproto/admin/getSubjectStatus.tsp
+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
+7
packages/emitter/test/integration/atproto/input/com/atproto/admin/searchAccounts.tsp
+14
packages/emitter/test/integration/atproto/input/com/atproto/admin/updateSubjectStatus.tsp
+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
+7
packages/emitter/test/integration/atproto/input/com/atproto/identity/refreshIdentity.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/identity/resolveIdentity.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/identity/resolveIdentity.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/label/queryLabels.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/label/queryLabels.tsp
+8
packages/emitter/test/integration/atproto/input/com/atproto/label/subscribeLabels.tsp
+8
packages/emitter/test/integration/atproto/input/com/atproto/label/subscribeLabels.tsp
+17
packages/emitter/test/integration/atproto/input/com/atproto/moderation/createReport.tsp
+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
+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
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/applyWrites.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/createRecord.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/createRecord.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/deleteRecord.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/deleteRecord.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/putRecord.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/repo/putRecord.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/server/getAccountInviteCodes.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/server/getAccountInviteCodes.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/sync/getHostStatus.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/sync/getHostStatus.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/sync/listHosts.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/sync/listHosts.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/temp/fetchLabels.tsp
+7
packages/emitter/test/integration/atproto/input/com/atproto/temp/fetchLabels.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/createTemplate.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/createTemplate.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/listTemplates.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/listTemplates.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/updateTemplate.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/communication/updateTemplate.tsp
+34
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/defs.tsp
+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
+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
+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
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getEvent.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRecord.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRecord.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRecords.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRecords.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRepo.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRepo.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getReporterStats.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getReporterStats.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRepos.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getRepos.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getSubjects.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/getSubjects.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/queryEvents.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/queryEvents.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/queryStatuses.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/queryStatuses.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/searchRepos.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/moderation/searchRepos.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/addRule.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/addRule.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/queryEvents.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/queryEvents.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/queryRules.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/queryRules.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/removeRule.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/removeRule.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/updateRule.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/safelink/updateRule.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/server/getConfig.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/server/getConfig.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/set/getValues.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/set/getValues.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/set/querySets.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/set/querySets.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/set/upsertSet.tsp
+8
packages/emitter/test/integration/atproto/input/tools/ozone/set/upsertSet.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/setting/defs.tsp
+10
packages/emitter/test/integration/atproto/input/tools/ozone/setting/defs.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/setting/listOptions.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/setting/listOptions.tsp
+15
packages/emitter/test/integration/atproto/input/tools/ozone/setting/upsertOption.tsp
+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
packages/emitter/test/integration/atproto/input/tools/ozone/signature/findCorrelation.tsp
+12
packages/emitter/test/integration/atproto/input/tools/ozone/signature/findRelatedAccounts.tsp
+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
+7
packages/emitter/test/integration/atproto/input/tools/ozone/signature/searchAccounts.tsp
+11
packages/emitter/test/integration/atproto/input/tools/ozone/team/addMember.tsp
+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
+7
packages/emitter/test/integration/atproto/input/tools/ozone/team/defs.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/team/listMembers.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/team/listMembers.tsp
+11
packages/emitter/test/integration/atproto/input/tools/ozone/team/updateMember.tsp
+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
+8
packages/emitter/test/integration/atproto/input/tools/ozone/verification/defs.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/verification/grantVerifications.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/verification/grantVerifications.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/verification/listVerifications.tsp
+7
packages/emitter/test/integration/atproto/input/tools/ozone/verification/listVerifications.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/defs.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/defs.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getAccountInfo.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getAccountInfo.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getAccountInfos.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getAccountInfos.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getInviteCodes.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getInviteCodes.tsp
+14
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/getSubjectStatus.tsp
+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
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/searchAccounts.tsp
+14
packages/emitter/test/integration/lexicon-examples/input/com/atproto/admin/updateSubjectStatus.tsp
+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
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/identity/refreshIdentity.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/identity/resolveIdentity.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/identity/resolveIdentity.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/label/queryLabels.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/label/queryLabels.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/label/subscribeLabels.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/label/subscribeLabels.tsp
+17
packages/emitter/test/integration/lexicon-examples/input/com/atproto/moderation/createReport.tsp
+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
+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
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/applyWrites.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/createRecord.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/createRecord.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/deleteRecord.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/deleteRecord.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/putRecord.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/repo/putRecord.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/server/getAccountInviteCodes.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/server/getAccountInviteCodes.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/sync/getHostStatus.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/sync/getHostStatus.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/sync/listHosts.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/sync/listHosts.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/temp/fetchLabels.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/com/atproto/temp/fetchLabels.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/blockquote.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/blockquote.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/bskyPost.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/bskyPost.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/header.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/header.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/text.tsp
+7
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/text.tsp
+17
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/blocks/unorderedList.tsp
+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
+12
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/comment.tsp
+12
packages/emitter/test/integration/lexicon-examples/input/pub/leaflet/document.tsp
+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
+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
+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
+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
+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
+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
+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
+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
+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
-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
-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
-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
-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
-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
-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
+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
+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
+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
+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
+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
-5
packages/example/tspconfig.yaml
+235
packages/example/typelex/externals.tsp
+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
+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
+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
-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
+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
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
+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: