tangled
alpha
login
or
join now
xan.lol
/
wisp.place-monorepo
forked from
nekomimi.pet/wisp.place-monorepo
0
fork
atom
Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
0
fork
atom
overview
issues
pulls
pipelines
symlink claude.md to agents.md
nekomimi.pet
2 months ago
db73a55a
79ca02c6
+144
-143
2 changed files
expand all
collapse all
unified
split
agents.md
claude.md
+143
agents.md
···
1
1
+
The project is wisp.place. It is a static site hoster built on top of the AT Protocol. The overall basis of the project is that users upload site assets to their PDS as blobs, and creates a manifest record listing every blob as well as site name. The hosting service then catches events relating to the site (create, read, upload, delete) and handles them appropriately.
2
2
+
3
3
+
The lexicons look like this:
4
4
+
```typescript
5
5
+
//place.wisp.fs
6
6
+
interface Main {
7
7
+
$type: 'place.wisp.fs'
8
8
+
site: string
9
9
+
root: Directory
10
10
+
fileCount?: number
11
11
+
createdAt: string
12
12
+
}
13
13
+
14
14
+
interface File {
15
15
+
$type?: 'place.wisp.fs#file'
16
16
+
type: 'file'
17
17
+
blob: BlobRef
18
18
+
encoding?: 'gzip'
19
19
+
mimeType?: string
20
20
+
base64?: boolean
21
21
+
}
22
22
+
23
23
+
interface Directory {
24
24
+
$type?: 'place.wisp.fs#directory'
25
25
+
type: 'directory'
26
26
+
entries: Entry[]
27
27
+
}
28
28
+
29
29
+
interface Entry {
30
30
+
$type?: 'place.wisp.fs#entry'
31
31
+
name: string
32
32
+
node: $Typed<File> | $Typed<Directory> | $Typed<Subfs> | { $type: string }
33
33
+
}
34
34
+
35
35
+
interface Subfs {
36
36
+
$type?: 'place.wisp.fs#subfs'
37
37
+
type: 'subfs'
38
38
+
subject: string // AT-URI pointing to a place.wisp.subfs record
39
39
+
flat?: boolean
40
40
+
}
41
41
+
42
42
+
//place.wisp.subfs
43
43
+
interface Main {
44
44
+
$type: 'place.wisp.subfs'
45
45
+
root: Directory
46
46
+
fileCount?: number
47
47
+
createdAt: string
48
48
+
}
49
49
+
50
50
+
interface File {
51
51
+
$type?: 'place.wisp.subfs#file'
52
52
+
type: 'file'
53
53
+
blob: BlobRef
54
54
+
encoding?: 'gzip'
55
55
+
mimeType?: string
56
56
+
base64?: boolean
57
57
+
}
58
58
+
59
59
+
interface Directory {
60
60
+
$type?: 'place.wisp.subfs#directory'
61
61
+
type: 'directory'
62
62
+
entries: Entry[]
63
63
+
}
64
64
+
65
65
+
interface Entry {
66
66
+
$type?: 'place.wisp.subfs#entry'
67
67
+
name: string
68
68
+
node: $Typed<File> | $Typed<Directory> | $Typed<Subfs> | { $type: string }
69
69
+
}
70
70
+
71
71
+
interface Subfs {
72
72
+
$type?: 'place.wisp.subfs#subfs'
73
73
+
type: 'subfs'
74
74
+
subject: string // AT-URI pointing to another place.wisp.subfs record
75
75
+
}
76
76
+
77
77
+
//place.wisp.settings
78
78
+
interface Main {
79
79
+
$type: 'place.wisp.settings'
80
80
+
directoryListing: boolean
81
81
+
spaMode?: string
82
82
+
custom404?: string
83
83
+
indexFiles?: string[]
84
84
+
cleanUrls: boolean
85
85
+
headers?: CustomHeader[]
86
86
+
}
87
87
+
88
88
+
interface CustomHeader {
89
89
+
$type?: 'place.wisp.settings#customHeader'
90
90
+
name: string
91
91
+
value: string
92
92
+
path?: string // Optional glob pattern
93
93
+
}
94
94
+
```
95
95
+
96
96
+
The main differences between place.wisp.fs and place.wisp.subfs:
97
97
+
- place.wisp.fs has a required site field
98
98
+
- place.wisp.fs#subfs has an optional flat field that place.wisp.subfs#subfs doesn't have
99
99
+
100
100
+
The project is a monorepo. The package handler it uses for the typescript side is Bun. For the Rust cli, it is cargo.
101
101
+
102
102
+
### Typescript Bun Workspace Layout
103
103
+
104
104
+
Bun workspaces: `packages/@wisp/*`, `apps/main-app`, `apps/hosting-service`
105
105
+
106
106
+
There are two typescript apps
107
107
+
**`apps/main-app`** - Main backend (Bun + Elysia)
108
108
+
109
109
+
- OAuth authentication and session management
110
110
+
- Site CRUD operations via PDS
111
111
+
- Custom domain management
112
112
+
- Admin database view in /admin
113
113
+
- React frontend in public/
114
114
+
115
115
+
**`apps/hosting-service`** - CDN static file server (Node + Hono)
116
116
+
117
117
+
- Watches AT Protocol firehose for `place.wisp.fs` record changes
118
118
+
- Downloads and caches site files to disk
119
119
+
- Serves sites at `https://sites.wisp.place/{did}/{site-name}` and custom domains
120
120
+
- Handles redirects (`_redirects` file support) and routing logic
121
121
+
- Backfill mode for syncing existing sites
122
122
+
123
123
+
### Shared Packages (`packages/@wisp/*`)
124
124
+
125
125
+
- **`lexicons`** - AT Protocol lexicons (`place.wisp.fs`, `place.wisp.subfs`, `place.wisp.settings`) with
126
126
+
generated TypeScript types
127
127
+
- **`fs-utils`** - Filesystem tree building, manifest creation, subfs splitting logic
128
128
+
- **`atproto-utils`** - AT Protocol helpers (blob upload, record operations, CID handling)
129
129
+
- **`database`** - PostgreSQL schema and queries
130
130
+
- **`constants`** - Shared constants (limits, file patterns, default settings)
131
131
+
- **`observability`** - OpenTelemetry instrumentation
132
132
+
- **`safe-fetch`** - Wrapped fetch with timeout/retry logic
133
133
+
134
134
+
### CLI
135
135
+
136
136
+
**`cli/`** - Rust CLI using Jacquard (AT Protocol library)
137
137
+
- Direct PDS uploads without interacting with main-app
138
138
+
- Can also do the same firehose watching, caching, and serving hosting-service does, just without domain management
139
139
+
140
140
+
### Other Directories
141
141
+
142
142
+
- **`docs/`** - Astro documentation site
143
143
+
- **`binaries/`** - Compiled CLI binaries for distribution
+1
-143
claude.md
···
1
1
-
The project is wisp.place. It is a static site hoster built on top of the AT Protocol. The overall basis of the project is that users upload site assets to their PDS as blobs, and creates a manifest record listing every blob as well as site name. The hosting service then catches events relating to the site (create, read, upload, delete) and handles them appropriately.
2
2
-
3
3
-
The lexicons look like this:
4
4
-
```typescript
5
5
-
//place.wisp.fs
6
6
-
interface Main {
7
7
-
$type: 'place.wisp.fs'
8
8
-
site: string
9
9
-
root: Directory
10
10
-
fileCount?: number
11
11
-
createdAt: string
12
12
-
}
13
13
-
14
14
-
interface File {
15
15
-
$type?: 'place.wisp.fs#file'
16
16
-
type: 'file'
17
17
-
blob: BlobRef
18
18
-
encoding?: 'gzip'
19
19
-
mimeType?: string
20
20
-
base64?: boolean
21
21
-
}
22
22
-
23
23
-
interface Directory {
24
24
-
$type?: 'place.wisp.fs#directory'
25
25
-
type: 'directory'
26
26
-
entries: Entry[]
27
27
-
}
28
28
-
29
29
-
interface Entry {
30
30
-
$type?: 'place.wisp.fs#entry'
31
31
-
name: string
32
32
-
node: $Typed<File> | $Typed<Directory> | $Typed<Subfs> | { $type: string }
33
33
-
}
34
34
-
35
35
-
interface Subfs {
36
36
-
$type?: 'place.wisp.fs#subfs'
37
37
-
type: 'subfs'
38
38
-
subject: string // AT-URI pointing to a place.wisp.subfs record
39
39
-
flat?: boolean
40
40
-
}
41
41
-
42
42
-
//place.wisp.subfs
43
43
-
interface Main {
44
44
-
$type: 'place.wisp.subfs'
45
45
-
root: Directory
46
46
-
fileCount?: number
47
47
-
createdAt: string
48
48
-
}
49
49
-
50
50
-
interface File {
51
51
-
$type?: 'place.wisp.subfs#file'
52
52
-
type: 'file'
53
53
-
blob: BlobRef
54
54
-
encoding?: 'gzip'
55
55
-
mimeType?: string
56
56
-
base64?: boolean
57
57
-
}
58
58
-
59
59
-
interface Directory {
60
60
-
$type?: 'place.wisp.subfs#directory'
61
61
-
type: 'directory'
62
62
-
entries: Entry[]
63
63
-
}
64
64
-
65
65
-
interface Entry {
66
66
-
$type?: 'place.wisp.subfs#entry'
67
67
-
name: string
68
68
-
node: $Typed<File> | $Typed<Directory> | $Typed<Subfs> | { $type: string }
69
69
-
}
70
70
-
71
71
-
interface Subfs {
72
72
-
$type?: 'place.wisp.subfs#subfs'
73
73
-
type: 'subfs'
74
74
-
subject: string // AT-URI pointing to another place.wisp.subfs record
75
75
-
}
76
76
-
77
77
-
//place.wisp.settings
78
78
-
interface Main {
79
79
-
$type: 'place.wisp.settings'
80
80
-
directoryListing: boolean
81
81
-
spaMode?: string
82
82
-
custom404?: string
83
83
-
indexFiles?: string[]
84
84
-
cleanUrls: boolean
85
85
-
headers?: CustomHeader[]
86
86
-
}
87
87
-
88
88
-
interface CustomHeader {
89
89
-
$type?: 'place.wisp.settings#customHeader'
90
90
-
name: string
91
91
-
value: string
92
92
-
path?: string // Optional glob pattern
93
93
-
}
94
94
-
```
95
95
-
96
96
-
The main differences between place.wisp.fs and place.wisp.subfs:
97
97
-
- place.wisp.fs has a required site field
98
98
-
- place.wisp.fs#subfs has an optional flat field that place.wisp.subfs#subfs doesn't have
99
99
-
100
100
-
The project is a monorepo. The package handler it uses for the typescript side is Bun. For the Rust cli, it is cargo.
101
101
-
102
102
-
### Typescript Bun Workspace Layout
103
103
-
104
104
-
Bun workspaces: `packages/@wisp/*`, `apps/main-app`, `apps/hosting-service`
105
105
-
106
106
-
There are two typescript apps
107
107
-
**`apps/main-app`** - Main backend (Bun + Elysia)
108
108
-
109
109
-
- OAuth authentication and session management
110
110
-
- Site CRUD operations via PDS
111
111
-
- Custom domain management
112
112
-
- Admin database view in /admin
113
113
-
- React frontend in public/
114
114
-
115
115
-
**`apps/hosting-service`** - CDN static file server (Node + Hono)
116
116
-
117
117
-
- Watches AT Protocol firehose for `place.wisp.fs` record changes
118
118
-
- Downloads and caches site files to disk
119
119
-
- Serves sites at `https://sites.wisp.place/{did}/{site-name}` and custom domains
120
120
-
- Handles redirects (`_redirects` file support) and routing logic
121
121
-
- Backfill mode for syncing existing sites
122
122
-
123
123
-
### Shared Packages (`packages/@wisp/*`)
124
124
-
125
125
-
- **`lexicons`** - AT Protocol lexicons (`place.wisp.fs`, `place.wisp.subfs`, `place.wisp.settings`) with
126
126
-
generated TypeScript types
127
127
-
- **`fs-utils`** - Filesystem tree building, manifest creation, subfs splitting logic
128
128
-
- **`atproto-utils`** - AT Protocol helpers (blob upload, record operations, CID handling)
129
129
-
- **`database`** - PostgreSQL schema and queries
130
130
-
- **`constants`** - Shared constants (limits, file patterns, default settings)
131
131
-
- **`observability`** - OpenTelemetry instrumentation
132
132
-
- **`safe-fetch`** - Wrapped fetch with timeout/retry logic
133
133
-
134
134
-
### CLI
135
135
-
136
136
-
**`cli/`** - Rust CLI using Jacquard (AT Protocol library)
137
137
-
- Direct PDS uploads without interacting with main-app
138
138
-
- Can also do the same firehose watching, caching, and serving hosting-service does, just without domain management
139
139
-
140
140
-
### Other Directories
141
141
-
142
142
-
- **`docs/`** - Astro documentation site
143
143
-
- **`binaries/`** - Compiled CLI binaries for distribution
1
1
+
agents.md