Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
wisp.place
1/**
2 * GENERATED CODE - DO NOT MODIFY
3 */
4import {
5 type LexiconDoc,
6 Lexicons,
7 ValidationError,
8 type ValidationResult,
9} from '@atproto/lexicon'
10import { type $Typed, is$typed, maybe$typed } from './util'
11
12export const schemaDict = {
13 PlaceWispFs: {
14 lexicon: 1,
15 id: 'place.wisp.fs',
16 defs: {
17 main: {
18 type: 'record',
19 description: 'Virtual filesystem manifest for a Wisp site',
20 record: {
21 type: 'object',
22 required: ['site', 'root', 'createdAt'],
23 properties: {
24 site: {
25 type: 'string',
26 },
27 root: {
28 type: 'ref',
29 ref: 'lex:place.wisp.fs#directory',
30 },
31 fileCount: {
32 type: 'integer',
33 minimum: 0,
34 maximum: 1000,
35 },
36 createdAt: {
37 type: 'string',
38 format: 'datetime',
39 },
40 },
41 },
42 },
43 file: {
44 type: 'object',
45 required: ['type', 'blob'],
46 properties: {
47 type: {
48 type: 'string',
49 const: 'file',
50 },
51 blob: {
52 type: 'blob',
53 accept: ['*/*'],
54 maxSize: 1000000000,
55 description: 'Content blob ref',
56 },
57 encoding: {
58 type: 'string',
59 enum: ['gzip'],
60 description: 'Content encoding (e.g., gzip for compressed files)',
61 },
62 mimeType: {
63 type: 'string',
64 description: 'Original MIME type before compression',
65 },
66 base64: {
67 type: 'boolean',
68 description:
69 'True if blob content is base64-encoded (used to bypass PDS content sniffing)',
70 },
71 },
72 },
73 directory: {
74 type: 'object',
75 required: ['type', 'entries'],
76 properties: {
77 type: {
78 type: 'string',
79 const: 'directory',
80 },
81 entries: {
82 type: 'array',
83 maxLength: 500,
84 items: {
85 type: 'ref',
86 ref: 'lex:place.wisp.fs#entry',
87 },
88 },
89 },
90 },
91 entry: {
92 type: 'object',
93 required: ['name', 'node'],
94 properties: {
95 name: {
96 type: 'string',
97 maxLength: 255,
98 },
99 node: {
100 type: 'union',
101 refs: [
102 'lex:place.wisp.fs#file',
103 'lex:place.wisp.fs#directory',
104 'lex:place.wisp.fs#subfs',
105 ],
106 },
107 },
108 },
109 subfs: {
110 type: 'object',
111 required: ['type', 'subject'],
112 properties: {
113 type: {
114 type: 'string',
115 const: 'subfs',
116 },
117 subject: {
118 type: 'string',
119 format: 'at-uri',
120 description:
121 'AT-URI pointing to a place.wisp.subfs record containing this subtree.',
122 },
123 flat: {
124 type: 'boolean',
125 description:
126 "If true (default), the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false, the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure.",
127 },
128 },
129 },
130 },
131 },
132 PlaceWispSettings: {
133 lexicon: 1,
134 id: 'place.wisp.settings',
135 defs: {
136 main: {
137 type: 'record',
138 description:
139 'Configuration settings for a static site hosted on wisp.place',
140 key: 'any',
141 record: {
142 type: 'object',
143 properties: {
144 directoryListing: {
145 type: 'boolean',
146 description:
147 'Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.',
148 default: false,
149 },
150 spaMode: {
151 type: 'string',
152 description:
153 "File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.",
154 maxLength: 500,
155 },
156 custom404: {
157 type: 'string',
158 description:
159 'Custom 404 error page file path. Incompatible with directoryListing and spaMode.',
160 maxLength: 500,
161 },
162 indexFiles: {
163 type: 'array',
164 description:
165 "Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
166 items: {
167 type: 'string',
168 maxLength: 255,
169 },
170 maxLength: 10,
171 },
172 cleanUrls: {
173 type: 'boolean',
174 description:
175 "Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.",
176 default: false,
177 },
178 headers: {
179 type: 'array',
180 description: 'Custom HTTP headers to set on responses',
181 items: {
182 type: 'ref',
183 ref: 'lex:place.wisp.settings#customHeader',
184 },
185 maxLength: 50,
186 },
187 },
188 },
189 },
190 customHeader: {
191 type: 'object',
192 description: 'Custom HTTP header configuration',
193 required: ['name', 'value'],
194 properties: {
195 name: {
196 type: 'string',
197 description:
198 "HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
199 maxLength: 100,
200 },
201 value: {
202 type: 'string',
203 description: 'HTTP header value',
204 maxLength: 1000,
205 },
206 path: {
207 type: 'string',
208 description:
209 "Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
210 maxLength: 500,
211 },
212 },
213 },
214 },
215 },
216 PlaceWispSubfs: {
217 lexicon: 1,
218 id: 'place.wisp.subfs',
219 defs: {
220 main: {
221 type: 'record',
222 description:
223 'Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.',
224 record: {
225 type: 'object',
226 required: ['root', 'createdAt'],
227 properties: {
228 root: {
229 type: 'ref',
230 ref: 'lex:place.wisp.subfs#directory',
231 },
232 fileCount: {
233 type: 'integer',
234 minimum: 0,
235 maximum: 1000,
236 },
237 createdAt: {
238 type: 'string',
239 format: 'datetime',
240 },
241 },
242 },
243 },
244 file: {
245 type: 'object',
246 required: ['type', 'blob'],
247 properties: {
248 type: {
249 type: 'string',
250 const: 'file',
251 },
252 blob: {
253 type: 'blob',
254 accept: ['*/*'],
255 maxSize: 1000000000,
256 description: 'Content blob ref',
257 },
258 encoding: {
259 type: 'string',
260 enum: ['gzip'],
261 description: 'Content encoding (e.g., gzip for compressed files)',
262 },
263 mimeType: {
264 type: 'string',
265 description: 'Original MIME type before compression',
266 },
267 base64: {
268 type: 'boolean',
269 description:
270 'True if blob content is base64-encoded (used to bypass PDS content sniffing)',
271 },
272 },
273 },
274 directory: {
275 type: 'object',
276 required: ['type', 'entries'],
277 properties: {
278 type: {
279 type: 'string',
280 const: 'directory',
281 },
282 entries: {
283 type: 'array',
284 maxLength: 500,
285 items: {
286 type: 'ref',
287 ref: 'lex:place.wisp.subfs#entry',
288 },
289 },
290 },
291 },
292 entry: {
293 type: 'object',
294 required: ['name', 'node'],
295 properties: {
296 name: {
297 type: 'string',
298 maxLength: 255,
299 },
300 node: {
301 type: 'union',
302 refs: [
303 'lex:place.wisp.subfs#file',
304 'lex:place.wisp.subfs#directory',
305 'lex:place.wisp.subfs#subfs',
306 ],
307 },
308 },
309 },
310 subfs: {
311 type: 'object',
312 required: ['type', 'subject'],
313 properties: {
314 type: {
315 type: 'string',
316 const: 'subfs',
317 },
318 subject: {
319 type: 'string',
320 format: 'at-uri',
321 description:
322 "AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.",
323 },
324 },
325 },
326 },
327 },
328} as const satisfies Record<string, LexiconDoc>
329export const schemas = Object.values(schemaDict) satisfies LexiconDoc[]
330export const lexicons: Lexicons = new Lexicons(schemas)
331
332export function validate<T extends { $type: string }>(
333 v: unknown,
334 id: string,
335 hash: string,
336 requiredType: true,
337): ValidationResult<T>
338export function validate<T extends { $type?: string }>(
339 v: unknown,
340 id: string,
341 hash: string,
342 requiredType?: false,
343): ValidationResult<T>
344export function validate(
345 v: unknown,
346 id: string,
347 hash: string,
348 requiredType?: boolean,
349): ValidationResult {
350 return (requiredType ? is$typed : maybe$typed)(v, id, hash)
351 ? lexicons.validate(`${id}#${hash}`, v)
352 : {
353 success: false,
354 error: new ValidationError(
355 `Must be an object with "${hash === 'main' ? id : `${id}#${hash}`}" $type property`,
356 ),
357 }
358}
359
360export const ids = {
361 PlaceWispFs: 'place.wisp.fs',
362 PlaceWispSettings: 'place.wisp.settings',
363 PlaceWispSubfs: 'place.wisp.subfs',
364} as const