Skip to content

Commit c19f737

Browse files
authored
Merge API into Docs (#5)
* update readme * adds cursor rules * Merge API into Docs * cleanup internal helpers * Rename registry app * migrate registry to vercel * revise registry deployment * oops * revert registry to cloudflare workers
1 parent 345a848 commit c19f737

77 files changed

Lines changed: 6825 additions & 956 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
description:
3+
globs: *.ts,*.tsx
4+
alwaysApply: false
5+
---
6+
When building generic functions, you may need to use any inside the function body.
7+
8+
This is because TypeScript often cannot match your runtime logic to the logic done inside your types.
9+
10+
One example:
11+
12+
```ts
13+
const youSayGoodbyeISayHello = <TInput extends "hello" | "goodbye">(
14+
input: TInput,
15+
): TInput extends "hello" ? "goodbye" : "hello" => {
16+
if (input === "goodbye") {
17+
return "hello"; // Error!
18+
} else {
19+
return "goodbye"; // Error!
20+
}
21+
};
22+
```
23+
24+
On the type level (and the runtime), this function returns `goodbye` when the input is `hello`.
25+
26+
There is no way to make this work concisely in TypeScript.
27+
28+
So using `any` is the most concise solution:
29+
30+
```ts
31+
const youSayGoodbyeISayHello = <TInput extends "hello" | "goodbye">(
32+
input: TInput,
33+
): TInput extends "hello" ? "goodbye" : "hello" => {
34+
if (input === "goodbye") {
35+
return "hello" as any;
36+
} else {
37+
return "goodbye" as any;
38+
}
39+
};
40+
```
41+
42+
Outside of generic functions, use `any` extremely sparingly.

.cursor/rules/create-model.mdc

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
description:
3+
globs: packages/forge-models/src/**/*.ts,apps/docs/src/content/docs/models/**/*
4+
alwaysApply: false
5+
---
6+
# Rule: Create Model
7+
8+
This rule outlines the process for defining new data models and ensuring their corresponding documentation is comprehensive and up-to-date. Adherence to this rule maintains clarity and consistency across the DH Forge System.
9+
10+
## Core Principle
11+
12+
Model definitions and their documentation are inextricably linked. **Whenever a model is created or modified, its documentation must be created or updated accordingly.**
13+
14+
## Model Definition
15+
16+
1. **Location:** All core data models are defined as Zod schemas within the `/packages/forge-models/src/` directory.
17+
2. - Models are stored within versioned folders (e.g., `/src/version-0.2`. `/src/version-1.0`)
18+
- Organize models logically, potentially by category (e.g., `character/`, `item/`, `ability/`).
19+
- Follow existing patterns or create new categorized subdirectories if appropriate.
20+
3. **Technology:** Use @Zod schema definition and validation.
21+
4. **Naming Conventions:**
22+
- **Zod Schema Variable:** `camelCase` (e.g., `characterSchema`).
23+
- **Exported Type:** `PascalCase` (e.g., `Character`), typically inferred from the Zod schema using `z.infer<typeof yourSchemaName>`.
24+
- **File Names (for Zod schemas):** `kebab-case.ts` (e.g., `character.ts` or `item-schemas.ts`).
25+
26+
## Documentation
27+
28+
Each distinct model type _must_ have its own documentation page.
29+
30+
1. **Location:** `apps/docs/src/content/docs/models/`
31+
2. **File Creation:**
32+
- Create a new `.mdx` file for the model (e.g., `character.mdx` or `primary-class.mdx`).
33+
- Use `kebab-case` for documentation filenames.
34+
3. **Content Requirements:**
35+
The `.mdx` file for each model must include:
36+
37+
- **Frontmatter:**
38+
- `title`: A clear, descriptive title for the model (e.g., `Character Model`).
39+
- `description`: A brief overview of what this model represents.
40+
- **Main Content:**
41+
- **Description Section:**
42+
- A concise explanation of what the model represents and its purpose within the DH Forge System.
43+
- Clarify any potential ambiguities.
44+
- **Schema and Expected Values Section:**
45+
- Detail all fields, their expected data types (e.g., string, number, boolean, array, nested object).
46+
- Specify if fields are required or optional.
47+
- Describe any constraints, enumerations (e.g., "must be one of 'VALUE_A', 'VALUE_B'"), or formatting rules.
48+
- This section should accurately reflect the Zod schema. Including a relevant snippet of the Zod schema definition or a simplified representation is highly encouraged.
49+
- **Examples Section:**
50+
- Provide at least one, preferably multiple, clear JSON or TypeScript object examples illustrating valid instances of the model.
51+
- Include examples that cover common use cases and demonstrate the use of optional fields.
52+
53+
**Example `.mdx` Structure:**
54+
55+
````mdx
56+
---
57+
title: Example Model Name
58+
description: A brief overview of what this Example Model represents and its role in the system.
59+
---
60+
61+
## Description
62+
63+
The `ExampleModel` is used to structure data related to [...]. Its primary purpose is to ensure consistency and provide a clear definition for [...].
64+
65+
## Schema and Expected Values
66+
67+
The `ExampleModel` has the following structure:
68+
69+
| key | type | required | note |
70+
|--------------------|---------------------|----------|--------------------------------------------------------------------------------------|
71+
| id | string | yes | Unique identifier for the instance. Must follow UUID v4 format. |
72+
| name | string | yes | Human-readable name for the instance. |
73+
| status | string | yes | Current status. Must be one of `ACTIVE`, `INACTIVE`, `PENDING`. |
74+
| configuration | object | no | Optional object containing further configuration details. |
75+
| configuration.retries | number | no | Number of retries, defaults to 3. |
76+
| configuration.isEnabled | boolean | yes | Flag to enable or disable. |
77+
| tags | array of strings | no | List of associated tags. |
78+
79+
## Examples
80+
81+
### Basic Example
82+
83+
```json
84+
{
85+
"id": "123e4567-e89b-12d3-a456-426614174000",
86+
"name": "My First Example Instance",
87+
"status": "ACTIVE"
88+
}
89+
```
90+
````
91+
92+
### Example with Optional Fields
93+
94+
```json
95+
{
96+
"id": "987e6543-e21b-32d1-b432-872251234011",
97+
"name": "Another Example Instance",
98+
"status": "PENDING",
99+
"configuration": {
100+
"retries": 5,
101+
"isEnabled": true
102+
},
103+
"tags": ["important", "needs-review"]
104+
}
105+
```
106+
107+
```
108+
109+
```
110+
111+
4. **Referencing Other Models:**
112+
- If the model references other models (e.g., using an ID that corresponds to another model, or the `category/type:id` convention if applicable), clearly explain these relationships.
113+
- Where appropriate, link to the documentation pages for any referenced models.
114+
115+
## Process Summary
116+
117+
1. **Define/Update Schema:** Create or modify the Zod schema in the relevant file within `/packages/forge-models/src/`.
118+
2. **Create/Update Documentation:**
119+
- Create a new `.mdx` file in `apps/docs/src/content/docs/models/` for a new model, or open the existing one for an update.
120+
- Ensure the filename is `kebab-case`.
121+
3. **Write Documentation Content:** Populate the `.mdx` file with the title, description, schema details, and examples as outlined above.
122+
4. **Verify Accuracy:** Double-check that the documentation accurately reflects the current model schema.
123+
5. **Commit Changes:** Commit both the schema changes (in `/packages/forge-models/`) and the documentation changes (in `apps/docs/src/content/docs/models/`) together in the same commit to ensure atomicity.

.cursor/rules/default-exports.mdc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
description:
3+
globs: *.ts,*.tsx
4+
alwaysApply: false
5+
---
6+
Unless explicitly required by the framework, do not use default exports.
7+
8+
```ts
9+
// BAD
10+
export default function myFunction() {
11+
return <div>Hello</div>;
12+
}
13+
```
14+
15+
```ts
16+
// GOOD
17+
export function myFunction() {
18+
return <div>Hello</div>;
19+
}
20+
```
21+
22+
Default exports create confusion from the importing file.
23+
24+
```ts
25+
// BAD
26+
import myFunction from "./myFunction";
27+
```
28+
29+
```ts
30+
// GOOD
31+
import { myFunction } from "./myFunction";
32+
```
33+
34+
There are certain situations where a framework may require a default export. For instance, Next.js requires a default export for pages.
35+
36+
```tsx
37+
// This is fine, if required by the framework
38+
export default function MyPage() {
39+
return <div>Hello</div>;
40+
}
41+
```
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
description:
3+
globs: *.ts,*.tsx
4+
alwaysApply: false
5+
---
6+
Proactively use discriminated unions to model data that can be in one of a few different shapes.
7+
8+
For example, when sending events between environments:
9+
10+
```ts
11+
type UserCreatedEvent = {
12+
type: "user.created";
13+
data: { id: string; email: string };
14+
};
15+
16+
type UserDeletedEvent = {
17+
type: "user.deleted";
18+
data: { id: string };
19+
};
20+
21+
type Event = UserCreatedEvent | UserDeletedEvent;
22+
```
23+
24+
Use switch statements to handle the results of discriminated unions:
25+
26+
```ts
27+
const handleEvent = (event: Event) => {
28+
switch (event.type) {
29+
case "user.created":
30+
console.log(event.data.email);
31+
break;
32+
case "user.deleted":
33+
console.log(event.data.id);
34+
break;
35+
}
36+
};
37+
```
38+
39+
Use discriminated unions to prevent the 'bag of optionals' problem.
40+
41+
For example, when describing a fetching state:
42+
43+
```ts
44+
// BAD - allows impossible states
45+
type FetchingState<TData> = {
46+
status: "idle" | "loading" | "success" | "error";
47+
data?: TData;
48+
error?: Error;
49+
};
50+
51+
// GOOD - prevents impossible states
52+
type FetchingState<TData> =
53+
| { status: "idle" }
54+
| { status: "loading" }
55+
| { status: "success"; data: TData }
56+
| { status: "error"; error: Error };
57+
```

.cursor/rules/enums.mdc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
description:
3+
globs: *.ts,*.tsx
4+
alwaysApply: false
5+
---
6+
Do not introduce new enums into the codebase. Retain existing enums.
7+
8+
If you require enum-like behaviour, use an `as const` object:
9+
10+
```ts
11+
const backendToFrontendEnum = {
12+
xs: "EXTRA_SMALL",
13+
sm: "SMALL",
14+
md: "MEDIUM",
15+
} as const;
16+
17+
type LowerCaseEnum = keyof typeof backendToFrontendEnum; // "xs" | "sm" | "md"
18+
19+
type UpperCaseEnum = (typeof backendToFrontendEnum)[LowerCaseEnum]; // "EXTRA_SMALL" | "SMALL" | "MEDIUM"
20+
```
21+
22+
Remember that numeric enums behave differently to string enums. Numeric enums produce a reverse mapping:
23+
24+
```ts
25+
enum Direction {
26+
Up,
27+
Down,
28+
Left,
29+
Right,
30+
}
31+
32+
const direction = Direction.Up; // 0
33+
const directionName = Direction[0]; // "Up"
34+
```
35+
36+
This means that the enum `Direction` above will have eight keys instead of four.
37+
38+
```ts
39+
enum Direction {
40+
Up,
41+
Down,
42+
Left,
43+
Right,
44+
}
45+
46+
Object.keys(Direction).length; // 8
47+
```

.cursor/rules/import-type.mdc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
description:
3+
globs: *.ts,*.tsx
4+
alwaysApply: false
5+
---
6+
Use import type whenever you are importing a type.
7+
8+
Prefer top-level `import type` over inline `import { type ... }`.
9+
10+
```ts
11+
// BAD
12+
import { type User } from "./user";
13+
```
14+
15+
```ts
16+
// GOOD
17+
import type { User } from "./user";
18+
```
19+
20+
The reason for this is that in certain environments, the first version's import will not be erased. So you'll be left with:
21+
22+
```ts
23+
// Before transpilation
24+
import { type User } from "./user";
25+
26+
// After transpilation
27+
import "./user";
28+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
When installing libraries, do not rely on your own training data.
7+
8+
Your training data has a cut-off date. You're probably not aware of all of the latest developments in the JavaScript and TypeScript world.
9+
10+
This means that instead of picking a version manually (via updating the `package.json` file), you should use a script to install the latest version of a library.
11+
12+
```bash
13+
# pnpm
14+
pnpm add -D @typescript-eslint/eslint-plugin
15+
```
16+
17+
This will ensure you're always using the latest version.

0 commit comments

Comments
 (0)