+1
.gitignore
+1
.gitignore
+2
.tangled/workflows/deploy-wisp.yml
+2
.tangled/workflows/deploy-wisp.yml
+2
-1
.tangled/workflows/test.yml
+2
-1
.tangled/workflows/test.yml
···
7
7
dependencies:
8
8
nixpkgs:
9
9
- git
10
+
- findutils
10
11
github:NixOS/nixpkgs/nixpkgs-unstable:
11
12
- bun
12
13
···
16
17
export PATH="$HOME/.nix-profile/bin:$PATH"
17
18
18
19
# have to regenerate otherwise it wont install necessary dependencies to run
19
-
rm -rf bun.lock package-lock.json
20
+
find . -type f \( -name "bun.lock" -o -name "package-lock.json" \) -delete
20
21
bun install
21
22
22
23
- name: run all tests
+9
-8
apps/hosting-service/package.json
+9
-8
apps/hosting-service/package.json
···
10
10
"backfill": "tsx src/index.ts --backfill"
11
11
},
12
12
"dependencies": {
13
-
"@wisp/lexicons": "workspace:*",
14
-
"@wisp/constants": "workspace:*",
15
-
"@wisp/observability": "workspace:*",
16
-
"@wisp/atproto-utils": "workspace:*",
17
-
"@wisp/database": "workspace:*",
18
-
"@wisp/fs-utils": "workspace:*",
19
-
"@wisp/safe-fetch": "workspace:*",
20
13
"@atproto/api": "^0.17.4",
21
14
"@atproto/identity": "^0.4.9",
22
15
"@atproto/lexicon": "^0.5.2",
23
16
"@atproto/sync": "^0.1.36",
24
17
"@atproto/xrpc": "^0.7.5",
25
18
"@hono/node-server": "^1.19.6",
19
+
"@wisp/atproto-utils": "workspace:*",
20
+
"@wisp/constants": "workspace:*",
21
+
"@wisp/database": "workspace:*",
22
+
"@wisp/fs-utils": "workspace:*",
23
+
"@wisp/lexicons": "workspace:*",
24
+
"@wisp/observability": "workspace:*",
25
+
"@wisp/safe-fetch": "workspace:*",
26
26
"hono": "^4.10.4",
27
27
"mime-types": "^2.1.35",
28
28
"multiformats": "^13.4.1",
29
-
"postgres": "^3.4.5"
29
+
"postgres": "^3.4.5",
30
+
"tiered-storage": "1.0.3"
30
31
},
31
32
"devDependencies": {
32
33
"@types/bun": "^1.3.1",
+31
-3
apps/hosting-service/src/index.ts
+31
-3
apps/hosting-service/src/index.ts
···
5
5
import { mkdirSync, existsSync } from 'fs';
6
6
import { backfillCache } from './lib/backfill';
7
7
import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode, closeDatabase } from './lib/db';
8
+
import { storage, getStorageConfig } from './lib/storage';
8
9
9
10
// Initialize Grafana exporters if configured
10
11
initializeGrafanaExporters({
···
50
51
51
52
firehose.start();
52
53
54
+
// Optional: Bootstrap hot cache from warm tier on startup
55
+
const BOOTSTRAP_HOT_ON_STARTUP = process.env.BOOTSTRAP_HOT_ON_STARTUP === 'true';
56
+
const BOOTSTRAP_HOT_LIMIT = process.env.BOOTSTRAP_HOT_LIMIT ? parseInt(process.env.BOOTSTRAP_HOT_LIMIT) : 100;
57
+
58
+
if (BOOTSTRAP_HOT_ON_STARTUP) {
59
+
console.log(`๐ฅ Bootstrapping hot cache (top ${BOOTSTRAP_HOT_LIMIT} items)...`);
60
+
storage.bootstrapHot(BOOTSTRAP_HOT_LIMIT)
61
+
.then((loaded: number) => {
62
+
console.log(`โ
Bootstrapped ${loaded} items into hot cache`);
63
+
})
64
+
.catch((err: unknown) => {
65
+
console.error('โ Hot cache bootstrap error:', err);
66
+
});
67
+
}
68
+
53
69
// Run backfill if requested
54
70
if (backfillOnStartup) {
55
71
console.log('๐ Backfill requested, starting cache backfill...');
···
78
94
port: PORT,
79
95
});
80
96
97
+
// Get storage configuration for display
98
+
const storageConfig = getStorageConfig();
99
+
81
100
console.log(`
82
-
Wisp Hosting Service
101
+
Wisp Hosting Service with Tiered Storage
83
102
84
103
Server: http://localhost:${PORT}
85
104
Health: http://localhost:${PORT}/health
86
-
Cache: ${CACHE_DIR}
87
-
Firehose: Connected to Firehose
88
105
Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'}
89
106
Backfill: ${backfillOnStartup ? `ENABLED (concurrency: ${BACKFILL_CONCURRENCY || 10})` : 'DISABLED'}
107
+
108
+
Tiered Storage Configuration:
109
+
Hot Cache: ${storageConfig.hotCacheSize} (${storageConfig.hotCacheCount} items max)
110
+
Warm Cache: ${storageConfig.warmCacheSize} (${storageConfig.warmEvictionPolicy} eviction)
111
+
Cold Storage: S3 - ${storageConfig.s3Bucket}
112
+
S3 Region: ${storageConfig.s3Region}
113
+
S3 Endpoint: ${storageConfig.s3Endpoint}
114
+
S3 Prefix: ${storageConfig.s3Prefix}
115
+
Metadata Bucket: ${storageConfig.metadataBucket}
116
+
117
+
Firehose: Connecting...
90
118
`);
91
119
92
120
// Graceful shutdown
+1
-1
apps/hosting-service/src/lib/backfill.ts
+1
-1
apps/hosting-service/src/lib/backfill.ts
···
69
69
const processSite = async () => {
70
70
try {
71
71
// Check if already cached
72
-
if (skipExisting && isCached(site.did, site.rkey)) {
72
+
if (skipExisting && await isCached(site.did, site.rkey)) {
73
73
stats.skipped++;
74
74
processed++;
75
75
logger.debug(`Skipping already cached site`, { did: site.did, rkey: site.rkey });
+35
-43
apps/hosting-service/src/lib/cache.ts
+35
-43
apps/hosting-service/src/lib/cache.ts
···
1
-
// In-memory LRU cache for file contents and metadata
1
+
/**
2
+
* Cache management for wisp-hosting-service
3
+
*
4
+
* With tiered storage, most caching is handled transparently.
5
+
* This module tracks sites being cached and manages rewritten HTML cache.
6
+
*/
2
7
8
+
import { storage } from './storage';
9
+
10
+
// In-memory LRU cache for rewritten HTML (for path rewriting in subdomain routes)
3
11
interface CacheEntry<T> {
4
12
value: T;
5
13
size: number;
···
96
104
return true;
97
105
}
98
106
99
-
// Invalidate all entries for a specific site
100
-
invalidateSite(did: string, rkey: string): number {
101
-
const prefix = `${did}:${rkey}:`;
102
-
let count = 0;
103
-
104
-
for (const key of Array.from(this.cache.keys())) {
105
-
if (key.startsWith(prefix)) {
106
-
this.delete(key);
107
-
count++;
108
-
}
109
-
}
110
-
111
-
return count;
112
-
}
113
-
114
-
// Get cache size
115
107
size(): number {
116
108
return this.cache.size;
117
109
}
···
127
119
return { ...this.stats };
128
120
}
129
121
130
-
// Get cache hit rate
131
122
getHitRate(): number {
132
123
const total = this.stats.hits + this.stats.misses;
133
124
return total === 0 ? 0 : (this.stats.hits / total) * 100;
134
125
}
135
126
}
136
127
137
-
// File metadata cache entry
138
-
export interface FileMetadata {
139
-
encoding?: 'gzip';
140
-
mimeType: string;
141
-
}
142
-
143
-
// Global cache instances
144
-
const FILE_CACHE_SIZE = 100 * 1024 * 1024; // 100MB
145
-
const FILE_CACHE_COUNT = 500;
146
-
const METADATA_CACHE_COUNT = 2000;
147
-
148
-
export const fileCache = new LRUCache<Buffer>(FILE_CACHE_SIZE, FILE_CACHE_COUNT);
149
-
export const metadataCache = new LRUCache<FileMetadata>(1024 * 1024, METADATA_CACHE_COUNT); // 1MB for metadata
128
+
// Rewritten HTML cache: stores HTML after path rewriting for subdomain routes
150
129
export const rewrittenHtmlCache = new LRUCache<Buffer>(50 * 1024 * 1024, 200); // 50MB for rewritten HTML
151
130
152
-
// Helper to generate cache keys
131
+
// Helper to generate cache keys for rewritten HTML
153
132
export function getCacheKey(did: string, rkey: string, filePath: string, suffix?: string): string {
154
133
const base = `${did}:${rkey}:${filePath}`;
155
134
return suffix ? `${base}:${suffix}` : base;
156
135
}
157
136
158
-
// Invalidate all caches for a site
159
-
export function invalidateSiteCache(did: string, rkey: string): void {
160
-
const fileCount = fileCache.invalidateSite(did, rkey);
161
-
const metaCount = metadataCache.invalidateSite(did, rkey);
162
-
const htmlCount = rewrittenHtmlCache.invalidateSite(did, rkey);
137
+
/**
138
+
* Invalidate site cache via tiered storage
139
+
* Also invalidates locally cached rewritten HTML
140
+
*/
141
+
export async function invalidateSiteCache(did: string, rkey: string): Promise<void> {
142
+
// Invalidate in tiered storage
143
+
const prefix = `${did}/${rkey}/`;
144
+
const deleted = await storage.invalidate(prefix);
163
145
164
-
console.log(`[Cache] Invalidated site ${did}:${rkey} - ${fileCount} files, ${metaCount} metadata, ${htmlCount} HTML`);
146
+
// Invalidate rewritten HTML cache for this site
147
+
const sitePrefix = `${did}:${rkey}:`;
148
+
let htmlCount = 0;
149
+
const cacheKeys = Array.from((rewrittenHtmlCache as any).cache?.keys() || []) as string[];
150
+
for (const key of cacheKeys) {
151
+
if (key.startsWith(sitePrefix)) {
152
+
rewrittenHtmlCache.delete(key);
153
+
htmlCount++;
154
+
}
155
+
}
156
+
157
+
console.log(`[Cache] Invalidated site ${did}:${rkey} - ${deleted} files in tiered storage, ${htmlCount} rewritten HTML`);
165
158
}
166
159
167
160
// Track sites currently being cached (to prevent serving stale cache during updates)
···
183
176
}
184
177
185
178
// Get overall cache statistics
186
-
export function getCacheStats() {
179
+
export async function getCacheStats() {
180
+
const tieredStats = await storage.getStats();
181
+
187
182
return {
188
-
files: fileCache.getStats(),
189
-
fileHitRate: fileCache.getHitRate(),
190
-
metadata: metadataCache.getStats(),
191
-
metadataHitRate: metadataCache.getHitRate(),
183
+
tieredStorage: tieredStats,
192
184
rewrittenHtml: rewrittenHtmlCache.getStats(),
193
185
rewrittenHtmlHitRate: rewrittenHtmlCache.getHitRate(),
194
186
sitesBeingCached: sitesBeingCached.size,
+64
-76
apps/hosting-service/src/lib/file-serving.ts
+64
-76
apps/hosting-service/src/lib/file-serving.ts
···
7
7
import { lookup } from 'mime-types';
8
8
import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings';
9
9
import { shouldCompressMimeType } from '@wisp/atproto-utils/compression';
10
-
import { fileCache, metadataCache, rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache';
10
+
import { rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache';
11
11
import { getCachedFilePath, getCachedSettings } from './utils';
12
12
import { loadRedirectRules, matchRedirectRule, parseCookies, parseQueryString } from './redirects';
13
13
import { rewriteHtmlPaths, isHtmlContent } from './html-rewriter';
14
14
import { generate404Page, generateDirectoryListing, siteUpdatingResponse } from './page-generators';
15
15
import { getIndexFiles, applyCustomHeaders, fileExists } from './request-utils';
16
16
import { getRedirectRulesFromCache, setRedirectRulesInCache } from './site-cache';
17
+
import { storage } from './storage';
18
+
19
+
/**
20
+
* Helper to retrieve a file with metadata from tiered storage
21
+
*/
22
+
async function getFileWithMetadata(did: string, rkey: string, filePath: string) {
23
+
const key = `${did}/${rkey}/${filePath}`;
24
+
return await storage.getWithMetadata(key);
25
+
}
17
26
18
27
/**
19
28
* Helper to serve files from cache (for custom domains and subdomains)
···
176
185
177
186
// Not a directory, try to serve as a file
178
187
const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html';
179
-
const cacheKey = getCacheKey(did, rkey, fileRequestPath);
180
-
const cachedFile = getCachedFilePath(did, rkey, fileRequestPath);
181
188
182
-
// Check in-memory cache first
183
-
let content = fileCache.get(cacheKey);
184
-
let meta = metadataCache.get(cacheKey);
189
+
// Retrieve from tiered storage
190
+
const result = await getFileWithMetadata(did, rkey, fileRequestPath);
185
191
186
-
if (!content && await fileExists(cachedFile)) {
187
-
// Read from disk and cache
188
-
content = await readFile(cachedFile);
189
-
fileCache.set(cacheKey, content, content.length);
192
+
if (result) {
193
+
const content = Buffer.from(result.data);
194
+
const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
190
195
191
-
const metaFile = `${cachedFile}.meta`;
192
-
if (await fileExists(metaFile)) {
193
-
const metaJson = await readFile(metaFile, 'utf-8');
194
-
meta = JSON.parse(metaJson);
195
-
metadataCache.set(cacheKey, meta!, JSON.stringify(meta).length);
196
-
}
197
-
}
198
-
199
-
if (content) {
200
196
// Build headers with caching
201
-
const headers: Record<string, string> = {};
197
+
const headers: Record<string, string> = {
198
+
'X-Cache-Tier': result.source,
199
+
};
202
200
203
-
if (meta && meta.encoding === 'gzip' && meta.mimeType) {
201
+
if (meta?.encoding === 'gzip' && meta.mimeType) {
204
202
const shouldServeCompressed = shouldCompressMimeType(meta.mimeType);
205
203
206
204
if (!shouldServeCompressed) {
···
233
231
}
234
232
235
233
// Non-compressed files
236
-
const mimeType = lookup(cachedFile) || 'application/octet-stream';
234
+
const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream';
237
235
headers['Content-Type'] = mimeType;
238
236
headers['Cache-Control'] = mimeType.startsWith('text/html')
239
237
? 'public, max-age=300'
···
246
244
if (!fileRequestPath.includes('.')) {
247
245
for (const indexFileName of indexFiles) {
248
246
const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName;
249
-
const indexCacheKey = getCacheKey(did, rkey, indexPath);
250
-
const indexFile = getCachedFilePath(did, rkey, indexPath);
251
247
252
-
let indexContent = fileCache.get(indexCacheKey);
253
-
let indexMeta = metadataCache.get(indexCacheKey);
248
+
const indexResult = await getFileWithMetadata(did, rkey, indexPath);
254
249
255
-
if (!indexContent && await fileExists(indexFile)) {
256
-
indexContent = await readFile(indexFile);
257
-
fileCache.set(indexCacheKey, indexContent, indexContent.length);
250
+
if (indexResult) {
251
+
const indexContent = Buffer.from(indexResult.data);
252
+
const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
258
253
259
-
const indexMetaFile = `${indexFile}.meta`;
260
-
if (await fileExists(indexMetaFile)) {
261
-
const metaJson = await readFile(indexMetaFile, 'utf-8');
262
-
indexMeta = JSON.parse(metaJson);
263
-
metadataCache.set(indexCacheKey, indexMeta!, JSON.stringify(indexMeta).length);
264
-
}
265
-
}
266
-
267
-
if (indexContent) {
268
254
const headers: Record<string, string> = {
269
255
'Content-Type': 'text/html; charset=utf-8',
270
256
'Cache-Control': 'public, max-age=300',
257
+
'X-Cache-Tier': indexResult.source,
271
258
};
272
259
273
-
if (indexMeta && indexMeta.encoding === 'gzip') {
260
+
if (indexMeta?.encoding === 'gzip') {
274
261
headers['Content-Encoding'] = 'gzip';
275
262
}
276
263
···
556
543
557
544
// Not a directory, try to serve as a file
558
545
const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html';
559
-
const cacheKey = getCacheKey(did, rkey, fileRequestPath);
560
-
const cachedFile = getCachedFilePath(did, rkey, fileRequestPath);
561
546
562
547
// Check for rewritten HTML in cache first (if it's HTML)
563
548
const mimeTypeGuess = lookup(fileRequestPath) || 'application/octet-stream';
···
565
550
const rewrittenKey = getCacheKey(did, rkey, fileRequestPath, `rewritten:${basePath}`);
566
551
const rewrittenContent = rewrittenHtmlCache.get(rewrittenKey);
567
552
if (rewrittenContent) {
553
+
console.log(`[HTML Rewrite] Serving from rewritten cache: ${rewrittenKey}`);
568
554
const headers: Record<string, string> = {
569
555
'Content-Type': 'text/html; charset=utf-8',
570
556
'Content-Encoding': 'gzip',
571
557
'Cache-Control': 'public, max-age=300',
558
+
'X-Cache-Tier': 'local', // Rewritten HTML is stored locally
572
559
};
573
560
applyCustomHeaders(headers, fileRequestPath, settings);
574
561
return new Response(rewrittenContent, { headers });
575
562
}
576
563
}
577
564
578
-
// Check in-memory file cache
579
-
let content = fileCache.get(cacheKey);
580
-
let meta = metadataCache.get(cacheKey);
565
+
// Retrieve from tiered storage
566
+
const result = await getFileWithMetadata(did, rkey, fileRequestPath);
581
567
582
-
if (!content && await fileExists(cachedFile)) {
583
-
// Read from disk and cache
584
-
content = await readFile(cachedFile);
585
-
fileCache.set(cacheKey, content, content.length);
568
+
if (result) {
569
+
const content = Buffer.from(result.data);
570
+
const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
571
+
const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream';
572
+
const isGzipped = meta?.encoding === 'gzip';
586
573
587
-
const metaFile = `${cachedFile}.meta`;
588
-
if (await fileExists(metaFile)) {
589
-
const metaJson = await readFile(metaFile, 'utf-8');
590
-
meta = JSON.parse(metaJson);
591
-
metadataCache.set(cacheKey, meta!, JSON.stringify(meta).length);
592
-
}
593
-
}
594
-
595
-
if (content) {
596
-
const mimeType = meta?.mimeType || lookup(cachedFile) || 'application/octet-stream';
597
-
const isGzipped = meta?.encoding === 'gzip';
574
+
console.log(`[File Serve] Serving ${fileRequestPath}, mimeType: ${mimeType}, isHTML: ${isHtmlContent(fileRequestPath, mimeType)}, basePath: ${basePath}`);
598
575
599
576
// Check if this is HTML content that needs rewriting
600
577
if (isHtmlContent(fileRequestPath, mimeType)) {
578
+
console.log(`[HTML Rewrite] Processing ${fileRequestPath}, basePath: ${basePath}, mimeType: ${mimeType}, isGzipped: ${isGzipped}`);
601
579
let htmlContent: string;
602
580
if (isGzipped) {
603
581
// Verify content is actually gzipped
···
612
590
} else {
613
591
htmlContent = content.toString('utf-8');
614
592
}
593
+
// Check for <base> tag which can override paths
594
+
const baseTagMatch = htmlContent.match(/<base\s+[^>]*href=["'][^"']+["'][^>]*>/i);
595
+
if (baseTagMatch) {
596
+
console.warn(`[HTML Rewrite] WARNING: <base> tag found: ${baseTagMatch[0]} - this may override path rewrites`);
597
+
}
598
+
599
+
// Find src/href attributes (quoted and unquoted) to debug
600
+
const allMatches = htmlContent.match(/(?:src|href)\s*=\s*["']?\/[^"'\s>]+/g);
601
+
console.log(`[HTML Rewrite] Found ${allMatches ? allMatches.length : 0} local path attrs`);
602
+
if (allMatches && allMatches.length > 0) {
603
+
console.log(`[HTML Rewrite] Sample paths: ${allMatches.slice(0, 5).join(', ')}`);
604
+
}
605
+
615
606
const rewritten = rewriteHtmlPaths(htmlContent, basePath, fileRequestPath);
616
607
608
+
const rewrittenMatches = rewritten.match(/(?:src|href)\s*=\s*["']?\/[^"'\s>]+/g);
609
+
console.log(`[HTML Rewrite] After rewrite, found ${rewrittenMatches ? rewrittenMatches.length : 0} local paths`);
610
+
if (rewrittenMatches && rewrittenMatches.length > 0) {
611
+
console.log(`[HTML Rewrite] Sample rewritten: ${rewrittenMatches.slice(0, 5).join(', ')}`);
612
+
}
613
+
617
614
// Recompress and cache the rewritten HTML
618
615
const { gzipSync } = await import('zlib');
619
616
const recompressed = gzipSync(Buffer.from(rewritten, 'utf-8'));
···
625
622
'Content-Type': 'text/html; charset=utf-8',
626
623
'Content-Encoding': 'gzip',
627
624
'Cache-Control': 'public, max-age=300',
625
+
'X-Cache-Tier': result.source,
628
626
};
629
627
applyCustomHeaders(htmlHeaders, fileRequestPath, settings);
630
628
return new Response(recompressed, { headers: htmlHeaders });
···
634
632
const headers: Record<string, string> = {
635
633
'Content-Type': mimeType,
636
634
'Cache-Control': 'public, max-age=31536000, immutable',
635
+
'X-Cache-Tier': result.source,
637
636
};
638
637
639
638
if (isGzipped) {
···
663
662
if (!fileRequestPath.includes('.')) {
664
663
for (const indexFileName of indexFiles) {
665
664
const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName;
666
-
const indexCacheKey = getCacheKey(did, rkey, indexPath);
667
-
const indexFile = getCachedFilePath(did, rkey, indexPath);
668
665
669
666
// Check for rewritten index file in cache
670
667
const rewrittenKey = getCacheKey(did, rkey, indexPath, `rewritten:${basePath}`);
···
674
671
'Content-Type': 'text/html; charset=utf-8',
675
672
'Content-Encoding': 'gzip',
676
673
'Cache-Control': 'public, max-age=300',
674
+
'X-Cache-Tier': 'local', // Rewritten HTML is stored locally
677
675
};
678
676
applyCustomHeaders(headers, indexPath, settings);
679
677
return new Response(rewrittenContent, { headers });
680
678
}
681
679
682
-
let indexContent = fileCache.get(indexCacheKey);
683
-
let indexMeta = metadataCache.get(indexCacheKey);
680
+
const indexResult = await getFileWithMetadata(did, rkey, indexPath);
684
681
685
-
if (!indexContent && await fileExists(indexFile)) {
686
-
indexContent = await readFile(indexFile);
687
-
fileCache.set(indexCacheKey, indexContent, indexContent.length);
688
-
689
-
const indexMetaFile = `${indexFile}.meta`;
690
-
if (await fileExists(indexMetaFile)) {
691
-
const metaJson = await readFile(indexMetaFile, 'utf-8');
692
-
indexMeta = JSON.parse(metaJson);
693
-
metadataCache.set(indexCacheKey, indexMeta!, JSON.stringify(indexMeta).length);
694
-
}
695
-
}
696
-
697
-
if (indexContent) {
682
+
if (indexResult) {
683
+
const indexContent = Buffer.from(indexResult.data);
684
+
const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
698
685
const isGzipped = indexMeta?.encoding === 'gzip';
699
686
700
687
let htmlContent: string;
···
722
709
'Content-Type': 'text/html; charset=utf-8',
723
710
'Content-Encoding': 'gzip',
724
711
'Cache-Control': 'public, max-age=300',
712
+
'X-Cache-Tier': indexResult.source,
725
713
};
726
714
applyCustomHeaders(headers, indexPath, settings);
727
715
return new Response(recompressed, { headers });
+46
-35
apps/hosting-service/src/lib/firehose.ts
+46
-35
apps/hosting-service/src/lib/firehose.ts
···
1
-
import { existsSync, rmSync } from 'fs'
1
+
import { existsSync } from 'fs'
2
2
import {
3
3
getPdsForDid,
4
4
downloadAndCacheSite,
···
13
13
import { invalidateSiteCache, markSiteAsBeingCached, unmarkSiteAsBeingCached } from './cache'
14
14
import { clearRedirectRulesCache } from './site-cache'
15
15
16
-
const CACHE_DIR = './cache/sites'
16
+
const CACHE_DIR = process.env.CACHE_DIR || './cache/sites'
17
17
18
18
export class FirehoseWorker {
19
19
private firehose: Firehose | null = null
20
20
private idResolver: IdResolver
21
21
private isShuttingDown = false
22
22
private lastEventTime = Date.now()
23
+
private eventCount = 0
23
24
private cacheCleanupInterval: NodeJS.Timeout | null = null
25
+
private healthCheckInterval: NodeJS.Timeout | null = null
24
26
25
27
constructor(
26
28
private logger?: (msg: string, data?: Record<string, unknown>) => void
···
47
49
48
50
this.log('IdResolver cache cleared')
49
51
}, 60 * 60 * 1000) // Every hour
52
+
53
+
// Health check: log if no events received for 30 seconds
54
+
this.healthCheckInterval = setInterval(() => {
55
+
if (this.isShuttingDown) return
56
+
57
+
const timeSinceLastEvent = Date.now() - this.lastEventTime
58
+
if (timeSinceLastEvent > 30000 && this.eventCount === 0) {
59
+
this.log('Warning: No firehose events received in the last 30 seconds', {
60
+
timeSinceLastEvent,
61
+
eventsReceived: this.eventCount
62
+
})
63
+
} else if (timeSinceLastEvent > 60000) {
64
+
this.log('Firehose status check', {
65
+
timeSinceLastEvent,
66
+
eventsReceived: this.eventCount
67
+
})
68
+
}
69
+
}, 30000) // Every 30 seconds
50
70
}
51
71
52
72
start() {
···
61
81
if (this.cacheCleanupInterval) {
62
82
clearInterval(this.cacheCleanupInterval)
63
83
this.cacheCleanupInterval = null
84
+
}
85
+
86
+
if (this.healthCheckInterval) {
87
+
clearInterval(this.healthCheckInterval)
88
+
this.healthCheckInterval = null
64
89
}
65
90
66
91
if (this.firehose) {
···
80
105
filterCollections: ['place.wisp.fs', 'place.wisp.settings'],
81
106
handleEvent: async (evt: any) => {
82
107
this.lastEventTime = Date.now()
108
+
this.eventCount++
109
+
110
+
if (this.eventCount === 1) {
111
+
this.log('First firehose event received - connection established', {
112
+
eventType: evt.event,
113
+
collection: evt.collection
114
+
})
115
+
}
83
116
84
117
// Watch for write events
85
118
if (evt.event === 'create' || evt.event === 'update') {
···
189
222
}
190
223
})
191
224
192
-
this.firehose.start()
193
-
this.log('Firehose started')
225
+
this.firehose.start().catch((err: unknown) => {
226
+
this.log('Fatal firehose error', {
227
+
error: err instanceof Error ? err.message : String(err)
228
+
})
229
+
console.error('Fatal firehose error:', err)
230
+
})
231
+
this.log('Firehose starting')
194
232
}
195
233
196
234
private async handleCreateOrUpdate(
···
250
288
}
251
289
252
290
// Invalidate in-memory caches before updating
253
-
invalidateSiteCache(did, site)
291
+
await invalidateSiteCache(did, site)
254
292
255
293
// Mark site as being cached to prevent serving stale content during update
256
294
markSiteAsBeingCached(did, site)
···
340
378
})
341
379
}
342
380
343
-
// Invalidate in-memory caches
344
-
invalidateSiteCache(did, site)
345
-
346
-
// Delete disk cache
347
-
this.deleteCache(did, site)
381
+
// Invalidate all caches (tiered storage invalidation is handled by invalidateSiteCache)
382
+
await invalidateSiteCache(did, site)
348
383
349
384
this.log('Successfully processed delete', { did, site })
350
385
}
···
353
388
this.log('Processing settings change', { did, rkey })
354
389
355
390
// Invalidate in-memory caches (includes metadata which stores settings)
356
-
invalidateSiteCache(did, rkey)
391
+
await invalidateSiteCache(did, rkey)
357
392
358
393
// Check if site is already cached
359
394
const cacheDir = `${CACHE_DIR}/${did}/${rkey}`
···
413
448
}
414
449
415
450
this.log('Successfully processed settings change', { did, rkey })
416
-
}
417
-
418
-
private deleteCache(did: string, site: string) {
419
-
const cacheDir = `${CACHE_DIR}/${did}/${site}`
420
-
421
-
if (!existsSync(cacheDir)) {
422
-
this.log('Cache directory does not exist, nothing to delete', {
423
-
did,
424
-
site
425
-
})
426
-
return
427
-
}
428
-
429
-
try {
430
-
rmSync(cacheDir, { recursive: true, force: true })
431
-
this.log('Cache deleted', { did, site, path: cacheDir })
432
-
} catch (err) {
433
-
this.log('Failed to delete cache', {
434
-
did,
435
-
site,
436
-
path: cacheDir,
437
-
error: err instanceof Error ? err.message : String(err)
438
-
})
439
-
}
440
451
}
441
452
442
453
getHealth() {
+16
apps/hosting-service/src/lib/html-rewriter.ts
+16
apps/hosting-service/src/lib/html-rewriter.ts
···
189
189
`\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}'([^']*)'`,
190
190
'gi'
191
191
)
192
+
// Unquoted attributes (valid in HTML5 for values without spaces/special chars)
193
+
// Match: attr=value where value starts immediately (no quotes) and continues until space or >
194
+
// Use negative lookahead to ensure we don't match quoted attributes
195
+
const unquotedRegex = new RegExp(
196
+
`\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}(?!["'])([^\\s>]+)`,
197
+
'gi'
198
+
)
192
199
193
200
rewritten = rewritten.replace(doubleQuoteRegex, (match, value) => {
194
201
const rewrittenValue = rewritePath(
···
206
213
documentPath
207
214
)
208
215
return `${attr}='${rewrittenValue}'`
216
+
})
217
+
218
+
rewritten = rewritten.replace(unquotedRegex, (match, value) => {
219
+
const rewrittenValue = rewritePath(
220
+
value,
221
+
normalizedBase,
222
+
documentPath
223
+
)
224
+
return `${attr}=${rewrittenValue}`
209
225
})
210
226
}
211
227
}
+1
-1
apps/hosting-service/src/lib/site-cache.ts
+1
-1
apps/hosting-service/src/lib/site-cache.ts
+270
apps/hosting-service/src/lib/storage.ts
+270
apps/hosting-service/src/lib/storage.ts
···
1
+
/**
2
+
* Tiered storage configuration for wisp-hosting-service
3
+
*
4
+
* Implements a three-tier caching strategy:
5
+
* - Hot (Memory): Instant access for frequently used files (index.html, CSS, JS)
6
+
* - Warm (Disk): Local cache with eviction policy
7
+
* - Cold (S3/R2): Object storage as source of truth (optional)
8
+
*
9
+
* When S3 is not configured, falls back to disk-only mode (warm tier acts as source of truth).
10
+
* In cache-only mode (non-master nodes), S3 writes are skipped even if configured.
11
+
*/
12
+
13
+
import {
14
+
TieredStorage,
15
+
MemoryStorageTier,
16
+
DiskStorageTier,
17
+
S3StorageTier,
18
+
type StorageTier,
19
+
type StorageMetadata,
20
+
} from 'tiered-storage';
21
+
22
+
const CACHE_DIR = process.env.CACHE_DIR || './cache/sites';
23
+
const HOT_CACHE_SIZE = parseInt(process.env.HOT_CACHE_SIZE || '104857600', 10); // 100MB default
24
+
const HOT_CACHE_COUNT = parseInt(process.env.HOT_CACHE_COUNT || '500', 10);
25
+
const WARM_CACHE_SIZE = parseInt(process.env.WARM_CACHE_SIZE || '10737418240', 10); // 10GB default
26
+
const WARM_EVICTION_POLICY = (process.env.WARM_EVICTION_POLICY || 'lru') as 'lru' | 'fifo' | 'size';
27
+
28
+
// Cache-only mode: skip S3 writes (non-master nodes)
29
+
// This is the same flag used to skip database writes
30
+
const CACHE_ONLY_MODE = process.env.CACHE_ONLY_MODE === 'true';
31
+
32
+
// S3/Cold tier configuration (optional)
33
+
const S3_BUCKET = process.env.S3_BUCKET || '';
34
+
const S3_METADATA_BUCKET = process.env.S3_METADATA_BUCKET;
35
+
const S3_REGION = process.env.S3_REGION || 'us-east-1';
36
+
const S3_ENDPOINT = process.env.S3_ENDPOINT;
37
+
const S3_FORCE_PATH_STYLE = process.env.S3_FORCE_PATH_STYLE !== 'false';
38
+
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
39
+
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
40
+
const S3_PREFIX = process.env.S3_PREFIX || 'sites/';
41
+
42
+
// Identity serializers for raw binary data (no JSON transformation)
43
+
// Files are stored as-is without any encoding/decoding
44
+
const identitySerialize = async (data: unknown): Promise<Uint8Array> => {
45
+
if (data instanceof Uint8Array) return data;
46
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
47
+
if (Buffer.isBuffer(data)) return new Uint8Array(data);
48
+
// For other types, fall back to JSON (shouldn't happen with file storage)
49
+
return new TextEncoder().encode(JSON.stringify(data));
50
+
};
51
+
52
+
const identityDeserialize = async (data: Uint8Array): Promise<unknown> => {
53
+
// Return as-is for binary file storage
54
+
return data;
55
+
};
56
+
57
+
/**
58
+
* Read-only wrapper for S3 tier in cache-only mode.
59
+
* Allows reads from S3 but skips all writes (for non-master nodes).
60
+
*/
61
+
class ReadOnlyS3Tier implements StorageTier {
62
+
private static hasLoggedWriteSkip = false;
63
+
64
+
constructor(private tier: StorageTier) {}
65
+
66
+
// Read operations - pass through to underlying tier
67
+
async get(key: string) {
68
+
return this.tier.get(key);
69
+
}
70
+
71
+
async getWithMetadata(key: string) {
72
+
return this.tier.getWithMetadata?.(key) ?? null;
73
+
}
74
+
75
+
async getStream(key: string) {
76
+
return this.tier.getStream?.(key) ?? null;
77
+
}
78
+
79
+
async exists(key: string) {
80
+
return this.tier.exists(key);
81
+
}
82
+
83
+
async getMetadata(key: string) {
84
+
return this.tier.getMetadata(key);
85
+
}
86
+
87
+
async *listKeys(prefix?: string) {
88
+
yield* this.tier.listKeys(prefix);
89
+
}
90
+
91
+
async getStats() {
92
+
return this.tier.getStats();
93
+
}
94
+
95
+
// Write operations - no-op in cache-only mode
96
+
async set(key: string, _data: Uint8Array, _metadata: StorageMetadata) {
97
+
this.logWriteSkip('set', key);
98
+
}
99
+
100
+
async setStream(key: string, _stream: NodeJS.ReadableStream, _metadata: StorageMetadata) {
101
+
this.logWriteSkip('setStream', key);
102
+
}
103
+
104
+
async setMetadata(key: string, _metadata: StorageMetadata) {
105
+
this.logWriteSkip('setMetadata', key);
106
+
}
107
+
108
+
async delete(key: string) {
109
+
this.logWriteSkip('delete', key);
110
+
}
111
+
112
+
async deleteMany(keys: string[]) {
113
+
this.logWriteSkip('deleteMany', `${keys.length} keys`);
114
+
}
115
+
116
+
async clear() {
117
+
this.logWriteSkip('clear', 'all keys');
118
+
}
119
+
120
+
private logWriteSkip(operation: string, key: string) {
121
+
// Only log once to avoid spam
122
+
if (!ReadOnlyS3Tier.hasLoggedWriteSkip) {
123
+
console.log(`[Storage] Cache-only mode: skipping S3 writes (operation: ${operation})`);
124
+
ReadOnlyS3Tier.hasLoggedWriteSkip = true;
125
+
}
126
+
}
127
+
}
128
+
129
+
/**
130
+
* Initialize tiered storage
131
+
* Must be called before serving requests
132
+
*/
133
+
function initializeStorage(): TieredStorage<Uint8Array> {
134
+
// Determine cold tier: S3 if configured, otherwise disk acts as cold
135
+
let coldTier: StorageTier;
136
+
let warmTier: StorageTier | undefined;
137
+
138
+
const diskTier = new DiskStorageTier({
139
+
directory: CACHE_DIR,
140
+
maxSizeBytes: WARM_CACHE_SIZE,
141
+
evictionPolicy: WARM_EVICTION_POLICY,
142
+
encodeColons: false, // Preserve colons for readable DID paths on Unix/macOS
143
+
});
144
+
145
+
if (S3_BUCKET) {
146
+
// Full three-tier setup with S3 as cold storage
147
+
const s3Tier = new S3StorageTier({
148
+
bucket: S3_BUCKET,
149
+
metadataBucket: S3_METADATA_BUCKET,
150
+
region: S3_REGION,
151
+
endpoint: S3_ENDPOINT,
152
+
forcePathStyle: S3_FORCE_PATH_STYLE,
153
+
credentials:
154
+
AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY
155
+
? { accessKeyId: AWS_ACCESS_KEY_ID, secretAccessKey: AWS_SECRET_ACCESS_KEY }
156
+
: undefined,
157
+
prefix: S3_PREFIX,
158
+
});
159
+
160
+
// In cache-only mode, wrap S3 tier to make it read-only
161
+
coldTier = CACHE_ONLY_MODE ? new ReadOnlyS3Tier(s3Tier) : s3Tier;
162
+
warmTier = diskTier;
163
+
164
+
if (CACHE_ONLY_MODE) {
165
+
console.log('[Storage] Cache-only mode: S3 as read-only cold tier (no writes), disk as warm tier');
166
+
} else {
167
+
console.log('[Storage] Using S3 as cold tier, disk as warm tier');
168
+
}
169
+
} else {
170
+
// Disk-only mode: disk tier acts as source of truth (cold)
171
+
coldTier = diskTier;
172
+
warmTier = undefined;
173
+
console.log('[Storage] S3 not configured - using disk-only mode (disk as cold tier)');
174
+
}
175
+
176
+
const storage = new TieredStorage<Uint8Array>({
177
+
tiers: {
178
+
// Hot tier: In-memory LRU for instant serving
179
+
hot: new MemoryStorageTier({
180
+
maxSizeBytes: HOT_CACHE_SIZE,
181
+
maxItems: HOT_CACHE_COUNT,
182
+
}),
183
+
184
+
// Warm tier: Disk-based cache (only when S3 is configured)
185
+
warm: warmTier,
186
+
187
+
// Cold tier: S3/R2 as source of truth, or disk in disk-only mode
188
+
cold: coldTier,
189
+
},
190
+
191
+
// Placement rules: determine which tiers each file goes to
192
+
placementRules: [
193
+
// Metadata is critical: frequently accessed for cache validity checks
194
+
{
195
+
pattern: '**/.metadata.json',
196
+
tiers: ['hot', 'warm', 'cold'],
197
+
},
198
+
199
+
// index.html is critical: write to all tiers for instant serving
200
+
{
201
+
pattern: '**/index.html',
202
+
tiers: ['hot', 'warm', 'cold'],
203
+
},
204
+
{
205
+
pattern: 'index.html',
206
+
tiers: ['hot', 'warm', 'cold'],
207
+
},
208
+
209
+
// CSS and JS: eligible for hot tier if accessed frequently
210
+
{
211
+
pattern: '**/*.{css,js}',
212
+
tiers: ['hot', 'warm', 'cold'],
213
+
},
214
+
215
+
// Media files: never needed in memory, skip hot tier
216
+
{
217
+
pattern: '**/*.{jpg,jpeg,png,gif,webp,svg,ico,mp4,webm,mp3,woff,woff2,ttf,eot}',
218
+
tiers: ['warm', 'cold'],
219
+
},
220
+
221
+
// Default: everything else goes to warm and cold
222
+
{
223
+
pattern: '**',
224
+
tiers: ['warm', 'cold'],
225
+
},
226
+
],
227
+
228
+
// IMPORTANT: Compression is disabled at the tiered-storage level
229
+
// Text files (HTML, CSS, JS, JSON) are pre-compressed with gzip at the app level
230
+
// Binary files (images, video) are stored uncompressed as they're already compressed
231
+
// The file's compression state is tracked in customMetadata.encoding
232
+
compression: false,
233
+
234
+
// TTL for cache entries (14 days)
235
+
defaultTTL: 14 * 24 * 60 * 60 * 1000,
236
+
237
+
// Eager promotion: promote data to upper tiers on read
238
+
// This ensures frequently accessed files end up in hot tier
239
+
promotionStrategy: 'eager',
240
+
241
+
// Identity serialization: store raw binary without JSON transformation
242
+
serialization: {
243
+
serialize: identitySerialize,
244
+
deserialize: identityDeserialize,
245
+
},
246
+
});
247
+
248
+
return storage;
249
+
}
250
+
251
+
// Export singleton instance
252
+
export const storage = initializeStorage();
253
+
254
+
/**
255
+
* Get storage configuration summary for logging
256
+
*/
257
+
export function getStorageConfig() {
258
+
return {
259
+
cacheDir: CACHE_DIR,
260
+
hotCacheSize: `${(HOT_CACHE_SIZE / 1024 / 1024).toFixed(0)}MB`,
261
+
hotCacheCount: HOT_CACHE_COUNT,
262
+
warmCacheSize: `${(WARM_CACHE_SIZE / 1024 / 1024 / 1024).toFixed(1)}GB`,
263
+
warmEvictionPolicy: WARM_EVICTION_POLICY,
264
+
s3Bucket: S3_BUCKET,
265
+
s3Region: S3_REGION,
266
+
s3Endpoint: S3_ENDPOINT || '(default AWS S3)',
267
+
s3Prefix: S3_PREFIX,
268
+
metadataBucket: S3_METADATA_BUCKET || '(embedded in data bucket)',
269
+
};
270
+
}
+69
-152
apps/hosting-service/src/lib/utils.ts
+69
-152
apps/hosting-service/src/lib/utils.ts
···
4
4
import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings';
5
5
import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs';
6
6
import { writeFile, readFile, rename } from 'fs/promises';
7
+
import { Readable } from 'stream';
7
8
import { safeFetchJson, safeFetchBlob } from '@wisp/safe-fetch';
8
9
import { CID } from 'multiformats';
9
10
import { extractBlobCid } from '@wisp/atproto-utils';
10
11
import { sanitizePath, collectFileCidsFromEntries, countFilesInDirectory } from '@wisp/fs-utils';
11
12
import { shouldCompressMimeType } from '@wisp/atproto-utils/compression';
12
13
import { MAX_BLOB_SIZE, MAX_FILE_COUNT, MAX_SITE_SIZE } from '@wisp/constants';
14
+
import { storage } from './storage';
13
15
14
16
// Re-export shared utilities for local usage and tests
15
17
export { extractBlobCid, sanitizePath };
···
395
397
const existingMetadata = await getCacheMetadata(did, rkey);
396
398
const existingFileCids = existingMetadata?.fileCids || {};
397
399
398
-
// Use a temporary directory with timestamp to avoid collisions
399
-
const tempSuffix = `.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
400
-
const tempDir = `${CACHE_DIR}/${did}/${rkey}${tempSuffix}`;
401
-
const finalDir = `${CACHE_DIR}/${did}/${rkey}`;
402
-
403
-
try {
404
-
// Collect file CIDs from the new record (using expanded root)
405
-
const newFileCids: Record<string, string> = {};
406
-
collectFileCidsFromEntries(expandedRoot.entries, '', newFileCids);
400
+
// Collect file CIDs from the new record (using expanded root)
401
+
const newFileCids: Record<string, string> = {};
402
+
collectFileCidsFromEntries(expandedRoot.entries, '', newFileCids);
407
403
408
-
// Fetch site settings (optional)
409
-
const settings = await fetchSiteSettings(did, rkey);
404
+
// Fetch site settings (optional)
405
+
const settings = await fetchSiteSettings(did, rkey);
410
406
411
-
// Download/copy files to temporary directory (with incremental logic, using expanded root)
412
-
await cacheFiles(did, rkey, expandedRoot.entries, pdsEndpoint, '', tempSuffix, existingFileCids, finalDir);
413
-
await saveCacheMetadata(did, rkey, recordCid, tempSuffix, newFileCids, settings);
407
+
// Download files directly to tiered storage (with incremental logic)
408
+
await cacheFiles(did, rkey, expandedRoot.entries, pdsEndpoint, '', existingFileCids);
409
+
await saveCacheMetadata(did, rkey, recordCid, newFileCids, settings);
414
410
415
-
// Atomically replace old cache with new cache
416
-
// On POSIX systems (Linux/macOS), rename is atomic
417
-
if (existsSync(finalDir)) {
418
-
// Rename old directory to backup
419
-
const backupDir = `${finalDir}.old-${Date.now()}`;
420
-
await rename(finalDir, backupDir);
421
-
422
-
try {
423
-
// Rename new directory to final location
424
-
await rename(tempDir, finalDir);
425
-
426
-
// Clean up old backup
427
-
rmSync(backupDir, { recursive: true, force: true });
428
-
} catch (err) {
429
-
// If rename failed, restore backup
430
-
if (existsSync(backupDir) && !existsSync(finalDir)) {
431
-
await rename(backupDir, finalDir);
432
-
}
433
-
throw err;
434
-
}
435
-
} else {
436
-
// No existing cache, just rename temp to final
437
-
await rename(tempDir, finalDir);
438
-
}
439
-
440
-
console.log('Successfully cached site atomically', did, rkey);
441
-
} catch (err) {
442
-
// Clean up temp directory on failure
443
-
if (existsSync(tempDir)) {
444
-
rmSync(tempDir, { recursive: true, force: true });
445
-
}
446
-
throw err;
447
-
}
411
+
console.log('Successfully cached site', did, rkey);
448
412
}
449
413
450
414
···
454
418
entries: Entry[],
455
419
pdsEndpoint: string,
456
420
pathPrefix: string,
457
-
dirSuffix: string = '',
458
-
existingFileCids: Record<string, string> = {},
459
-
existingCacheDir?: string
421
+
existingFileCids: Record<string, string> = {}
460
422
): Promise<void> {
461
-
// Collect file tasks, separating unchanged files from new/changed files
423
+
// Collect file download tasks (skip unchanged files)
462
424
const downloadTasks: Array<() => Promise<void>> = [];
463
-
const copyTasks: Array<() => Promise<void>> = [];
464
425
465
426
function collectFileTasks(
466
427
entries: Entry[],
···
477
438
const cid = extractBlobCid(fileNode.blob);
478
439
479
440
// Check if file is unchanged (same CID as existing cache)
480
-
if (cid && existingFileCids[currentPath] === cid && existingCacheDir) {
481
-
// File unchanged - copy from existing cache instead of downloading
482
-
copyTasks.push(() => copyExistingFile(
483
-
did,
484
-
site,
485
-
currentPath,
486
-
dirSuffix,
487
-
existingCacheDir
488
-
));
441
+
if (cid && existingFileCids[currentPath] === cid) {
442
+
// File unchanged - skip download (already in tiered storage)
443
+
console.log(`Skipping unchanged file: ${currentPath}`);
489
444
} else {
490
445
// File new or changed - download it
491
446
downloadTasks.push(() => cacheFileBlob(
···
496
451
pdsEndpoint,
497
452
fileNode.encoding,
498
453
fileNode.mimeType,
499
-
fileNode.base64,
500
-
dirSuffix
454
+
fileNode.base64
501
455
));
502
456
}
503
457
}
···
506
460
507
461
collectFileTasks(entries, pathPrefix);
508
462
509
-
console.log(`[Incremental Update] Files to copy: ${copyTasks.length}, Files to download: ${downloadTasks.length}`);
463
+
console.log(`[Incremental Update] Files to download: ${downloadTasks.length}`);
510
464
511
-
// Copy unchanged files in parallel (fast local operations) - increased limit for better performance
512
-
const copyLimit = 50;
513
-
for (let i = 0; i < copyTasks.length; i += copyLimit) {
514
-
const batch = copyTasks.slice(i, i + copyLimit);
515
-
await Promise.all(batch.map(task => task()));
516
-
if (copyTasks.length > copyLimit) {
517
-
console.log(`[Cache Progress] Copied ${Math.min(i + copyLimit, copyTasks.length)}/${copyTasks.length} unchanged files`);
518
-
}
519
-
}
520
-
521
-
// Download new/changed files concurrently - increased from 3 to 20 for much better performance
465
+
// Download new/changed files concurrently
522
466
const downloadLimit = 20;
523
467
let successCount = 0;
524
468
let failureCount = 0;
···
547
491
}
548
492
}
549
493
550
-
/**
551
-
* Copy an unchanged file from existing cache to new cache location
552
-
*/
553
-
async function copyExistingFile(
554
-
did: string,
555
-
site: string,
556
-
filePath: string,
557
-
dirSuffix: string,
558
-
existingCacheDir: string
559
-
): Promise<void> {
560
-
const { copyFile } = await import('fs/promises');
561
-
562
-
const sourceFile = `${existingCacheDir}/${filePath}`;
563
-
const destFile = `${CACHE_DIR}/${did}/${site}${dirSuffix}/${filePath}`;
564
-
const destDir = destFile.substring(0, destFile.lastIndexOf('/'));
565
-
566
-
// Create destination directory if needed
567
-
if (destDir && !existsSync(destDir)) {
568
-
mkdirSync(destDir, { recursive: true });
569
-
}
570
-
571
-
try {
572
-
// Copy the file
573
-
await copyFile(sourceFile, destFile);
574
-
575
-
// Copy metadata file if it exists
576
-
const sourceMetaFile = `${sourceFile}.meta`;
577
-
const destMetaFile = `${destFile}.meta`;
578
-
if (existsSync(sourceMetaFile)) {
579
-
await copyFile(sourceMetaFile, destMetaFile);
580
-
}
581
-
} catch (err) {
582
-
console.error(`Failed to copy cached file ${filePath}, will attempt download:`, err);
583
-
throw err;
584
-
}
585
-
}
586
-
587
494
async function cacheFileBlob(
588
495
did: string,
589
496
site: string,
···
592
499
pdsEndpoint: string,
593
500
encoding?: 'gzip',
594
501
mimeType?: string,
595
-
base64?: boolean,
596
-
dirSuffix: string = ''
502
+
base64?: boolean
597
503
): Promise<void> {
598
504
const cid = extractBlobCid(blobRef);
599
505
if (!cid) {
···
616
522
content = Buffer.from(base64String, 'base64');
617
523
}
618
524
619
-
const cacheFile = `${CACHE_DIR}/${did}/${site}${dirSuffix}/${filePath}`;
620
-
const fileDir = cacheFile.substring(0, cacheFile.lastIndexOf('/'));
621
-
622
-
if (fileDir && !existsSync(fileDir)) {
623
-
mkdirSync(fileDir, { recursive: true });
624
-
}
625
-
626
525
// Use the shared function to determine if this should remain compressed
627
526
const shouldStayCompressed = shouldCompressMimeType(mimeType);
628
527
···
640
539
}
641
540
}
642
541
643
-
await writeFile(cacheFile, content);
542
+
// Write to tiered storage with metadata
543
+
const stream = Readable.from([content]);
544
+
const key = `${did}/${site}/${filePath}`;
545
+
546
+
// Build metadata object, only including defined values
547
+
const customMetadata: Record<string, string> = {};
548
+
if (encoding) customMetadata.encoding = encoding;
549
+
if (mimeType) customMetadata.mimeType = mimeType;
550
+
551
+
await storage.setStream(key, stream, {
552
+
size: content.length,
553
+
skipTiers: ['hot'], // Don't put in memory on ingest, only on access
554
+
metadata: customMetadata,
555
+
});
644
556
645
-
// Store metadata only if file is still compressed
557
+
// Log completion
646
558
if (encoding === 'gzip' && mimeType) {
647
-
const metaFile = `${cacheFile}.meta`;
648
-
await writeFile(metaFile, JSON.stringify({ encoding, mimeType }));
649
559
console.log('Cached file', filePath, content.length, 'bytes (gzipped,', mimeType + ')');
650
560
} else {
651
561
console.log('Cached file', filePath, content.length, 'bytes');
···
658
568
return `${CACHE_DIR}/${did}/${site}/${sanitizedPath}`;
659
569
}
660
570
661
-
export function isCached(did: string, site: string): boolean {
662
-
return existsSync(`${CACHE_DIR}/${did}/${site}`);
571
+
/**
572
+
* Check if a site exists in any tier of the cache (without checking metadata)
573
+
* This is a quick existence check - for actual retrieval, use storage.get()
574
+
*/
575
+
export async function isCached(did: string, site: string): Promise<boolean> {
576
+
// Check if any file exists for this site by checking for the index.html
577
+
// If index.html exists, the site is cached
578
+
const indexKey = `${did}/${site}/index.html`;
579
+
return await storage.exists(indexKey);
663
580
}
664
581
665
-
async function saveCacheMetadata(did: string, rkey: string, recordCid: string, dirSuffix: string = '', fileCids?: Record<string, string>, settings?: WispSettings | null): Promise<void> {
582
+
async function saveCacheMetadata(did: string, rkey: string, recordCid: string, fileCids?: Record<string, string>, settings?: WispSettings | null): Promise<void> {
666
583
const metadata: CacheMetadata = {
667
584
recordCid,
668
585
cachedAt: Date.now(),
···
672
589
settings: settings || undefined
673
590
};
674
591
675
-
const metadataPath = `${CACHE_DIR}/${did}/${rkey}${dirSuffix}/.metadata.json`;
676
-
const metadataDir = metadataPath.substring(0, metadataPath.lastIndexOf('/'));
677
-
678
-
if (!existsSync(metadataDir)) {
679
-
mkdirSync(metadataDir, { recursive: true });
680
-
}
681
-
682
-
await writeFile(metadataPath, JSON.stringify(metadata, null, 2));
592
+
// Store through tiered storage for persistence to S3/cold tier
593
+
const metadataKey = `${did}/${rkey}/.metadata.json`;
594
+
const metadataBytes = new TextEncoder().encode(JSON.stringify(metadata, null, 2));
595
+
await storage.set(metadataKey, metadataBytes);
683
596
}
684
597
685
598
async function getCacheMetadata(did: string, rkey: string): Promise<CacheMetadata | null> {
686
599
try {
687
-
const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`;
688
-
if (!existsSync(metadataPath)) return null;
600
+
// Retrieve metadata from tiered storage
601
+
const metadataKey = `${did}/${rkey}/.metadata.json`;
602
+
const data = await storage.get(metadataKey);
689
603
690
-
const content = await readFile(metadataPath, 'utf-8');
691
-
return JSON.parse(content) as CacheMetadata;
604
+
if (!data) return null;
605
+
606
+
// Deserialize from Uint8Array to JSON (storage uses identity serialization)
607
+
const jsonString = new TextDecoder().decode(data as Uint8Array);
608
+
return JSON.parse(jsonString) as CacheMetadata;
692
609
} catch (err) {
693
610
console.error('Failed to read cache metadata', err);
694
611
return null;
···
722
639
}
723
640
724
641
export async function updateCacheMetadataSettings(did: string, rkey: string, settings: WispSettings | null): Promise<void> {
725
-
const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`;
726
-
727
-
if (!existsSync(metadataPath)) {
728
-
console.warn('Metadata file does not exist, cannot update settings', { did, rkey });
729
-
return;
730
-
}
731
-
732
642
try {
733
-
// Read existing metadata
734
-
const content = await readFile(metadataPath, 'utf-8');
735
-
const metadata = JSON.parse(content) as CacheMetadata;
643
+
// Read existing metadata from tiered storage
644
+
const metadata = await getCacheMetadata(did, rkey);
645
+
646
+
if (!metadata) {
647
+
console.warn('Metadata does not exist, cannot update settings', { did, rkey });
648
+
return;
649
+
}
736
650
737
651
// Update settings field
738
652
// Store null explicitly to cache "no settings" state and avoid repeated fetches
739
653
metadata.settings = settings ?? null;
740
654
741
-
// Write back to disk
742
-
await writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf-8');
655
+
// Write back through tiered storage
656
+
// Convert to Uint8Array since storage is typed for binary data
657
+
const metadataKey = `${did}/${rkey}/.metadata.json`;
658
+
const metadataBytes = new TextEncoder().encode(JSON.stringify(metadata, null, 2));
659
+
await storage.set(metadataKey, metadataBytes);
743
660
console.log('Updated metadata settings', { did, rkey, hasSettings: !!settings });
744
661
} catch (err) {
745
662
console.error('Failed to update metadata settings', err);
+4
-1
apps/hosting-service/src/server.ts
+4
-1
apps/hosting-service/src/server.ts
···
80
80
return c.text('Invalid identifier', 400);
81
81
}
82
82
83
+
console.log(`[Server] sites.wisp.place request: identifier=${identifier}, site=${site}, filePath=${filePath}`);
84
+
83
85
// Check if site is currently being cached - return updating response early
84
86
if (isSiteBeingCached(did, site)) {
85
87
return siteUpdatingResponse();
···
93
95
94
96
// Serve with HTML path rewriting to handle absolute paths
95
97
const basePath = `/${identifier}/${site}/`;
98
+
console.log(`[Server] Serving with basePath: ${basePath}`);
96
99
const headers = extractHeaders(c.req.raw.headers);
97
100
return serveFromCacheWithRewrite(did, site, filePath, basePath, c.req.url, headers);
98
101
}
···
227
230
228
231
app.get('/__internal__/observability/cache', async (c) => {
229
232
const { getCacheStats } = await import('./lib/cache');
230
-
const stats = getCacheStats();
233
+
const stats = await getCacheStats();
231
234
return c.json({ cache: stats });
232
235
});
233
236
+59
backup.nix
+59
backup.nix
···
1
+
{
2
+
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
3
+
inputs.nci.url = "github:90-008/nix-cargo-integration";
4
+
inputs.nci.inputs.nixpkgs.follows = "nixpkgs";
5
+
inputs.parts.url = "github:hercules-ci/flake-parts";
6
+
inputs.parts.inputs.nixpkgs-lib.follows = "nixpkgs";
7
+
inputs.fenix = {
8
+
url = "github:nix-community/fenix";
9
+
inputs.nixpkgs.follows = "nixpkgs";
10
+
};
11
+
12
+
outputs = inputs @ {
13
+
parts,
14
+
nci,
15
+
...
16
+
}:
17
+
parts.lib.mkFlake {inherit inputs;} {
18
+
systems = ["x86_64-linux" "aarch64-darwin"];
19
+
imports = [
20
+
nci.flakeModule
21
+
./crates.nix
22
+
];
23
+
perSystem = {
24
+
pkgs,
25
+
config,
26
+
...
27
+
}: let
28
+
crateOutputs = config.nci.outputs."wisp-cli";
29
+
mkRenamedPackage = name: pkg: isWindows: pkgs.runCommand name {} ''
30
+
mkdir -p $out/bin
31
+
if [ -f ${pkg}/bin/wisp-cli.exe ]; then
32
+
cp ${pkg}/bin/wisp-cli.exe $out/bin/${name}
33
+
elif [ -f ${pkg}/bin/wisp-cli ]; then
34
+
cp ${pkg}/bin/wisp-cli $out/bin/${name}
35
+
else
36
+
echo "Error: Could not find wisp-cli binary in ${pkg}/bin/"
37
+
ls -la ${pkg}/bin/ || true
38
+
exit 1
39
+
fi
40
+
'';
41
+
in {
42
+
devShells.default = crateOutputs.devShell;
43
+
packages.default = crateOutputs.packages.release;
44
+
packages.wisp-cli-x86_64-linux = mkRenamedPackage "wisp-cli-x86_64-linux" crateOutputs.packages.release false;
45
+
packages.wisp-cli-aarch64-linux = mkRenamedPackage "wisp-cli-aarch64-linux" crateOutputs.allTargets."aarch64-unknown-linux-gnu".packages.release false;
46
+
packages.wisp-cli-x86_64-windows = mkRenamedPackage "wisp-cli-x86_64-windows.exe" crateOutputs.allTargets."x86_64-pc-windows-gnu".packages.release true;
47
+
packages.wisp-cli-aarch64-darwin = mkRenamedPackage "wisp-cli-aarch64-darwin" crateOutputs.allTargets."aarch64-apple-darwin".packages.release false;
48
+
packages.all = pkgs.symlinkJoin {
49
+
name = "wisp-cli-all";
50
+
paths = [
51
+
config.packages.wisp-cli-x86_64-linux
52
+
config.packages.wisp-cli-aarch64-linux
53
+
config.packages.wisp-cli-x86_64-windows
54
+
config.packages.wisp-cli-aarch64-darwin
55
+
];
56
+
};
57
+
};
58
+
};
59
+
}
+230
-5
bun.lock
+230
-5
bun.lock
···
36
36
"mime-types": "^2.1.35",
37
37
"multiformats": "^13.4.1",
38
38
"postgres": "^3.4.5",
39
+
"tiered-storage": "1.0.3",
39
40
},
40
41
"devDependencies": {
41
42
"@types/bun": "^1.3.1",
···
262
263
263
264
"@atproto/xrpc-server": ["@atproto/xrpc-server@0.9.6", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@atproto/ws-client": "^0.0.2", "@atproto/xrpc": "^0.7.5", "cbor-x": "^1.5.1", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "uint8arrays": "3.0.0", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-N/wPK0VEk8lZLkVsfG1wlkINQnBLO2fzWT+xclOjYl5lJwDi5xgiiyEQJAyZN49d6cmbsONu0SuOVw9pa5xLCw=="],
264
265
266
+
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
267
+
268
+
"@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="],
269
+
270
+
"@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="],
271
+
272
+
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
273
+
274
+
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
275
+
276
+
"@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
277
+
278
+
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
279
+
280
+
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.962.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/credential-provider-node": "3.962.0", "@aws-sdk/middleware-bucket-endpoint": "3.957.0", "@aws-sdk/middleware-expect-continue": "3.957.0", "@aws-sdk/middleware-flexible-checksums": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-location-constraint": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-sdk-s3": "3.957.0", "@aws-sdk/middleware-ssec": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/signature-v4-multi-region": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/eventstream-serde-browser": "^4.2.7", "@smithy/eventstream-serde-config-resolver": "^4.3.7", "@smithy/eventstream-serde-node": "^4.2.7", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-blob-browser": "^4.2.8", "@smithy/hash-node": "^4.2.7", "@smithy/hash-stream-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/md5-js": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-I2/1McBZCcM3PfM4ck8D6gnZR3K7+yl1fGkwTq/3ThEn9tdLjNwcdgTbPfxfX6LoecLrH9Ekoo+D9nmQ0T261w=="],
281
+
282
+
"@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.958.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6qNCIeaMzKzfqasy2nNRuYnMuaMebCcCPP4J2CVGkA8QYMbIVKPlkn9bpB20Vxe6H/r3jtCCLQaOJjVTx/6dXg=="],
283
+
284
+
"@aws-sdk/core": ["@aws-sdk/core@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrZgDnF1lQZv75a52nFWs6MExihJF2GZB6ETZRqr6jMwhrk2kbJPUtvgbifwcL7AYmVqHQDJBrR/MqkwwFCpiw=="],
285
+
286
+
"@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-qSwSfI+qBU9HDsd6/4fM9faCxYJx2yDuHtj+NVOQ6XYDWQzFab/hUdwuKZ77Pi6goLF1pBZhJ2azaC2w7LbnTA=="],
287
+
288
+
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-475mkhGaWCr+Z52fOOVb/q2VHuNvqEDixlYIkeaO6xJ6t9qR0wpLt4hOQaR6zR1wfZV0SlE7d8RErdYq/PByog=="],
289
+
290
+
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-8dS55QHRxXgJlHkEYaCGZIhieCs9NU1HU1BcqQ4RfUdSsfRdxxktqUKgCnBnOOn0oD3PPA8cQOCAVgIyRb3Rfw=="],
291
+
292
+
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.962.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/credential-provider-env": "3.957.0", "@aws-sdk/credential-provider-http": "3.957.0", "@aws-sdk/credential-provider-login": "3.962.0", "@aws-sdk/credential-provider-process": "3.957.0", "@aws-sdk/credential-provider-sso": "3.958.0", "@aws-sdk/credential-provider-web-identity": "3.958.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-h0kVnXLW2d3nxbcrR/Pfg3W/+YoCguasWz7/3nYzVqmdKarGrpJzaFdoZtLgvDSZ8VgWUC4lWOTcsDMV0UNqUQ=="],
293
+
294
+
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.962.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-kHYH6Av2UifG3mPkpPUNRh/PuX6adaAcpmsclJdHdxlixMCRdh8GNeEihq480DC0GmfqdpoSf1w2CLmLLPIS6w=="],
295
+
296
+
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.962.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.957.0", "@aws-sdk/credential-provider-http": "3.957.0", "@aws-sdk/credential-provider-ini": "3.962.0", "@aws-sdk/credential-provider-process": "3.957.0", "@aws-sdk/credential-provider-sso": "3.958.0", "@aws-sdk/credential-provider-web-identity": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-CS78NsWRxLa+nWqeWBEYMZTLacMFIXs1C5WJuM9kD05LLiWL32ksljoPsvNN24Bc7rCSQIIMx/U3KGvkDVZMVg=="],
297
+
298
+
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/KIz9kadwbeLy6SKvT79W81Y+hb/8LMDyeloA2zhouE28hmne+hLn0wNCQXAAupFFlYOAtZR2NTBs7HBAReJlg=="],
299
+
300
+
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.958.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.958.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/token-providers": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-CBYHJ5ufp8HC4q+o7IJejCUctJXWaksgpmoFpXerbjAso7/Fg7LLUu9inXVOxlHKLlvYekDXjIUBXDJS2WYdgg=="],
301
+
302
+
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.958.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-dgnvwjMq5Y66WozzUzxNkCFap+umHUtqMMKlr8z/vl9NYMLem/WUbWNpFFOVFWquXikc+ewtpBMR4KEDXfZ+KA=="],
303
+
304
+
"@aws-sdk/lib-storage": ["@aws-sdk/lib-storage@3.962.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/smithy-client": "^4.10.2", "buffer": "5.6.0", "events": "3.3.0", "stream-browserify": "3.0.0", "tslib": "^2.6.2" }, "peerDependencies": { "@aws-sdk/client-s3": "^3.962.0" } }, "sha512-Ai5gWRQkzsUMQ6NPoZZoiLXoQ6/yPRcR4oracIVjyWcu48TfBpsRgbqY/5zNOM55ag1wPX9TtJJGOhK3TNk45g=="],
305
+
306
+
"@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/util-arn-parser": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iczcn/QRIBSpvsdAS/rbzmoBpleX1JBjXvCynMbDceVLBIcVrwT1hXECrhtIC2cjh4HaLo9ClAbiOiWuqt+6MA=="],
307
+
308
+
"@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-AlbK3OeVNwZZil0wlClgeI/ISlOt/SPUxBsIns876IFaVu/Pj3DgImnYhpcJuFRek4r4XM51xzIaGQXM6GDHGg=="],
309
+
310
+
"@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.957.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/crc64-nvme": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iJpeVR5V8se1hl2pt+k8bF/e9JO4KWgPCMjg8BtRspNtKIUGy7j6msYvbDixaKZaF2Veg9+HoYcOhwnZumjXSA=="],
311
+
312
+
"@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA=="],
313
+
314
+
"@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-y8/W7TOQpmDJg/fPYlqAhwA4+I15LrS7TwgUEoxogtkD8gfur9wFMRLT8LCyc9o4NMEcAnK50hSb4+wB0qv6tQ=="],
315
+
316
+
"@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ=="],
317
+
318
+
"@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA=="],
319
+
320
+
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-arn-parser": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-5B2qY2nR2LYpxoQP0xUum5A1UNvH2JQpLHDH1nWFNF/XetV7ipFHksMxPNhtJJ6ARaWhQIDXfOUj0jcnkJxXUg=="],
321
+
322
+
"@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-qwkmrK0lizdjNt5qxl4tHYfASh8DFpHXM1iDVo+qHe+zuslfMqQEGRkzxS8tJq/I+8F0c6v3IKOveKJAfIvfqQ=="],
323
+
324
+
"@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-50vcHu96XakQnIvlKJ1UoltrFODjsq2KvtTgHiPFteUS884lQnK5VC/8xd1Msz/1ONpLMzdCVproCQqhDTtMPQ=="],
325
+
326
+
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.958.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-/KuCcS8b5TpQXkYOrPLYytrgxBhv81+5pChkOlhegbeHttjM69pyUpQVJqyfDM/A7wPLnDrzCAnk4zaAOkY0Nw=="],
327
+
328
+
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A=="],
329
+
330
+
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.957.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-t6UfP1xMUigMMzHcb7vaZcjv7dA2DQkk9C/OAP1dKyrE0vb4lFGDaTApi17GN6Km9zFxJthEMUbBc7DL0hq1Bg=="],
331
+
332
+
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.958.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-UCj7lQXODduD1myNJQkV+LYcGYJ9iiMggR8ow8Hva1g3A/Na5imNXzz6O67k7DAee0TYpy+gkNw+SizC6min8Q=="],
333
+
334
+
"@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="],
335
+
336
+
"@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.957.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Aj6m+AyrhWyg8YQ4LDPg2/gIfGHCEcoQdBt5DeSFogN5k9mmJPOJ+IAmNSWmWRjpOxEy6eY813RNDI6qS97M0g=="],
337
+
338
+
"@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw=="],
339
+
340
+
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.957.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nhmgKHnNV9K+i9daumaIz8JTLsIIML9PE/HUks5liyrjUzenjW/aHoc7WJ9/Td/gPZtayxFnXQSJRb/fDlBuJw=="],
341
+
342
+
"@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw=="],
343
+
344
+
"@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.957.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-ycbYCwqXk4gJGp0Oxkzf2KBeeGBdTxz559D41NJP8FlzSej1Gh7Rk40Zo6AyTfsNWkrl/kVi1t937OIzC5t+9Q=="],
345
+
346
+
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="],
347
+
348
+
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="],
349
+
265
350
"@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="],
266
351
267
352
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="],
···
544
629
545
630
"@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="],
546
631
632
+
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="],
633
+
634
+
"@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA=="],
635
+
636
+
"@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.1", "", { "dependencies": { "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ=="],
637
+
638
+
"@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="],
639
+
640
+
"@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="],
641
+
642
+
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA=="],
643
+
644
+
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="],
645
+
646
+
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ujzPk8seYoDBmABDE5YqlhQZAXLOrtxtJLrbhHMKjBoG5b4dK4i6/mEU+6/7yXIAkqOO8sJ6YxZl+h0QQ1IJ7g=="],
647
+
648
+
"@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-x7BtAiIPSaNaWuzm24Q/mtSkv+BrISO/fmheiJ39PKRNH3RmH2Hph/bUKSOBOBC9unqfIYDhKTHwpyZycLGPVQ=="],
649
+
650
+
"@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-roySCtHC5+pQq5lK4be1fZ/WR6s/AxnPaLfCODIPArtN2du8s5Ot4mKVK3pPtijL/L654ws592JHJ1PbZFF6+A=="],
651
+
652
+
"@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.7", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-QVD+g3+icFkThoy4r8wVFZMsIP08taHVKjE6Jpmz8h5CgX/kk6pTODq5cht0OMtcapUx+xrPzUTQdA+TmO0m1g=="],
653
+
654
+
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="],
655
+
656
+
"@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.8", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.0", "@smithy/chunked-blob-reader-native": "^4.2.1", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-07InZontqsM1ggTCPSRgI7d8DirqRrnpL7nIACT4PW0AWrgDiHhjGZzbAE5UtRSiU0NISGUYe7/rri9ZeWyDpw=="],
657
+
658
+
"@smithy/hash-node": ["@smithy/hash-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw=="],
659
+
660
+
"@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZQVoAwNYnFMIbd4DUc517HuwNelJUY6YOzwqrbcAgCnVn+79/OK7UjwA93SPpdTOpKDVkLIzavWm/Ck7SmnDPQ=="],
661
+
662
+
"@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="],
663
+
664
+
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
665
+
666
+
"@smithy/md5-js": ["@smithy/md5-js@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Wv6JcUxtOLTnxvNjDnAiATUsk8gvA6EeS8zzHig07dotpByYsLot+m0AaQEniUBjx97AC41MQR4hW0baraD1Xw=="],
667
+
668
+
"@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg=="],
669
+
670
+
"@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="],
671
+
672
+
"@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.17", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg=="],
673
+
674
+
"@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="],
675
+
676
+
"@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="],
677
+
678
+
"@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="],
679
+
680
+
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="],
681
+
682
+
"@smithy/property-provider": ["@smithy/property-provider@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA=="],
683
+
684
+
"@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="],
685
+
686
+
"@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="],
687
+
688
+
"@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="],
689
+
690
+
"@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="],
691
+
692
+
"@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="],
693
+
694
+
"@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="],
695
+
696
+
"@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="],
697
+
698
+
"@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="],
699
+
700
+
"@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="],
701
+
702
+
"@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
703
+
704
+
"@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
705
+
706
+
"@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
707
+
708
+
"@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
709
+
710
+
"@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
711
+
712
+
"@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.16", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ=="],
713
+
714
+
"@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.19", "", { "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA=="],
715
+
716
+
"@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="],
717
+
718
+
"@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
719
+
720
+
"@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="],
721
+
722
+
"@smithy/util-retry": ["@smithy/util-retry@4.2.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg=="],
723
+
724
+
"@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="],
725
+
726
+
"@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
727
+
728
+
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
729
+
730
+
"@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="],
731
+
732
+
"@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
733
+
547
734
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
548
735
549
736
"@tailwindcss/cli": ["@tailwindcss/cli@4.1.17", "", { "dependencies": { "@parcel/watcher": "^2.5.1", "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "enhanced-resolve": "^5.18.3", "mri": "^1.2.0", "picocolors": "^1.1.1", "tailwindcss": "4.1.17" }, "bin": { "tailwindcss": "dist/index.mjs" } }, "sha512-jUIxcyUNlCC2aNPnyPEWU/L2/ik3pB4fF3auKGXr8AvN3T3OFESVctFKOBoPZQaZJIeUpPn1uCLp0MRxuek8gg=="],
···
643
830
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
644
831
645
832
"body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="],
833
+
834
+
"bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="],
646
835
647
836
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
648
837
649
838
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
650
839
651
-
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
840
+
"buffer": ["buffer@5.6.0", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw=="],
652
841
653
842
"bun": ["bun@1.3.3", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.3.3", "@oven/bun-darwin-x64": "1.3.3", "@oven/bun-darwin-x64-baseline": "1.3.3", "@oven/bun-linux-aarch64": "1.3.3", "@oven/bun-linux-aarch64-musl": "1.3.3", "@oven/bun-linux-x64": "1.3.3", "@oven/bun-linux-x64-baseline": "1.3.3", "@oven/bun-linux-x64-musl": "1.3.3", "@oven/bun-linux-x64-musl-baseline": "1.3.3", "@oven/bun-windows-x64": "1.3.3", "@oven/bun-windows-x64-baseline": "1.3.3" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-2hJ4ocTZ634/Ptph4lysvO+LbbRZq8fzRvMwX0/CqaLBxrF2UB5D1LdMB8qGcdtCer4/VR9Bx5ORub0yn+yzmw=="],
654
843
···
750
939
751
940
"fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="],
752
941
942
+
"fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
943
+
753
944
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
754
945
755
946
"file-type": ["file-type@21.1.1", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-ifJXo8zUqbQ/bLbl9sFoqHNTNWbnPY1COImFfM6CCy7z+E+jC1eY9YfOKkx0fckIg+VljAy2/87T61fp0+eEkg=="],
···
960
1151
961
1152
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
962
1153
963
-
"readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
1154
+
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
964
1155
965
1156
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
966
1157
···
1004
1195
1005
1196
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
1006
1197
1198
+
"stream-browserify": ["stream-browserify@3.0.0", "", { "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" } }, "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA=="],
1199
+
1007
1200
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
1008
1201
1009
1202
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
1010
1203
1011
1204
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
1205
+
1206
+
"strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="],
1012
1207
1013
1208
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
1014
1209
···
1024
1219
1025
1220
"thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="],
1026
1221
1222
+
"tiered-storage": ["tiered-storage@1.0.3", "", { "dependencies": { "@aws-sdk/client-s3": "^3.500.0", "@aws-sdk/lib-storage": "^3.500.0", "hono": "^4.10.7", "mime-types": "^3.0.2", "tiny-lru": "^11.0.0" } }, "sha512-ntJCsWWYHSQWIDbObMfnJ8xw7cRSJCPzfbrjoY4hu0YIRizCthRWg8kCvJOgsgC+Upt259YHmfNwEr1wLv6Rxw=="],
1223
+
1224
+
"tiny-lru": ["tiny-lru@11.4.5", "", {}, "sha512-hkcz3FjNJfKXjV4mjQ1OrXSLAehg8Hw+cEZclOVT+5c/cWQWImQ9wolzTjth+dmmDe++p3bme3fTxz6Q4Etsqw=="],
1225
+
1027
1226
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
1028
1227
1029
1228
"tlds": ["tlds@1.261.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA=="],
···
1063
1262
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
1064
1263
1065
1264
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
1265
+
1266
+
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
1066
1267
1067
1268
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
1068
1269
···
1118
1319
1119
1320
"@atproto/sync/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1120
1321
1322
+
"@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
1323
+
1324
+
"@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
1325
+
1326
+
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
1327
+
1121
1328
"@ipld/dag-cbor/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1122
1329
1123
1330
"@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
···
1274
1481
1275
1482
"@wisp/main-app/@atproto/api": ["@atproto/api@0.17.7", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/lexicon": "^0.5.1", "@atproto/syntax": "^0.4.1", "@atproto/xrpc": "^0.7.5", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-V+OJBZq9chcrD21xk1bUa6oc5DSKfQj5DmUPf5rmZncqL1w9ZEbS38H5cMyqqdhfgo2LWeDRdZHD0rvNyJsIaw=="],
1276
1483
1484
+
"@wisp/observability/bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
1485
+
1277
1486
"express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
1278
1487
1279
1488
"iron-session/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
···
1282
1491
1283
1492
"node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
1284
1493
1494
+
"pino-abstract-transport/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
1495
+
1285
1496
"require-in-the-middle/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
1286
1497
1287
1498
"send/http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
···
1291
1502
"send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
1292
1503
1293
1504
"serve-static/send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="],
1505
+
1506
+
"tiered-storage/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
1294
1507
1295
1508
"tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
1296
1509
···
1302
1515
1303
1516
"wisp-hosting-service/@atproto/api": ["@atproto/api@0.17.7", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/lexicon": "^0.5.1", "@atproto/syntax": "^0.4.1", "@atproto/xrpc": "^0.7.5", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-V+OJBZq9chcrD21xk1bUa6oc5DSKfQj5DmUPf5rmZncqL1w9ZEbS38H5cMyqqdhfgo2LWeDRdZHD0rvNyJsIaw=="],
1304
1517
1305
-
"wisp-hosting-service/@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="],
1518
+
"@atproto/sync/@atproto/xrpc-server/@atproto/ws-client": ["@atproto/ws-client@0.0.3", "", { "dependencies": { "@atproto/common": "^0.5.0", "ws": "^8.12.0" } }, "sha512-eKqkTWBk6zuMY+6gs02eT7mS8Btewm8/qaL/Dp00NDCqpNC+U59MWvQsOWT3xkNGfd9Eip+V6VI4oyPvAfsfTA=="],
1306
1519
1307
-
"@atproto/sync/@atproto/xrpc-server/@atproto/ws-client": ["@atproto/ws-client@0.0.3", "", { "dependencies": { "@atproto/common": "^0.5.0", "ws": "^8.12.0" } }, "sha512-eKqkTWBk6zuMY+6gs02eT7mS8Btewm8/qaL/Dp00NDCqpNC+U59MWvQsOWT3xkNGfd9Eip+V6VI4oyPvAfsfTA=="],
1520
+
"@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
1521
+
1522
+
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
1523
+
1524
+
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
1308
1525
1309
1526
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
1310
1527
···
1342
1559
1343
1560
"@wisp/main-app/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1344
1561
1562
+
"pino-abstract-transport/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
1563
+
1345
1564
"require-in-the-middle/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
1346
1565
1347
1566
"serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
···
1351
1570
"serve-static/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
1352
1571
1353
1572
"serve-static/send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
1573
+
1574
+
"tiered-storage/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
1354
1575
1355
1576
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA=="],
1356
1577
···
1406
1627
1407
1628
"wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1408
1629
1409
-
"wisp-hosting-service/@types/bun/bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="],
1630
+
"@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
1631
+
1632
+
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
1633
+
1634
+
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
1410
1635
}
1411
1636
}
+277
-516
cli/Cargo.lock
+277
-516
cli/Cargo.lock
···
3
3
version = 4
4
4
5
5
[[package]]
6
-
name = "abnf"
7
-
version = "0.13.0"
8
-
source = "registry+https://github.com/rust-lang/crates.io-index"
9
-
checksum = "087113bd50d9adce24850eed5d0476c7d199d532fce8fab5173650331e09033a"
10
-
dependencies = [
11
-
"abnf-core",
12
-
"nom",
13
-
]
14
-
15
-
[[package]]
16
-
name = "abnf-core"
17
-
version = "0.5.0"
18
-
source = "registry+https://github.com/rust-lang/crates.io-index"
19
-
checksum = "c44e09c43ae1c368fb91a03a566472d0087c26cf7e1b9e8e289c14ede681dd7d"
20
-
dependencies = [
21
-
"nom",
22
-
]
23
-
24
-
[[package]]
25
6
name = "addr2line"
26
7
version = "0.25.1"
27
8
source = "registry+https://github.com/rust-lang/crates.io-index"
···
71
52
dependencies = [
72
53
"alloc-no-stdlib",
73
54
]
55
+
56
+
[[package]]
57
+
name = "allocator-api2"
58
+
version = "0.2.21"
59
+
source = "registry+https://github.com/rust-lang/crates.io-index"
60
+
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
74
61
75
62
[[package]]
76
63
name = "android_system_properties"
···
139
126
140
127
[[package]]
141
128
name = "async-compression"
142
-
version = "0.4.34"
129
+
version = "0.4.36"
143
130
source = "registry+https://github.com/rust-lang/crates.io-index"
144
-
checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473"
131
+
checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37"
145
132
dependencies = [
146
133
"compression-codecs",
147
134
"compression-core",
···
158
145
dependencies = [
159
146
"proc-macro2",
160
147
"quote",
161
-
"syn 2.0.111",
148
+
"syn 2.0.113",
162
149
]
163
150
164
151
[[package]]
···
184
171
185
172
[[package]]
186
173
name = "axum"
187
-
version = "0.8.7"
174
+
version = "0.8.8"
188
175
source = "registry+https://github.com/rust-lang/crates.io-index"
189
-
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
176
+
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
190
177
dependencies = [
191
178
"axum-core",
192
179
"bytes",
···
217
204
218
205
[[package]]
219
206
name = "axum-core"
220
-
version = "0.5.5"
207
+
version = "0.5.6"
221
208
source = "registry+https://github.com/rust-lang/crates.io-index"
222
-
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
209
+
checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
223
210
dependencies = [
224
211
"bytes",
225
212
"futures-core",
···
246
233
"miniz_oxide",
247
234
"object",
248
235
"rustc-demangle",
249
-
"windows-link 0.2.1",
236
+
"windows-link",
250
237
]
251
238
252
239
[[package]]
···
294
281
295
282
[[package]]
296
283
name = "base64ct"
297
-
version = "1.8.0"
284
+
version = "1.8.2"
298
285
source = "registry+https://github.com/rust-lang/crates.io-index"
299
-
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
286
+
checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82"
300
287
301
288
[[package]]
302
289
name = "bitflags"
···
335
322
"proc-macro2",
336
323
"quote",
337
324
"rustversion",
338
-
"syn 2.0.111",
325
+
"syn 2.0.113",
339
326
]
340
327
341
328
[[package]]
342
329
name = "borsh"
343
-
version = "1.5.7"
330
+
version = "1.6.0"
344
331
source = "registry+https://github.com/rust-lang/crates.io-index"
345
-
checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
332
+
checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f"
346
333
dependencies = [
347
334
"cfg_aliases",
348
335
]
···
376
363
dependencies = [
377
364
"memchr",
378
365
"serde",
379
-
]
380
-
381
-
[[package]]
382
-
name = "btree-range-map"
383
-
version = "0.7.2"
384
-
source = "registry+https://github.com/rust-lang/crates.io-index"
385
-
checksum = "1be5c9672446d3800bcbcaabaeba121fe22f1fb25700c4562b22faf76d377c33"
386
-
dependencies = [
387
-
"btree-slab",
388
-
"cc-traits",
389
-
"range-traits",
390
-
"serde",
391
-
"slab",
392
-
]
393
-
394
-
[[package]]
395
-
name = "btree-slab"
396
-
version = "0.6.1"
397
-
source = "registry+https://github.com/rust-lang/crates.io-index"
398
-
checksum = "7a2b56d3029f075c4fa892428a098425b86cef5c89ae54073137ece416aef13c"
399
-
dependencies = [
400
-
"cc-traits",
401
-
"slab",
402
-
"smallvec",
403
366
]
404
367
405
368
[[package]]
···
414
377
415
378
[[package]]
416
379
name = "bumpalo"
417
-
version = "3.19.0"
380
+
version = "3.19.1"
418
381
source = "registry+https://github.com/rust-lang/crates.io-index"
419
-
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
382
+
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
420
383
421
384
[[package]]
422
385
name = "byteorder"
···
444
407
445
408
[[package]]
446
409
name = "cc"
447
-
version = "1.2.47"
410
+
version = "1.2.51"
448
411
source = "registry+https://github.com/rust-lang/crates.io-index"
449
-
checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
412
+
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
450
413
dependencies = [
451
414
"find-msvc-tools",
452
415
"shlex",
453
416
]
454
417
455
418
[[package]]
456
-
name = "cc-traits"
457
-
version = "2.0.0"
458
-
source = "registry+https://github.com/rust-lang/crates.io-index"
459
-
checksum = "060303ef31ef4a522737e1b1ab68c67916f2a787bb2f4f54f383279adba962b5"
460
-
dependencies = [
461
-
"slab",
462
-
]
463
-
464
-
[[package]]
465
419
name = "cesu8"
466
420
version = "1.1.0"
467
421
source = "registry+https://github.com/rust-lang/crates.io-index"
···
490
444
"num-traits",
491
445
"serde",
492
446
"wasm-bindgen",
493
-
"windows-link 0.2.1",
447
+
"windows-link",
494
448
]
495
449
496
450
[[package]]
···
542
496
543
497
[[package]]
544
498
name = "clap"
545
-
version = "4.5.53"
499
+
version = "4.5.54"
546
500
source = "registry+https://github.com/rust-lang/crates.io-index"
547
-
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
501
+
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
548
502
dependencies = [
549
503
"clap_builder",
550
504
"clap_derive",
···
552
506
553
507
[[package]]
554
508
name = "clap_builder"
555
-
version = "4.5.53"
509
+
version = "4.5.54"
556
510
source = "registry+https://github.com/rust-lang/crates.io-index"
557
-
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
511
+
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
558
512
dependencies = [
559
513
"anstream",
560
514
"anstyle",
···
571
525
"heck 0.5.0",
572
526
"proc-macro2",
573
527
"quote",
574
-
"syn 2.0.111",
528
+
"syn 2.0.113",
575
529
]
576
530
577
531
[[package]]
···
607
561
608
562
[[package]]
609
563
name = "compression-codecs"
610
-
version = "0.4.33"
564
+
version = "0.4.35"
611
565
source = "registry+https://github.com/rust-lang/crates.io-index"
612
-
checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad"
566
+
checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2"
613
567
dependencies = [
614
568
"compression-core",
615
569
"flate2",
···
799
753
"proc-macro2",
800
754
"quote",
801
755
"strsim",
802
-
"syn 2.0.111",
756
+
"syn 2.0.113",
803
757
]
804
758
805
759
[[package]]
···
810
764
dependencies = [
811
765
"darling_core",
812
766
"quote",
813
-
"syn 2.0.111",
767
+
"syn 2.0.113",
814
768
]
815
769
816
770
[[package]]
···
850
804
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
851
805
dependencies = [
852
806
"data-encoding",
853
-
"syn 2.0.111",
807
+
"syn 2.0.113",
854
808
]
855
809
856
810
[[package]]
···
881
835
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
882
836
dependencies = [
883
837
"powerfmt",
884
-
"serde_core",
885
838
]
886
839
887
840
[[package]]
···
901
854
dependencies = [
902
855
"proc-macro2",
903
856
"quote",
904
-
"syn 2.0.111",
857
+
"syn 2.0.113",
905
858
"unicode-xid",
906
859
]
907
860
···
952
905
dependencies = [
953
906
"proc-macro2",
954
907
"quote",
955
-
"syn 2.0.111",
908
+
"syn 2.0.113",
956
909
]
957
-
958
-
[[package]]
959
-
name = "dyn-clone"
960
-
version = "1.0.20"
961
-
source = "registry+https://github.com/rust-lang/crates.io-index"
962
-
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
963
910
964
911
[[package]]
965
912
name = "ecdsa"
···
1031
978
"heck 0.5.0",
1032
979
"proc-macro2",
1033
980
"quote",
1034
-
"syn 2.0.111",
981
+
"syn 2.0.113",
1035
982
]
1036
983
1037
984
[[package]]
···
1080
1027
1081
1028
[[package]]
1082
1029
name = "find-msvc-tools"
1083
-
version = "0.1.5"
1030
+
version = "0.1.6"
1084
1031
source = "registry+https://github.com/rust-lang/crates.io-index"
1085
-
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
1032
+
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
1086
1033
1087
1034
[[package]]
1088
1035
name = "flate2"
···
1099
1046
version = "1.0.7"
1100
1047
source = "registry+https://github.com/rust-lang/crates.io-index"
1101
1048
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
1049
+
1050
+
[[package]]
1051
+
name = "foldhash"
1052
+
version = "0.1.5"
1053
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1054
+
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1102
1055
1103
1056
[[package]]
1104
1057
name = "form_urlencoded"
···
1201
1154
dependencies = [
1202
1155
"proc-macro2",
1203
1156
"quote",
1204
-
"syn 2.0.111",
1157
+
"syn 2.0.113",
1205
1158
]
1206
1159
1207
1160
[[package]]
···
1236
1189
1237
1190
[[package]]
1238
1191
name = "generator"
1239
-
version = "0.8.7"
1192
+
version = "0.8.8"
1240
1193
source = "registry+https://github.com/rust-lang/crates.io-index"
1241
-
checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2"
1194
+
checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9"
1242
1195
dependencies = [
1243
1196
"cc",
1244
1197
"cfg-if",
1245
1198
"libc",
1246
1199
"log",
1247
1200
"rustversion",
1248
-
"windows",
1201
+
"windows-link",
1202
+
"windows-result",
1249
1203
]
1250
1204
1251
1205
[[package]]
···
1355
1309
1356
1310
[[package]]
1357
1311
name = "h2"
1358
-
version = "0.4.12"
1312
+
version = "0.4.13"
1359
1313
source = "registry+https://github.com/rust-lang/crates.io-index"
1360
-
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
1314
+
checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
1361
1315
dependencies = [
1362
1316
"atomic-waker",
1363
1317
"bytes",
···
1365
1319
"futures-core",
1366
1320
"futures-sink",
1367
1321
"http",
1368
-
"indexmap 2.12.1",
1322
+
"indexmap",
1369
1323
"slab",
1370
1324
"tokio",
1371
1325
"tokio-util",
···
1394
1348
1395
1349
[[package]]
1396
1350
name = "hashbrown"
1397
-
version = "0.12.3"
1351
+
version = "0.14.5"
1398
1352
source = "registry+https://github.com/rust-lang/crates.io-index"
1399
-
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
1353
+
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
1400
1354
1401
1355
[[package]]
1402
1356
name = "hashbrown"
1403
-
version = "0.14.5"
1357
+
version = "0.15.5"
1404
1358
source = "registry+https://github.com/rust-lang/crates.io-index"
1405
-
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
1359
+
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
1360
+
dependencies = [
1361
+
"allocator-api2",
1362
+
"equivalent",
1363
+
"foldhash",
1364
+
]
1406
1365
1407
1366
[[package]]
1408
1367
name = "hashbrown"
···
1449
1408
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
1450
1409
1451
1410
[[package]]
1452
-
name = "hex_fmt"
1453
-
version = "0.3.0"
1454
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1455
-
checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f"
1456
-
1457
-
[[package]]
1458
1411
name = "hickory-proto"
1459
1412
version = "0.24.4"
1460
1413
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1519
1472
"markup5ever",
1520
1473
"proc-macro2",
1521
1474
"quote",
1522
-
"syn 2.0.111",
1475
+
"syn 2.0.113",
1523
1476
]
1524
1477
1525
1478
[[package]]
···
1615
1568
1616
1569
[[package]]
1617
1570
name = "hyper-util"
1618
-
version = "0.1.18"
1571
+
version = "0.1.19"
1619
1572
source = "registry+https://github.com/rust-lang/crates.io-index"
1620
-
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
1573
+
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
1621
1574
dependencies = [
1622
1575
"base64 0.22.1",
1623
1576
"bytes",
···
1651
1604
"js-sys",
1652
1605
"log",
1653
1606
"wasm-bindgen",
1654
-
"windows-core 0.62.2",
1607
+
"windows-core",
1655
1608
]
1656
1609
1657
1610
[[package]]
···
1711
1664
1712
1665
[[package]]
1713
1666
name = "icu_properties"
1714
-
version = "2.1.1"
1667
+
version = "2.1.2"
1715
1668
source = "registry+https://github.com/rust-lang/crates.io-index"
1716
-
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99"
1669
+
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
1717
1670
dependencies = [
1718
1671
"icu_collections",
1719
1672
"icu_locale_core",
···
1725
1678
1726
1679
[[package]]
1727
1680
name = "icu_properties_data"
1728
-
version = "2.1.1"
1681
+
version = "2.1.2"
1729
1682
source = "registry+https://github.com/rust-lang/crates.io-index"
1730
-
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899"
1683
+
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
1731
1684
1732
1685
[[package]]
1733
1686
name = "icu_provider"
···
1789
1742
1790
1743
[[package]]
1791
1744
name = "indexmap"
1792
-
version = "1.9.3"
1793
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1794
-
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
1795
-
dependencies = [
1796
-
"autocfg",
1797
-
"hashbrown 0.12.3",
1798
-
"serde",
1799
-
]
1800
-
1801
-
[[package]]
1802
-
name = "indexmap"
1803
1745
version = "2.12.1"
1804
1746
source = "registry+https://github.com/rust-lang/crates.io-index"
1805
1747
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
1806
1748
dependencies = [
1807
1749
"equivalent",
1808
1750
"hashbrown 0.16.1",
1809
-
"serde",
1810
-
"serde_core",
1811
1751
]
1812
1752
1813
1753
[[package]]
···
1821
1761
"portable-atomic",
1822
1762
"unicode-width 0.2.2",
1823
1763
"web-time",
1824
-
]
1825
-
1826
-
[[package]]
1827
-
name = "indoc"
1828
-
version = "2.0.7"
1829
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1830
-
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
1831
-
dependencies = [
1832
-
"rustversion",
1833
1764
]
1834
1765
1835
1766
[[package]]
···
1872
1803
1873
1804
[[package]]
1874
1805
name = "iri-string"
1875
-
version = "0.7.9"
1806
+
version = "0.7.10"
1876
1807
source = "registry+https://github.com/rust-lang/crates.io-index"
1877
-
checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
1808
+
checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
1878
1809
dependencies = [
1879
1810
"memchr",
1880
1811
"serde",
···
1894
1825
1895
1826
[[package]]
1896
1827
name = "itoa"
1897
-
version = "1.0.15"
1828
+
version = "1.0.17"
1898
1829
source = "registry+https://github.com/rust-lang/crates.io-index"
1899
-
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1830
+
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
1900
1831
1901
1832
[[package]]
1902
1833
name = "jacquard"
1903
-
version = "0.9.4"
1904
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1834
+
version = "0.9.5"
1835
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1905
1836
dependencies = [
1906
1837
"bytes",
1907
1838
"getrandom 0.2.16",
···
1917
1848
"regex",
1918
1849
"regex-lite",
1919
1850
"reqwest",
1920
-
"ring",
1921
1851
"serde",
1922
1852
"serde_html_form",
1923
1853
"serde_json",
···
1931
1861
1932
1862
[[package]]
1933
1863
name = "jacquard-api"
1934
-
version = "0.9.2"
1935
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1864
+
version = "0.9.5"
1865
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1936
1866
dependencies = [
1937
1867
"bon",
1938
1868
"bytes",
···
1950
1880
1951
1881
[[package]]
1952
1882
name = "jacquard-common"
1953
-
version = "0.9.2"
1954
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1883
+
version = "0.9.5"
1884
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1955
1885
dependencies = [
1956
1886
"base64 0.22.1",
1957
1887
"bon",
1958
1888
"bytes",
1959
1889
"chrono",
1960
1890
"ciborium",
1891
+
"ciborium-io",
1961
1892
"cid",
1962
1893
"futures",
1963
1894
"getrandom 0.2.16",
1964
1895
"getrandom 0.3.4",
1896
+
"hashbrown 0.15.5",
1965
1897
"http",
1966
1898
"ipld-core",
1967
1899
"k256",
1968
-
"langtag",
1900
+
"maitake-sync",
1969
1901
"miette",
1970
1902
"multibase",
1971
1903
"multihash",
1972
1904
"n0-future 0.1.3",
1973
1905
"ouroboros",
1906
+
"oxilangtag",
1974
1907
"p256",
1975
1908
"postcard",
1976
1909
"rand 0.9.2",
1977
1910
"regex",
1911
+
"regex-automata",
1978
1912
"regex-lite",
1979
1913
"reqwest",
1980
-
"ring",
1981
1914
"serde",
1982
1915
"serde_bytes",
1983
1916
"serde_html_form",
···
1985
1918
"serde_json",
1986
1919
"signature",
1987
1920
"smol_str",
1921
+
"spin 0.10.0",
1988
1922
"thiserror 2.0.17",
1989
1923
"tokio",
1990
1924
"tokio-tungstenite-wasm",
···
1995
1929
1996
1930
[[package]]
1997
1931
name = "jacquard-derive"
1998
-
version = "0.9.4"
1999
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1932
+
version = "0.9.5"
1933
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
2000
1934
dependencies = [
2001
1935
"heck 0.5.0",
2002
1936
"jacquard-lexicon",
2003
1937
"proc-macro2",
2004
1938
"quote",
2005
-
"syn 2.0.111",
1939
+
"syn 2.0.113",
2006
1940
]
2007
1941
2008
1942
[[package]]
2009
1943
name = "jacquard-identity"
2010
-
version = "0.9.2"
2011
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1944
+
version = "0.9.5"
1945
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
2012
1946
dependencies = [
2013
1947
"bon",
2014
1948
"bytes",
···
2018
1952
"jacquard-common",
2019
1953
"jacquard-lexicon",
2020
1954
"miette",
2021
-
"mini-moka",
1955
+
"mini-moka-wasm",
2022
1956
"n0-future 0.1.3",
2023
1957
"percent-encoding",
2024
1958
"reqwest",
2025
-
"ring",
2026
1959
"serde",
2027
1960
"serde_html_form",
2028
1961
"serde_json",
···
2035
1968
2036
1969
[[package]]
2037
1970
name = "jacquard-lexicon"
2038
-
version = "0.9.2"
2039
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1971
+
version = "0.9.5"
1972
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
2040
1973
dependencies = [
2041
1974
"cid",
2042
1975
"dashmap",
···
2054
1987
"serde_repr",
2055
1988
"serde_with",
2056
1989
"sha2",
2057
-
"syn 2.0.111",
1990
+
"syn 2.0.113",
2058
1991
"thiserror 2.0.17",
2059
1992
"unicode-segmentation",
2060
1993
]
2061
1994
2062
1995
[[package]]
2063
1996
name = "jacquard-oauth"
2064
-
version = "0.9.2"
2065
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
1997
+
version = "0.9.6"
1998
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
2066
1999
dependencies = [
2067
2000
"base64 0.22.1",
2068
2001
"bytes",
···
2077
2010
"miette",
2078
2011
"p256",
2079
2012
"rand 0.8.5",
2080
-
"ring",
2081
2013
"rouille",
2082
2014
"serde",
2083
2015
"serde_html_form",
···
2151
2083
2152
2084
[[package]]
2153
2085
name = "js-sys"
2154
-
version = "0.3.82"
2086
+
version = "0.3.83"
2155
2087
source = "registry+https://github.com/rust-lang/crates.io-index"
2156
-
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
2088
+
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
2157
2089
dependencies = [
2158
2090
"once_cell",
2159
2091
"wasm-bindgen",
···
2172
2104
]
2173
2105
2174
2106
[[package]]
2175
-
name = "langtag"
2176
-
version = "0.4.0"
2177
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2178
-
checksum = "9ecb4c689a30e48ebeaa14237f34037e300dd072e6ad21a9ec72e810ff3c6600"
2179
-
dependencies = [
2180
-
"serde",
2181
-
"static-regular-grammar",
2182
-
"thiserror 1.0.69",
2183
-
]
2184
-
2185
-
[[package]]
2186
2107
name = "lazy_static"
2187
2108
version = "1.5.0"
2188
2109
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2193
2114
2194
2115
[[package]]
2195
2116
name = "libc"
2196
-
version = "0.2.177"
2117
+
version = "0.2.179"
2197
2118
source = "registry+https://github.com/rust-lang/crates.io-index"
2198
-
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
2119
+
checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
2199
2120
2200
2121
[[package]]
2201
2122
name = "libm"
···
2205
2126
2206
2127
[[package]]
2207
2128
name = "libredox"
2208
-
version = "0.1.10"
2129
+
version = "0.1.12"
2209
2130
source = "registry+https://github.com/rust-lang/crates.io-index"
2210
-
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
2131
+
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
2211
2132
dependencies = [
2212
2133
"bitflags",
2213
2134
"libc",
2214
-
"redox_syscall",
2135
+
"redox_syscall 0.7.0",
2215
2136
]
2216
2137
2217
2138
[[package]]
···
2243
2164
2244
2165
[[package]]
2245
2166
name = "log"
2246
-
version = "0.4.28"
2167
+
version = "0.4.29"
2247
2168
source = "registry+https://github.com/rust-lang/crates.io-index"
2248
-
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
2169
+
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2249
2170
2250
2171
[[package]]
2251
2172
name = "loom"
···
2282
2203
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
2283
2204
2284
2205
[[package]]
2206
+
name = "maitake-sync"
2207
+
version = "0.1.2"
2208
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2209
+
checksum = "6816ab14147f80234c675b80ed6dc4f440d8a1cefc158e766067aedb84c0bcd5"
2210
+
dependencies = [
2211
+
"cordyceps",
2212
+
"loom",
2213
+
"mycelium-bitfield",
2214
+
"pin-project",
2215
+
"portable-atomic",
2216
+
]
2217
+
2218
+
[[package]]
2285
2219
name = "markup5ever"
2286
2220
version = "0.12.1"
2287
2221
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2366
2300
dependencies = [
2367
2301
"proc-macro2",
2368
2302
"quote",
2369
-
"syn 2.0.111",
2303
+
"syn 2.0.113",
2370
2304
]
2371
2305
2372
2306
[[package]]
···
2386
2320
]
2387
2321
2388
2322
[[package]]
2389
-
name = "mini-moka"
2323
+
name = "mini-moka-wasm"
2390
2324
version = "0.10.99"
2391
-
source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df"
2325
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
2392
2326
dependencies = [
2393
2327
"crossbeam-channel",
2394
2328
"crossbeam-utils",
···
2400
2334
]
2401
2335
2402
2336
[[package]]
2403
-
name = "minimal-lexical"
2404
-
version = "0.2.1"
2405
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2406
-
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
2407
-
2408
-
[[package]]
2409
2337
name = "miniz_oxide"
2410
2338
version = "0.8.9"
2411
2339
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2417
2345
2418
2346
[[package]]
2419
2347
name = "mio"
2420
-
version = "1.1.0"
2348
+
version = "1.1.1"
2421
2349
source = "registry+https://github.com/rust-lang/crates.io-index"
2422
-
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
2350
+
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
2423
2351
dependencies = [
2424
2352
"libc",
2425
2353
"wasi",
···
2468
2396
]
2469
2397
2470
2398
[[package]]
2399
+
name = "mycelium-bitfield"
2400
+
version = "0.1.5"
2401
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2402
+
checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc"
2403
+
2404
+
[[package]]
2471
2405
name = "n0-future"
2472
2406
version = "0.1.3"
2473
2407
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2520
2454
version = "1.0.6"
2521
2455
source = "registry+https://github.com/rust-lang/crates.io-index"
2522
2456
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
2523
-
2524
-
[[package]]
2525
-
name = "nom"
2526
-
version = "7.1.3"
2527
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2528
-
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
2529
-
dependencies = [
2530
-
"memchr",
2531
-
"minimal-lexical",
2532
-
]
2533
2457
2534
2458
[[package]]
2535
2459
name = "nu-ansi-term"
···
2665
2589
2666
2590
[[package]]
2667
2591
name = "openssl-probe"
2668
-
version = "0.1.6"
2592
+
version = "0.2.0"
2669
2593
source = "registry+https://github.com/rust-lang/crates.io-index"
2670
-
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
2594
+
checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391"
2671
2595
2672
2596
[[package]]
2673
2597
name = "option-ext"
···
2696
2620
"proc-macro2",
2697
2621
"proc-macro2-diagnostics",
2698
2622
"quote",
2699
-
"syn 2.0.111",
2623
+
"syn 2.0.113",
2700
2624
]
2701
2625
2702
2626
[[package]]
···
2706
2630
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
2707
2631
2708
2632
[[package]]
2633
+
name = "oxilangtag"
2634
+
version = "0.1.5"
2635
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2636
+
checksum = "23f3f87617a86af77fa3691e6350483e7154c2ead9f1261b75130e21ca0f8acb"
2637
+
dependencies = [
2638
+
"serde",
2639
+
]
2640
+
2641
+
[[package]]
2709
2642
name = "p256"
2710
2643
version = "0.13.2"
2711
2644
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2751
2684
dependencies = [
2752
2685
"cfg-if",
2753
2686
"libc",
2754
-
"redox_syscall",
2687
+
"redox_syscall 0.5.18",
2755
2688
"smallvec",
2756
-
"windows-link 0.2.1",
2689
+
"windows-link",
2757
2690
]
2758
2691
2759
2692
[[package]]
···
2826
2759
dependencies = [
2827
2760
"proc-macro2",
2828
2761
"quote",
2829
-
"syn 2.0.111",
2762
+
"syn 2.0.113",
2830
2763
]
2831
2764
2832
2765
[[package]]
···
2864
2797
2865
2798
[[package]]
2866
2799
name = "portable-atomic"
2867
-
version = "1.11.1"
2800
+
version = "1.13.0"
2868
2801
source = "registry+https://github.com/rust-lang/crates.io-index"
2869
-
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
2802
+
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
2870
2803
2871
2804
[[package]]
2872
2805
name = "postcard"
···
2918
2851
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
2919
2852
dependencies = [
2920
2853
"proc-macro2",
2921
-
"syn 2.0.111",
2854
+
"syn 2.0.113",
2922
2855
]
2923
2856
2924
2857
[[package]]
···
2931
2864
]
2932
2865
2933
2866
[[package]]
2934
-
name = "proc-macro-error"
2935
-
version = "1.0.4"
2936
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2937
-
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
2938
-
dependencies = [
2939
-
"proc-macro-error-attr",
2940
-
"proc-macro2",
2941
-
"quote",
2942
-
"syn 1.0.109",
2943
-
"version_check",
2944
-
]
2945
-
2946
-
[[package]]
2947
-
name = "proc-macro-error-attr"
2948
-
version = "1.0.4"
2949
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2950
-
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
2951
-
dependencies = [
2952
-
"proc-macro2",
2953
-
"quote",
2954
-
"version_check",
2955
-
]
2956
-
2957
-
[[package]]
2958
2867
name = "proc-macro2"
2959
-
version = "1.0.103"
2868
+
version = "1.0.105"
2960
2869
source = "registry+https://github.com/rust-lang/crates.io-index"
2961
-
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
2870
+
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
2962
2871
dependencies = [
2963
2872
"unicode-ident",
2964
2873
]
···
2971
2880
dependencies = [
2972
2881
"proc-macro2",
2973
2882
"quote",
2974
-
"syn 2.0.111",
2883
+
"syn 2.0.113",
2975
2884
"version_check",
2976
2885
"yansi",
2977
2886
]
···
3039
2948
3040
2949
[[package]]
3041
2950
name = "quote"
3042
-
version = "1.0.42"
2951
+
version = "1.0.43"
3043
2952
source = "registry+https://github.com/rust-lang/crates.io-index"
3044
-
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
2953
+
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
3045
2954
dependencies = [
3046
2955
"proc-macro2",
3047
2956
]
···
3112
3021
]
3113
3022
3114
3023
[[package]]
3115
-
name = "range-traits"
3116
-
version = "0.3.2"
3024
+
name = "redox_syscall"
3025
+
version = "0.5.18"
3117
3026
source = "registry+https://github.com/rust-lang/crates.io-index"
3118
-
checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab"
3027
+
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
3028
+
dependencies = [
3029
+
"bitflags",
3030
+
]
3119
3031
3120
3032
[[package]]
3121
3033
name = "redox_syscall"
3122
-
version = "0.5.18"
3034
+
version = "0.7.0"
3123
3035
source = "registry+https://github.com/rust-lang/crates.io-index"
3124
-
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
3036
+
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
3125
3037
dependencies = [
3126
3038
"bitflags",
3127
3039
]
···
3138
3050
]
3139
3051
3140
3052
[[package]]
3141
-
name = "ref-cast"
3142
-
version = "1.0.25"
3143
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3144
-
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
3145
-
dependencies = [
3146
-
"ref-cast-impl",
3147
-
]
3148
-
3149
-
[[package]]
3150
-
name = "ref-cast-impl"
3151
-
version = "1.0.25"
3152
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3153
-
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
3154
-
dependencies = [
3155
-
"proc-macro2",
3156
-
"quote",
3157
-
"syn 2.0.111",
3158
-
]
3159
-
3160
-
[[package]]
3161
3053
name = "regex"
3162
3054
version = "1.12.2"
3163
3055
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3194
3086
3195
3087
[[package]]
3196
3088
name = "reqwest"
3197
-
version = "0.12.24"
3089
+
version = "0.12.28"
3198
3090
source = "registry+https://github.com/rust-lang/crates.io-index"
3199
-
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
3091
+
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
3200
3092
dependencies = [
3201
-
"async-compression",
3202
3093
"base64 0.22.1",
3203
3094
"bytes",
3204
3095
"encoding_rs",
···
3293
3184
3294
3185
[[package]]
3295
3186
name = "rsa"
3296
-
version = "0.9.9"
3187
+
version = "0.9.10"
3297
3188
source = "registry+https://github.com/rust-lang/crates.io-index"
3298
-
checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88"
3189
+
checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
3299
3190
dependencies = [
3300
3191
"const-oid",
3301
3192
"digest",
···
3334
3225
3335
3226
[[package]]
3336
3227
name = "rustix"
3337
-
version = "1.1.2"
3228
+
version = "1.1.3"
3338
3229
source = "registry+https://github.com/rust-lang/crates.io-index"
3339
-
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
3230
+
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
3340
3231
dependencies = [
3341
3232
"bitflags",
3342
3233
"errno",
···
3347
3238
3348
3239
[[package]]
3349
3240
name = "rustls"
3350
-
version = "0.23.35"
3241
+
version = "0.23.36"
3351
3242
source = "registry+https://github.com/rust-lang/crates.io-index"
3352
-
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
3243
+
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
3353
3244
dependencies = [
3354
3245
"once_cell",
3355
3246
"ring",
···
3361
3252
3362
3253
[[package]]
3363
3254
name = "rustls-native-certs"
3364
-
version = "0.8.2"
3255
+
version = "0.8.3"
3365
3256
source = "registry+https://github.com/rust-lang/crates.io-index"
3366
-
checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923"
3257
+
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
3367
3258
dependencies = [
3368
3259
"openssl-probe",
3369
3260
"rustls-pki-types",
···
3373
3264
3374
3265
[[package]]
3375
3266
name = "rustls-pki-types"
3376
-
version = "1.13.0"
3267
+
version = "1.13.2"
3377
3268
source = "registry+https://github.com/rust-lang/crates.io-index"
3378
-
checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a"
3269
+
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
3379
3270
dependencies = [
3380
3271
"web-time",
3381
3272
"zeroize",
···
3400
3291
3401
3292
[[package]]
3402
3293
name = "ryu"
3403
-
version = "1.0.20"
3294
+
version = "1.0.22"
3404
3295
source = "registry+https://github.com/rust-lang/crates.io-index"
3405
-
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
3296
+
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
3406
3297
3407
3298
[[package]]
3408
3299
name = "safemem"
···
3429
3320
]
3430
3321
3431
3322
[[package]]
3432
-
name = "schemars"
3433
-
version = "0.9.0"
3434
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3435
-
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
3436
-
dependencies = [
3437
-
"dyn-clone",
3438
-
"ref-cast",
3439
-
"serde",
3440
-
"serde_json",
3441
-
]
3442
-
3443
-
[[package]]
3444
-
name = "schemars"
3445
-
version = "1.1.0"
3446
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3447
-
checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289"
3448
-
dependencies = [
3449
-
"dyn-clone",
3450
-
"ref-cast",
3451
-
"serde",
3452
-
"serde_json",
3453
-
]
3454
-
3455
-
[[package]]
3456
3323
name = "scoped-tls"
3457
3324
version = "1.0.1"
3458
3325
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3550
3417
dependencies = [
3551
3418
"proc-macro2",
3552
3419
"quote",
3553
-
"syn 2.0.111",
3420
+
"syn 2.0.113",
3554
3421
]
3555
3422
3556
3423
[[package]]
3557
3424
name = "serde_html_form"
3558
-
version = "0.2.8"
3425
+
version = "0.3.2"
3559
3426
source = "registry+https://github.com/rust-lang/crates.io-index"
3560
-
checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
3427
+
checksum = "2acf96b1d9364968fce46ebb548f1c0e1d7eceae27bdff73865d42e6c7369d94"
3561
3428
dependencies = [
3562
3429
"form_urlencoded",
3563
-
"indexmap 2.12.1",
3430
+
"indexmap",
3564
3431
"itoa",
3565
-
"ryu",
3566
3432
"serde_core",
3567
3433
]
3568
3434
···
3580
3446
3581
3447
[[package]]
3582
3448
name = "serde_json"
3583
-
version = "1.0.145"
3449
+
version = "1.0.149"
3584
3450
source = "registry+https://github.com/rust-lang/crates.io-index"
3585
-
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
3451
+
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
3586
3452
dependencies = [
3587
3453
"itoa",
3588
3454
"memchr",
3589
-
"ryu",
3590
3455
"serde",
3591
3456
"serde_core",
3457
+
"zmij",
3592
3458
]
3593
3459
3594
3460
[[package]]
···
3610
3476
dependencies = [
3611
3477
"proc-macro2",
3612
3478
"quote",
3613
-
"syn 2.0.111",
3479
+
"syn 2.0.113",
3614
3480
]
3615
3481
3616
3482
[[package]]
···
3627
3493
3628
3494
[[package]]
3629
3495
name = "serde_with"
3630
-
version = "3.16.0"
3496
+
version = "3.16.1"
3631
3497
source = "registry+https://github.com/rust-lang/crates.io-index"
3632
-
checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1"
3498
+
checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
3633
3499
dependencies = [
3634
3500
"base64 0.22.1",
3635
3501
"chrono",
3636
3502
"hex",
3637
-
"indexmap 1.9.3",
3638
-
"indexmap 2.12.1",
3639
-
"schemars 0.9.0",
3640
-
"schemars 1.1.0",
3641
3503
"serde_core",
3642
3504
"serde_json",
3643
3505
"serde_with_macros",
···
3646
3508
3647
3509
[[package]]
3648
3510
name = "serde_with_macros"
3649
-
version = "3.16.0"
3511
+
version = "3.16.1"
3650
3512
source = "registry+https://github.com/rust-lang/crates.io-index"
3651
-
checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b"
3513
+
checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
3652
3514
dependencies = [
3653
3515
"darling",
3654
3516
"proc-macro2",
3655
3517
"quote",
3656
-
"syn 2.0.111",
3518
+
"syn 2.0.113",
3657
3519
]
3658
3520
3659
3521
[[package]]
···
3710
3572
3711
3573
[[package]]
3712
3574
name = "signal-hook-registry"
3713
-
version = "1.4.7"
3575
+
version = "1.4.8"
3714
3576
source = "registry+https://github.com/rust-lang/crates.io-index"
3715
-
checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
3577
+
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
3716
3578
dependencies = [
3579
+
"errno",
3717
3580
"libc",
3718
3581
]
3719
3582
···
3729
3592
3730
3593
[[package]]
3731
3594
name = "simd-adler32"
3732
-
version = "0.3.7"
3595
+
version = "0.3.8"
3733
3596
source = "registry+https://github.com/rust-lang/crates.io-index"
3734
-
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
3597
+
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
3735
3598
3736
3599
[[package]]
3737
3600
name = "siphasher"
···
3813
3676
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
3814
3677
3815
3678
[[package]]
3816
-
name = "static-regular-grammar"
3817
-
version = "2.0.2"
3818
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3819
-
checksum = "4f4a6c40247579acfbb138c3cd7de3dab113ab4ac6227f1b7de7d626ee667957"
3820
-
dependencies = [
3821
-
"abnf",
3822
-
"btree-range-map",
3823
-
"ciborium",
3824
-
"hex_fmt",
3825
-
"indoc",
3826
-
"proc-macro-error",
3827
-
"proc-macro2",
3828
-
"quote",
3829
-
"serde",
3830
-
"sha2",
3831
-
"syn 2.0.111",
3832
-
"thiserror 1.0.69",
3833
-
]
3834
-
3835
-
[[package]]
3836
3679
name = "static_assertions"
3837
3680
version = "1.1.0"
3838
3681
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3886
3729
3887
3730
[[package]]
3888
3731
name = "supports-hyperlinks"
3889
-
version = "3.1.0"
3732
+
version = "3.2.0"
3890
3733
source = "registry+https://github.com/rust-lang/crates.io-index"
3891
-
checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b"
3734
+
checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91"
3892
3735
3893
3736
[[package]]
3894
3737
name = "supports-unicode"
···
3909
3752
3910
3753
[[package]]
3911
3754
name = "syn"
3912
-
version = "2.0.111"
3755
+
version = "2.0.113"
3913
3756
source = "registry+https://github.com/rust-lang/crates.io-index"
3914
-
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
3757
+
checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
3915
3758
dependencies = [
3916
3759
"proc-macro2",
3917
3760
"quote",
···
3935
3778
dependencies = [
3936
3779
"proc-macro2",
3937
3780
"quote",
3938
-
"syn 2.0.111",
3781
+
"syn 2.0.113",
3939
3782
]
3940
3783
3941
3784
[[package]]
···
3967
3810
3968
3811
[[package]]
3969
3812
name = "tempfile"
3970
-
version = "3.23.0"
3813
+
version = "3.24.0"
3971
3814
source = "registry+https://github.com/rust-lang/crates.io-index"
3972
-
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
3815
+
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
3973
3816
dependencies = [
3974
3817
"fastrand",
3975
3818
"getrandom 0.3.4",
···
4035
3878
dependencies = [
4036
3879
"proc-macro2",
4037
3880
"quote",
4038
-
"syn 2.0.111",
3881
+
"syn 2.0.113",
4039
3882
]
4040
3883
4041
3884
[[package]]
···
4046
3889
dependencies = [
4047
3890
"proc-macro2",
4048
3891
"quote",
4049
-
"syn 2.0.111",
3892
+
"syn 2.0.113",
4050
3893
]
4051
3894
4052
3895
[[package]]
···
4074
3917
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
4075
3918
dependencies = [
4076
3919
"deranged",
4077
-
"itoa",
4078
3920
"libc",
4079
3921
"num-conv",
4080
3922
"num_threads",
4081
3923
"powerfmt",
4082
3924
"serde",
4083
3925
"time-core",
4084
-
"time-macros",
4085
3926
]
4086
3927
4087
3928
[[package]]
···
4091
3932
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
4092
3933
4093
3934
[[package]]
4094
-
name = "time-macros"
4095
-
version = "0.2.24"
4096
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4097
-
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
4098
-
dependencies = [
4099
-
"num-conv",
4100
-
"time-core",
4101
-
]
4102
-
4103
-
[[package]]
4104
3935
name = "tiny_http"
4105
3936
version = "0.12.0"
4106
3937
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4139
3970
4140
3971
[[package]]
4141
3972
name = "tokio"
4142
-
version = "1.48.0"
3973
+
version = "1.49.0"
4143
3974
source = "registry+https://github.com/rust-lang/crates.io-index"
4144
-
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
3975
+
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
4145
3976
dependencies = [
4146
3977
"bytes",
4147
3978
"libc",
···
4162
3993
dependencies = [
4163
3994
"proc-macro2",
4164
3995
"quote",
4165
-
"syn 2.0.111",
3996
+
"syn 2.0.113",
4166
3997
]
4167
3998
4168
3999
[[package]]
···
4212
4043
4213
4044
[[package]]
4214
4045
name = "tokio-util"
4215
-
version = "0.7.17"
4046
+
version = "0.7.18"
4216
4047
source = "registry+https://github.com/rust-lang/crates.io-index"
4217
-
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
4048
+
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
4218
4049
dependencies = [
4219
4050
"bytes",
4220
4051
"futures-core",
···
4242
4073
4243
4074
[[package]]
4244
4075
name = "tower-http"
4245
-
version = "0.6.7"
4076
+
version = "0.6.8"
4246
4077
source = "registry+https://github.com/rust-lang/crates.io-index"
4247
-
checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456"
4078
+
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
4248
4079
dependencies = [
4249
4080
"async-compression",
4250
4081
"bitflags",
···
4283
4114
4284
4115
[[package]]
4285
4116
name = "tracing"
4286
-
version = "0.1.41"
4117
+
version = "0.1.44"
4287
4118
source = "registry+https://github.com/rust-lang/crates.io-index"
4288
-
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
4119
+
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
4289
4120
dependencies = [
4290
4121
"log",
4291
4122
"pin-project-lite",
···
4295
4126
4296
4127
[[package]]
4297
4128
name = "tracing-attributes"
4298
-
version = "0.1.30"
4129
+
version = "0.1.31"
4299
4130
source = "registry+https://github.com/rust-lang/crates.io-index"
4300
-
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
4131
+
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
4301
4132
dependencies = [
4302
4133
"proc-macro2",
4303
4134
"quote",
4304
-
"syn 2.0.111",
4135
+
"syn 2.0.113",
4305
4136
]
4306
4137
4307
4138
[[package]]
4308
4139
name = "tracing-core"
4309
-
version = "0.1.34"
4140
+
version = "0.1.36"
4310
4141
source = "registry+https://github.com/rust-lang/crates.io-index"
4311
-
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
4142
+
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
4312
4143
dependencies = [
4313
4144
"once_cell",
4314
4145
"valuable",
···
4327
4158
4328
4159
[[package]]
4329
4160
name = "tracing-subscriber"
4330
-
version = "0.3.20"
4161
+
version = "0.3.22"
4331
4162
source = "registry+https://github.com/rust-lang/crates.io-index"
4332
-
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
4163
+
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
4333
4164
dependencies = [
4334
4165
"matchers",
4335
4166
"nu-ansi-term",
···
4351
4182
dependencies = [
4352
4183
"proc-macro2",
4353
4184
"quote",
4354
-
"syn 2.0.111",
4185
+
"syn 2.0.113",
4355
4186
]
4356
4187
4357
4188
[[package]]
···
4403
4234
4404
4235
[[package]]
4405
4236
name = "unicase"
4406
-
version = "2.8.1"
4237
+
version = "2.9.0"
4407
4238
source = "registry+https://github.com/rust-lang/crates.io-index"
4408
-
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
4239
+
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
4409
4240
4410
4241
[[package]]
4411
4242
name = "unicode-ident"
···
4457
4288
4458
4289
[[package]]
4459
4290
name = "url"
4460
-
version = "2.5.7"
4291
+
version = "2.5.8"
4461
4292
source = "registry+https://github.com/rust-lang/crates.io-index"
4462
-
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
4293
+
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
4463
4294
dependencies = [
4464
4295
"form_urlencoded",
4465
4296
"idna",
4466
4297
"percent-encoding",
4467
4298
"serde",
4299
+
"serde_derive",
4468
4300
]
4469
4301
4470
4302
[[package]]
···
4539
4371
4540
4372
[[package]]
4541
4373
name = "wasm-bindgen"
4542
-
version = "0.2.105"
4374
+
version = "0.2.106"
4543
4375
source = "registry+https://github.com/rust-lang/crates.io-index"
4544
-
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
4376
+
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
4545
4377
dependencies = [
4546
4378
"cfg-if",
4547
4379
"once_cell",
···
4552
4384
4553
4385
[[package]]
4554
4386
name = "wasm-bindgen-futures"
4555
-
version = "0.4.55"
4387
+
version = "0.4.56"
4556
4388
source = "registry+https://github.com/rust-lang/crates.io-index"
4557
-
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
4389
+
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
4558
4390
dependencies = [
4559
4391
"cfg-if",
4560
4392
"js-sys",
···
4565
4397
4566
4398
[[package]]
4567
4399
name = "wasm-bindgen-macro"
4568
-
version = "0.2.105"
4400
+
version = "0.2.106"
4569
4401
source = "registry+https://github.com/rust-lang/crates.io-index"
4570
-
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
4402
+
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
4571
4403
dependencies = [
4572
4404
"quote",
4573
4405
"wasm-bindgen-macro-support",
···
4575
4407
4576
4408
[[package]]
4577
4409
name = "wasm-bindgen-macro-support"
4578
-
version = "0.2.105"
4410
+
version = "0.2.106"
4579
4411
source = "registry+https://github.com/rust-lang/crates.io-index"
4580
-
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
4412
+
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
4581
4413
dependencies = [
4582
4414
"bumpalo",
4583
4415
"proc-macro2",
4584
4416
"quote",
4585
-
"syn 2.0.111",
4417
+
"syn 2.0.113",
4586
4418
"wasm-bindgen-shared",
4587
4419
]
4588
4420
4589
4421
[[package]]
4590
4422
name = "wasm-bindgen-shared"
4591
-
version = "0.2.105"
4423
+
version = "0.2.106"
4592
4424
source = "registry+https://github.com/rust-lang/crates.io-index"
4593
-
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
4425
+
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
4594
4426
dependencies = [
4595
4427
"unicode-ident",
4596
4428
]
···
4610
4442
4611
4443
[[package]]
4612
4444
name = "web-sys"
4613
-
version = "0.3.82"
4445
+
version = "0.3.83"
4614
4446
source = "registry+https://github.com/rust-lang/crates.io-index"
4615
-
checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
4447
+
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
4616
4448
dependencies = [
4617
4449
"js-sys",
4618
4450
"wasm-bindgen",
···
4658
4490
4659
4491
[[package]]
4660
4492
name = "webpki-roots"
4661
-
version = "1.0.4"
4493
+
version = "1.0.5"
4662
4494
source = "registry+https://github.com/rust-lang/crates.io-index"
4663
-
checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
4495
+
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
4664
4496
dependencies = [
4665
4497
"rustls-pki-types",
4666
4498
]
···
4681
4513
]
4682
4514
4683
4515
[[package]]
4684
-
name = "windows"
4685
-
version = "0.61.3"
4686
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4687
-
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
4688
-
dependencies = [
4689
-
"windows-collections",
4690
-
"windows-core 0.61.2",
4691
-
"windows-future",
4692
-
"windows-link 0.1.3",
4693
-
"windows-numerics",
4694
-
]
4695
-
4696
-
[[package]]
4697
-
name = "windows-collections"
4698
-
version = "0.2.0"
4699
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4700
-
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
4701
-
dependencies = [
4702
-
"windows-core 0.61.2",
4703
-
]
4704
-
4705
-
[[package]]
4706
-
name = "windows-core"
4707
-
version = "0.61.2"
4708
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4709
-
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
4710
-
dependencies = [
4711
-
"windows-implement",
4712
-
"windows-interface",
4713
-
"windows-link 0.1.3",
4714
-
"windows-result 0.3.4",
4715
-
"windows-strings 0.4.2",
4716
-
]
4717
-
4718
-
[[package]]
4719
4516
name = "windows-core"
4720
4517
version = "0.62.2"
4721
4518
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4723
4520
dependencies = [
4724
4521
"windows-implement",
4725
4522
"windows-interface",
4726
-
"windows-link 0.2.1",
4727
-
"windows-result 0.4.1",
4728
-
"windows-strings 0.5.1",
4729
-
]
4730
-
4731
-
[[package]]
4732
-
name = "windows-future"
4733
-
version = "0.2.1"
4734
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4735
-
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
4736
-
dependencies = [
4737
-
"windows-core 0.61.2",
4738
-
"windows-link 0.1.3",
4739
-
"windows-threading",
4523
+
"windows-link",
4524
+
"windows-result",
4525
+
"windows-strings",
4740
4526
]
4741
4527
4742
4528
[[package]]
···
4747
4533
dependencies = [
4748
4534
"proc-macro2",
4749
4535
"quote",
4750
-
"syn 2.0.111",
4536
+
"syn 2.0.113",
4751
4537
]
4752
4538
4753
4539
[[package]]
···
4758
4544
dependencies = [
4759
4545
"proc-macro2",
4760
4546
"quote",
4761
-
"syn 2.0.111",
4547
+
"syn 2.0.113",
4762
4548
]
4763
4549
4764
4550
[[package]]
4765
4551
name = "windows-link"
4766
-
version = "0.1.3"
4767
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4768
-
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
4769
-
4770
-
[[package]]
4771
-
name = "windows-link"
4772
4552
version = "0.2.1"
4773
4553
source = "registry+https://github.com/rust-lang/crates.io-index"
4774
4554
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
4775
4555
4776
4556
[[package]]
4777
-
name = "windows-numerics"
4778
-
version = "0.2.0"
4779
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4780
-
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
4781
-
dependencies = [
4782
-
"windows-core 0.61.2",
4783
-
"windows-link 0.1.3",
4784
-
]
4785
-
4786
-
[[package]]
4787
4557
name = "windows-registry"
4788
4558
version = "0.6.1"
4789
4559
source = "registry+https://github.com/rust-lang/crates.io-index"
4790
4560
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
4791
4561
dependencies = [
4792
-
"windows-link 0.2.1",
4793
-
"windows-result 0.4.1",
4794
-
"windows-strings 0.5.1",
4795
-
]
4796
-
4797
-
[[package]]
4798
-
name = "windows-result"
4799
-
version = "0.3.4"
4800
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4801
-
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
4802
-
dependencies = [
4803
-
"windows-link 0.1.3",
4562
+
"windows-link",
4563
+
"windows-result",
4564
+
"windows-strings",
4804
4565
]
4805
4566
4806
4567
[[package]]
···
4809
4570
source = "registry+https://github.com/rust-lang/crates.io-index"
4810
4571
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
4811
4572
dependencies = [
4812
-
"windows-link 0.2.1",
4813
-
]
4814
-
4815
-
[[package]]
4816
-
name = "windows-strings"
4817
-
version = "0.4.2"
4818
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4819
-
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
4820
-
dependencies = [
4821
-
"windows-link 0.1.3",
4573
+
"windows-link",
4822
4574
]
4823
4575
4824
4576
[[package]]
···
4827
4579
source = "registry+https://github.com/rust-lang/crates.io-index"
4828
4580
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
4829
4581
dependencies = [
4830
-
"windows-link 0.2.1",
4582
+
"windows-link",
4831
4583
]
4832
4584
4833
4585
[[package]]
···
4881
4633
source = "registry+https://github.com/rust-lang/crates.io-index"
4882
4634
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
4883
4635
dependencies = [
4884
-
"windows-link 0.2.1",
4636
+
"windows-link",
4885
4637
]
4886
4638
4887
4639
[[package]]
···
4936
4688
source = "registry+https://github.com/rust-lang/crates.io-index"
4937
4689
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
4938
4690
dependencies = [
4939
-
"windows-link 0.2.1",
4691
+
"windows-link",
4940
4692
"windows_aarch64_gnullvm 0.53.1",
4941
4693
"windows_aarch64_msvc 0.53.1",
4942
4694
"windows_i686_gnu 0.53.1",
···
4945
4697
"windows_x86_64_gnu 0.53.1",
4946
4698
"windows_x86_64_gnullvm 0.53.1",
4947
4699
"windows_x86_64_msvc 0.53.1",
4948
-
]
4949
-
4950
-
[[package]]
4951
-
name = "windows-threading"
4952
-
version = "0.1.0"
4953
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4954
-
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
4955
-
dependencies = [
4956
-
"windows-link 0.1.3",
4957
4700
]
4958
4701
4959
4702
[[package]]
···
5184
4927
"tower-http",
5185
4928
"url",
5186
4929
"walkdir",
4930
+
"wisp-lexicons",
4931
+
]
4932
+
4933
+
[[package]]
4934
+
name = "wisp-lexicons"
4935
+
version = "0.1.0"
4936
+
dependencies = [
4937
+
"jacquard-common",
4938
+
"jacquard-derive",
4939
+
"jacquard-lexicon",
4940
+
"rustversion",
4941
+
"serde",
5187
4942
]
5188
4943
5189
4944
[[package]]
···
5234
4989
dependencies = [
5235
4990
"proc-macro2",
5236
4991
"quote",
5237
-
"syn 2.0.111",
4992
+
"syn 2.0.113",
5238
4993
"synstructure",
5239
4994
]
5240
4995
5241
4996
[[package]]
5242
4997
name = "zerocopy"
5243
-
version = "0.8.30"
4998
+
version = "0.8.32"
5244
4999
source = "registry+https://github.com/rust-lang/crates.io-index"
5245
-
checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
5000
+
checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56"
5246
5001
dependencies = [
5247
5002
"zerocopy-derive",
5248
5003
]
5249
5004
5250
5005
[[package]]
5251
5006
name = "zerocopy-derive"
5252
-
version = "0.8.30"
5007
+
version = "0.8.32"
5253
5008
source = "registry+https://github.com/rust-lang/crates.io-index"
5254
-
checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
5009
+
checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90"
5255
5010
dependencies = [
5256
5011
"proc-macro2",
5257
5012
"quote",
5258
-
"syn 2.0.111",
5013
+
"syn 2.0.113",
5259
5014
]
5260
5015
5261
5016
[[package]]
···
5275
5030
dependencies = [
5276
5031
"proc-macro2",
5277
5032
"quote",
5278
-
"syn 2.0.111",
5033
+
"syn 2.0.113",
5279
5034
"synstructure",
5280
5035
]
5281
5036
···
5318
5073
dependencies = [
5319
5074
"proc-macro2",
5320
5075
"quote",
5321
-
"syn 2.0.111",
5076
+
"syn 2.0.113",
5322
5077
]
5078
+
5079
+
[[package]]
5080
+
name = "zmij"
5081
+
version = "1.0.12"
5082
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5083
+
checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
+8
-7
cli/Cargo.toml
+8
-7
cli/Cargo.toml
···
8
8
place_wisp = []
9
9
10
10
[dependencies]
11
-
jacquard = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["loopback"] }
12
-
jacquard-oauth = { git = "https://tangled.org/nekomimi.pet/jacquard" }
13
-
jacquard-api = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["streaming"] }
14
-
jacquard-common = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["websocket"] }
15
-
jacquard-identity = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["dns"] }
16
-
jacquard-derive = { git = "https://tangled.org/nekomimi.pet/jacquard" }
17
-
jacquard-lexicon = { git = "https://tangled.org/nekomimi.pet/jacquard" }
11
+
jacquard = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["loopback"] }
12
+
jacquard-oauth = { git = "https://tangled.org/nonbinary.computer/jacquard" }
13
+
jacquard-api = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["streaming"] }
14
+
jacquard-common = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["websocket"] }
15
+
jacquard-identity = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["dns"] }
16
+
jacquard-derive = { git = "https://tangled.org/nonbinary.computer/jacquard" }
17
+
jacquard-lexicon = { git = "https://tangled.org/nonbinary.computer/jacquard" }
18
+
wisp-lexicons = { path = "crates/lexicons" }
18
19
#jacquard = { path = "../../jacquard/crates/jacquard", features = ["loopback"] }
19
20
#jacquard-oauth = { path = "../../jacquard/crates/jacquard-oauth" }
20
21
#jacquard-api = { path = "../../jacquard/crates/jacquard-api", features = ["streaming"] }
+72
-2
cli/README.md
+72
-2
cli/README.md
···
32
32
33
33
## Usage
34
34
35
+
### Commands
36
+
37
+
The CLI supports three main commands:
38
+
- **deploy**: Upload a site to your PDS (default command)
39
+
- **pull**: Download a site from a PDS to a local directory
40
+
- **serve**: Serve a site locally with real-time firehose updates
41
+
35
42
### Basic Deployment
36
43
37
44
Deploy the current directory:
38
45
39
46
```bash
40
-
wisp-cli nekomimi.ppet --path . --site my-site
47
+
wisp-cli nekomimi.pet --path . --site my-site
41
48
```
42
49
43
50
Deploy a specific directory:
···
46
53
wisp-cli alice.bsky.social --path ./dist/ --site my-site
47
54
```
48
55
56
+
Or use the explicit `deploy` subcommand:
57
+
58
+
```bash
59
+
wisp-cli deploy alice.bsky.social --path ./dist/ --site my-site
60
+
```
61
+
62
+
### Pull a Site
63
+
64
+
Download a site from a PDS to a local directory:
65
+
66
+
```bash
67
+
wisp-cli pull alice.bsky.social --site my-site --path ./downloaded-site
68
+
```
69
+
70
+
This will download all files from the site to the specified directory.
71
+
72
+
### Serve a Site Locally
73
+
74
+
Serve a site locally with real-time updates from the firehose:
75
+
76
+
```bash
77
+
wisp-cli serve alice.bsky.social --site my-site --path ./site --port 8080
78
+
```
79
+
80
+
This will:
81
+
1. Download the site to the specified path
82
+
2. Start a local server on the specified port (default: 8080)
83
+
3. Watch the firehose for updates and automatically reload files when changed
84
+
49
85
### Authentication Methods
50
86
51
87
#### OAuth (Recommended)
···
79
115
80
116
## Command-Line Options
81
117
118
+
### Deploy Command
119
+
82
120
```
83
-
wisp-cli [OPTIONS] <INPUT>
121
+
wisp-cli [deploy] [OPTIONS] <INPUT>
84
122
85
123
Arguments:
86
124
<INPUT> Handle (e.g., alice.bsky.social), DID, or PDS URL
···
90
128
-s, --site <SITE> Site name (defaults to directory name)
91
129
--store <STORE> Path to auth store file (only used with OAuth) [default: /tmp/wisp-oauth-session.json]
92
130
--password <PASSWORD> App Password for authentication (alternative to OAuth)
131
+
--directory Enable directory listing mode for paths without index files
132
+
--spa Enable SPA mode (serve index.html for all routes)
133
+
-y, --yes Skip confirmation prompts (automatically accept warnings)
93
134
-h, --help Print help
94
135
-V, --version Print version
136
+
```
137
+
138
+
### Pull Command
139
+
140
+
```
141
+
wisp-cli pull [OPTIONS] --site <SITE> <INPUT>
142
+
143
+
Arguments:
144
+
<INPUT> Handle (e.g., alice.bsky.social) or DID
145
+
146
+
Options:
147
+
-s, --site <SITE> Site name (record key)
148
+
-p, --path <PATH> Output directory for the downloaded site [default: .]
149
+
-h, --help Print help
150
+
```
151
+
152
+
### Serve Command
153
+
154
+
```
155
+
wisp-cli serve [OPTIONS] --site <SITE> <INPUT>
156
+
157
+
Arguments:
158
+
<INPUT> Handle (e.g., alice.bsky.social) or DID
159
+
160
+
Options:
161
+
-s, --site <SITE> Site name (record key)
162
+
-p, --path <PATH> Output directory for the site files [default: .]
163
+
-P, --port <PORT> Port to serve on [default: 8080]
164
+
-h, --help Print help
95
165
```
96
166
97
167
## How It Works
+15
cli/crates/lexicons/Cargo.toml
+15
cli/crates/lexicons/Cargo.toml
···
1
+
[package]
2
+
name = "wisp-lexicons"
3
+
version = "0.1.0"
4
+
edition = "2024"
5
+
6
+
[features]
7
+
default = ["place_wisp"]
8
+
place_wisp = []
9
+
10
+
[dependencies]
11
+
jacquard-common = { git = "https://tangled.org/nonbinary.computer/jacquard" }
12
+
jacquard-derive = { git = "https://tangled.org/nonbinary.computer/jacquard" }
13
+
jacquard-lexicon = { git = "https://tangled.org/nonbinary.computer/jacquard" }
14
+
serde = { version = "1.0", features = ["derive"] }
15
+
rustversion = "1.0"
+43
cli/crates/lexicons/src/builder_types.rs
+43
cli/crates/lexicons/src/builder_types.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// This file was automatically generated from Lexicon schemas.
4
+
// Any manual changes will be overwritten on the next regeneration.
5
+
6
+
/// Marker type indicating a builder field has been set
7
+
pub struct Set<T>(pub T);
8
+
impl<T> Set<T> {
9
+
/// Extract the inner value
10
+
#[inline]
11
+
pub fn into_inner(self) -> T {
12
+
self.0
13
+
}
14
+
}
15
+
16
+
/// Marker type indicating a builder field has not been set
17
+
pub struct Unset;
18
+
/// Trait indicating a builder field is set (has a value)
19
+
#[rustversion::attr(
20
+
since(1.78.0),
21
+
diagnostic::on_unimplemented(
22
+
message = "the field `{Self}` was not set, but this method requires it to be set",
23
+
label = "the field `{Self}` was not set"
24
+
)
25
+
)]
26
+
pub trait IsSet: private::Sealed {}
27
+
/// Trait indicating a builder field is unset (no value yet)
28
+
#[rustversion::attr(
29
+
since(1.78.0),
30
+
diagnostic::on_unimplemented(
31
+
message = "the field `{Self}` was already set, but this method requires it to be unset",
32
+
label = "the field `{Self}` was already set"
33
+
)
34
+
)]
35
+
pub trait IsUnset: private::Sealed {}
36
+
impl<T> IsSet for Set<T> {}
37
+
impl IsUnset for Unset {}
38
+
mod private {
39
+
/// Sealed trait to prevent external implementations
40
+
pub trait Sealed {}
41
+
impl<T> Sealed for super::Set<T> {}
42
+
impl Sealed for super::Unset {}
43
+
}
+11
cli/crates/lexicons/src/lib.rs
+11
cli/crates/lexicons/src/lib.rs
···
1
+
extern crate alloc;
2
+
3
+
// @generated by jacquard-lexicon. DO NOT EDIT.
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
pub mod builder_types;
9
+
10
+
#[cfg(feature = "place_wisp")]
11
+
pub mod place_wisp;
+1490
cli/crates/lexicons/src/place_wisp/fs.rs
+1490
cli/crates/lexicons/src/place_wisp/fs.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// Lexicon: place.wisp.fs
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
#[jacquard_derive::lexicon]
9
+
#[derive(
10
+
serde::Serialize,
11
+
serde::Deserialize,
12
+
Debug,
13
+
Clone,
14
+
PartialEq,
15
+
Eq,
16
+
jacquard_derive::IntoStatic
17
+
)]
18
+
#[serde(rename_all = "camelCase")]
19
+
pub struct Directory<'a> {
20
+
#[serde(borrow)]
21
+
pub entries: Vec<crate::place_wisp::fs::Entry<'a>>,
22
+
#[serde(borrow)]
23
+
pub r#type: jacquard_common::CowStr<'a>,
24
+
}
25
+
26
+
pub mod directory_state {
27
+
28
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
+
#[allow(unused)]
30
+
use ::core::marker::PhantomData;
31
+
mod sealed {
32
+
pub trait Sealed {}
33
+
}
34
+
/// State trait tracking which required fields have been set
35
+
pub trait State: sealed::Sealed {
36
+
type Type;
37
+
type Entries;
38
+
}
39
+
/// Empty state - all required fields are unset
40
+
pub struct Empty(());
41
+
impl sealed::Sealed for Empty {}
42
+
impl State for Empty {
43
+
type Type = Unset;
44
+
type Entries = Unset;
45
+
}
46
+
///State transition - sets the `type` field to Set
47
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
+
impl<S: State> sealed::Sealed for SetType<S> {}
49
+
impl<S: State> State for SetType<S> {
50
+
type Type = Set<members::r#type>;
51
+
type Entries = S::Entries;
52
+
}
53
+
///State transition - sets the `entries` field to Set
54
+
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
+
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
+
impl<S: State> State for SetEntries<S> {
57
+
type Type = S::Type;
58
+
type Entries = Set<members::entries>;
59
+
}
60
+
/// Marker types for field names
61
+
#[allow(non_camel_case_types)]
62
+
pub mod members {
63
+
///Marker type for the `type` field
64
+
pub struct r#type(());
65
+
///Marker type for the `entries` field
66
+
pub struct entries(());
67
+
}
68
+
}
69
+
70
+
/// Builder for constructing an instance of this type
71
+
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
+
__unsafe_private_named: (
74
+
::core::option::Option<Vec<crate::place_wisp::fs::Entry<'a>>>,
75
+
::core::option::Option<jacquard_common::CowStr<'a>>,
76
+
),
77
+
_phantom: ::core::marker::PhantomData<&'a ()>,
78
+
}
79
+
80
+
impl<'a> Directory<'a> {
81
+
/// Create a new builder for this type
82
+
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
+
DirectoryBuilder::new()
84
+
}
85
+
}
86
+
87
+
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
+
/// Create a new builder with all fields unset
89
+
pub fn new() -> Self {
90
+
DirectoryBuilder {
91
+
_phantom_state: ::core::marker::PhantomData,
92
+
__unsafe_private_named: (None, None),
93
+
_phantom: ::core::marker::PhantomData,
94
+
}
95
+
}
96
+
}
97
+
98
+
impl<'a, S> DirectoryBuilder<'a, S>
99
+
where
100
+
S: directory_state::State,
101
+
S::Entries: directory_state::IsUnset,
102
+
{
103
+
/// Set the `entries` field (required)
104
+
pub fn entries(
105
+
mut self,
106
+
value: impl Into<Vec<crate::place_wisp::fs::Entry<'a>>>,
107
+
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
+
DirectoryBuilder {
110
+
_phantom_state: ::core::marker::PhantomData,
111
+
__unsafe_private_named: self.__unsafe_private_named,
112
+
_phantom: ::core::marker::PhantomData,
113
+
}
114
+
}
115
+
}
116
+
117
+
impl<'a, S> DirectoryBuilder<'a, S>
118
+
where
119
+
S: directory_state::State,
120
+
S::Type: directory_state::IsUnset,
121
+
{
122
+
/// Set the `type` field (required)
123
+
pub fn r#type(
124
+
mut self,
125
+
value: impl Into<jacquard_common::CowStr<'a>>,
126
+
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
+
DirectoryBuilder {
129
+
_phantom_state: ::core::marker::PhantomData,
130
+
__unsafe_private_named: self.__unsafe_private_named,
131
+
_phantom: ::core::marker::PhantomData,
132
+
}
133
+
}
134
+
}
135
+
136
+
impl<'a, S> DirectoryBuilder<'a, S>
137
+
where
138
+
S: directory_state::State,
139
+
S::Type: directory_state::IsSet,
140
+
S::Entries: directory_state::IsSet,
141
+
{
142
+
/// Build the final struct
143
+
pub fn build(self) -> Directory<'a> {
144
+
Directory {
145
+
entries: self.__unsafe_private_named.0.unwrap(),
146
+
r#type: self.__unsafe_private_named.1.unwrap(),
147
+
extra_data: Default::default(),
148
+
}
149
+
}
150
+
/// Build the final struct with custom extra_data
151
+
pub fn build_with_data(
152
+
self,
153
+
extra_data: std::collections::BTreeMap<
154
+
jacquard_common::smol_str::SmolStr,
155
+
jacquard_common::types::value::Data<'a>,
156
+
>,
157
+
) -> Directory<'a> {
158
+
Directory {
159
+
entries: self.__unsafe_private_named.0.unwrap(),
160
+
r#type: self.__unsafe_private_named.1.unwrap(),
161
+
extra_data: Some(extra_data),
162
+
}
163
+
}
164
+
}
165
+
166
+
fn lexicon_doc_place_wisp_fs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
+
::jacquard_lexicon::lexicon::LexiconDoc {
168
+
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
+
id: ::jacquard_common::CowStr::new_static("place.wisp.fs"),
170
+
revision: None,
171
+
description: None,
172
+
defs: {
173
+
let mut map = ::std::collections::BTreeMap::new();
174
+
map.insert(
175
+
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
+
description: None,
178
+
required: Some(
179
+
vec![
180
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
+
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
+
],
183
+
),
184
+
nullable: None,
185
+
properties: {
186
+
#[allow(unused_mut)]
187
+
let mut map = ::std::collections::BTreeMap::new();
188
+
map.insert(
189
+
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
+
description: None,
192
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
+
description: None,
194
+
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
+
}),
196
+
min_length: None,
197
+
max_length: Some(500usize),
198
+
}),
199
+
);
200
+
map.insert(
201
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
+
description: None,
204
+
format: None,
205
+
default: None,
206
+
min_length: None,
207
+
max_length: None,
208
+
min_graphemes: None,
209
+
max_graphemes: None,
210
+
r#enum: None,
211
+
r#const: None,
212
+
known_values: None,
213
+
}),
214
+
);
215
+
map
216
+
},
217
+
}),
218
+
);
219
+
map.insert(
220
+
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
+
description: None,
223
+
required: Some(
224
+
vec![
225
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
+
::jacquard_common::smol_str::SmolStr::new_static("node")
227
+
],
228
+
),
229
+
nullable: None,
230
+
properties: {
231
+
#[allow(unused_mut)]
232
+
let mut map = ::std::collections::BTreeMap::new();
233
+
map.insert(
234
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
+
description: None,
237
+
format: None,
238
+
default: None,
239
+
min_length: None,
240
+
max_length: Some(255usize),
241
+
min_graphemes: None,
242
+
max_graphemes: None,
243
+
r#enum: None,
244
+
r#const: None,
245
+
known_values: None,
246
+
}),
247
+
);
248
+
map.insert(
249
+
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
+
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
+
description: None,
252
+
refs: vec![
253
+
::jacquard_common::CowStr::new_static("#file"),
254
+
::jacquard_common::CowStr::new_static("#directory"),
255
+
::jacquard_common::CowStr::new_static("#subfs")
256
+
],
257
+
closed: None,
258
+
}),
259
+
);
260
+
map
261
+
},
262
+
}),
263
+
);
264
+
map.insert(
265
+
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
+
description: None,
268
+
required: Some(
269
+
vec![
270
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
+
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
+
],
273
+
),
274
+
nullable: None,
275
+
properties: {
276
+
#[allow(unused_mut)]
277
+
let mut map = ::std::collections::BTreeMap::new();
278
+
map.insert(
279
+
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
+
description: None,
282
+
default: None,
283
+
r#const: None,
284
+
}),
285
+
);
286
+
map.insert(
287
+
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
+
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
+
description: None,
290
+
accept: None,
291
+
max_size: None,
292
+
}),
293
+
);
294
+
map.insert(
295
+
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
+
description: Some(
298
+
::jacquard_common::CowStr::new_static(
299
+
"Content encoding (e.g., gzip for compressed files)",
300
+
),
301
+
),
302
+
format: None,
303
+
default: None,
304
+
min_length: None,
305
+
max_length: None,
306
+
min_graphemes: None,
307
+
max_graphemes: None,
308
+
r#enum: None,
309
+
r#const: None,
310
+
known_values: None,
311
+
}),
312
+
);
313
+
map.insert(
314
+
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
+
description: Some(
317
+
::jacquard_common::CowStr::new_static(
318
+
"Original MIME type before compression",
319
+
),
320
+
),
321
+
format: None,
322
+
default: None,
323
+
min_length: None,
324
+
max_length: None,
325
+
min_graphemes: None,
326
+
max_graphemes: None,
327
+
r#enum: None,
328
+
r#const: None,
329
+
known_values: None,
330
+
}),
331
+
);
332
+
map.insert(
333
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
+
description: None,
336
+
format: None,
337
+
default: None,
338
+
min_length: None,
339
+
max_length: None,
340
+
min_graphemes: None,
341
+
max_graphemes: None,
342
+
r#enum: None,
343
+
r#const: None,
344
+
known_values: None,
345
+
}),
346
+
);
347
+
map
348
+
},
349
+
}),
350
+
);
351
+
map.insert(
352
+
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
+
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
+
description: Some(
355
+
::jacquard_common::CowStr::new_static(
356
+
"Virtual filesystem manifest for a Wisp site",
357
+
),
358
+
),
359
+
key: None,
360
+
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
+
description: None,
362
+
required: Some(
363
+
vec![
364
+
::jacquard_common::smol_str::SmolStr::new_static("site"),
365
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
366
+
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
367
+
],
368
+
),
369
+
nullable: None,
370
+
properties: {
371
+
#[allow(unused_mut)]
372
+
let mut map = ::std::collections::BTreeMap::new();
373
+
map.insert(
374
+
::jacquard_common::smol_str::SmolStr::new_static(
375
+
"createdAt",
376
+
),
377
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
378
+
description: None,
379
+
format: Some(
380
+
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
381
+
),
382
+
default: None,
383
+
min_length: None,
384
+
max_length: None,
385
+
min_graphemes: None,
386
+
max_graphemes: None,
387
+
r#enum: None,
388
+
r#const: None,
389
+
known_values: None,
390
+
}),
391
+
);
392
+
map.insert(
393
+
::jacquard_common::smol_str::SmolStr::new_static(
394
+
"fileCount",
395
+
),
396
+
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
397
+
description: None,
398
+
default: None,
399
+
minimum: Some(0i64),
400
+
maximum: Some(1000i64),
401
+
r#enum: None,
402
+
r#const: None,
403
+
}),
404
+
);
405
+
map.insert(
406
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
407
+
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
408
+
description: None,
409
+
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
410
+
}),
411
+
);
412
+
map.insert(
413
+
::jacquard_common::smol_str::SmolStr::new_static("site"),
414
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
415
+
description: None,
416
+
format: None,
417
+
default: None,
418
+
min_length: None,
419
+
max_length: None,
420
+
min_graphemes: None,
421
+
max_graphemes: None,
422
+
r#enum: None,
423
+
r#const: None,
424
+
known_values: None,
425
+
}),
426
+
);
427
+
map
428
+
},
429
+
}),
430
+
}),
431
+
);
432
+
map.insert(
433
+
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
434
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
435
+
description: None,
436
+
required: Some(
437
+
vec![
438
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
439
+
::jacquard_common::smol_str::SmolStr::new_static("subject")
440
+
],
441
+
),
442
+
nullable: None,
443
+
properties: {
444
+
#[allow(unused_mut)]
445
+
let mut map = ::std::collections::BTreeMap::new();
446
+
map.insert(
447
+
::jacquard_common::smol_str::SmolStr::new_static("flat"),
448
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
449
+
description: None,
450
+
default: None,
451
+
r#const: None,
452
+
}),
453
+
);
454
+
map.insert(
455
+
::jacquard_common::smol_str::SmolStr::new_static("subject"),
456
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
457
+
description: Some(
458
+
::jacquard_common::CowStr::new_static(
459
+
"AT-URI pointing to a place.wisp.subfs record containing this subtree.",
460
+
),
461
+
),
462
+
format: Some(
463
+
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
464
+
),
465
+
default: None,
466
+
min_length: None,
467
+
max_length: None,
468
+
min_graphemes: None,
469
+
max_graphemes: None,
470
+
r#enum: None,
471
+
r#const: None,
472
+
known_values: None,
473
+
}),
474
+
);
475
+
map.insert(
476
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
477
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
478
+
description: None,
479
+
format: None,
480
+
default: None,
481
+
min_length: None,
482
+
max_length: None,
483
+
min_graphemes: None,
484
+
max_graphemes: None,
485
+
r#enum: None,
486
+
r#const: None,
487
+
known_values: None,
488
+
}),
489
+
);
490
+
map
491
+
},
492
+
}),
493
+
);
494
+
map
495
+
},
496
+
}
497
+
}
498
+
499
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
500
+
fn nsid() -> &'static str {
501
+
"place.wisp.fs"
502
+
}
503
+
fn def_name() -> &'static str {
504
+
"directory"
505
+
}
506
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
507
+
lexicon_doc_place_wisp_fs()
508
+
}
509
+
fn validate(
510
+
&self,
511
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
512
+
{
513
+
let value = &self.entries;
514
+
#[allow(unused_comparisons)]
515
+
if value.len() > 500usize {
516
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
517
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
518
+
"entries",
519
+
),
520
+
max: 500usize,
521
+
actual: value.len(),
522
+
});
523
+
}
524
+
}
525
+
Ok(())
526
+
}
527
+
}
528
+
529
+
#[jacquard_derive::lexicon]
530
+
#[derive(
531
+
serde::Serialize,
532
+
serde::Deserialize,
533
+
Debug,
534
+
Clone,
535
+
PartialEq,
536
+
Eq,
537
+
jacquard_derive::IntoStatic
538
+
)]
539
+
#[serde(rename_all = "camelCase")]
540
+
pub struct Entry<'a> {
541
+
#[serde(borrow)]
542
+
pub name: jacquard_common::CowStr<'a>,
543
+
#[serde(borrow)]
544
+
pub node: EntryNode<'a>,
545
+
}
546
+
547
+
pub mod entry_state {
548
+
549
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
550
+
#[allow(unused)]
551
+
use ::core::marker::PhantomData;
552
+
mod sealed {
553
+
pub trait Sealed {}
554
+
}
555
+
/// State trait tracking which required fields have been set
556
+
pub trait State: sealed::Sealed {
557
+
type Node;
558
+
type Name;
559
+
}
560
+
/// Empty state - all required fields are unset
561
+
pub struct Empty(());
562
+
impl sealed::Sealed for Empty {}
563
+
impl State for Empty {
564
+
type Node = Unset;
565
+
type Name = Unset;
566
+
}
567
+
///State transition - sets the `node` field to Set
568
+
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
569
+
impl<S: State> sealed::Sealed for SetNode<S> {}
570
+
impl<S: State> State for SetNode<S> {
571
+
type Node = Set<members::node>;
572
+
type Name = S::Name;
573
+
}
574
+
///State transition - sets the `name` field to Set
575
+
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
576
+
impl<S: State> sealed::Sealed for SetName<S> {}
577
+
impl<S: State> State for SetName<S> {
578
+
type Node = S::Node;
579
+
type Name = Set<members::name>;
580
+
}
581
+
/// Marker types for field names
582
+
#[allow(non_camel_case_types)]
583
+
pub mod members {
584
+
///Marker type for the `node` field
585
+
pub struct node(());
586
+
///Marker type for the `name` field
587
+
pub struct name(());
588
+
}
589
+
}
590
+
591
+
/// Builder for constructing an instance of this type
592
+
pub struct EntryBuilder<'a, S: entry_state::State> {
593
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
594
+
__unsafe_private_named: (
595
+
::core::option::Option<jacquard_common::CowStr<'a>>,
596
+
::core::option::Option<EntryNode<'a>>,
597
+
),
598
+
_phantom: ::core::marker::PhantomData<&'a ()>,
599
+
}
600
+
601
+
impl<'a> Entry<'a> {
602
+
/// Create a new builder for this type
603
+
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
604
+
EntryBuilder::new()
605
+
}
606
+
}
607
+
608
+
impl<'a> EntryBuilder<'a, entry_state::Empty> {
609
+
/// Create a new builder with all fields unset
610
+
pub fn new() -> Self {
611
+
EntryBuilder {
612
+
_phantom_state: ::core::marker::PhantomData,
613
+
__unsafe_private_named: (None, None),
614
+
_phantom: ::core::marker::PhantomData,
615
+
}
616
+
}
617
+
}
618
+
619
+
impl<'a, S> EntryBuilder<'a, S>
620
+
where
621
+
S: entry_state::State,
622
+
S::Name: entry_state::IsUnset,
623
+
{
624
+
/// Set the `name` field (required)
625
+
pub fn name(
626
+
mut self,
627
+
value: impl Into<jacquard_common::CowStr<'a>>,
628
+
) -> EntryBuilder<'a, entry_state::SetName<S>> {
629
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
630
+
EntryBuilder {
631
+
_phantom_state: ::core::marker::PhantomData,
632
+
__unsafe_private_named: self.__unsafe_private_named,
633
+
_phantom: ::core::marker::PhantomData,
634
+
}
635
+
}
636
+
}
637
+
638
+
impl<'a, S> EntryBuilder<'a, S>
639
+
where
640
+
S: entry_state::State,
641
+
S::Node: entry_state::IsUnset,
642
+
{
643
+
/// Set the `node` field (required)
644
+
pub fn node(
645
+
mut self,
646
+
value: impl Into<EntryNode<'a>>,
647
+
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
648
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
649
+
EntryBuilder {
650
+
_phantom_state: ::core::marker::PhantomData,
651
+
__unsafe_private_named: self.__unsafe_private_named,
652
+
_phantom: ::core::marker::PhantomData,
653
+
}
654
+
}
655
+
}
656
+
657
+
impl<'a, S> EntryBuilder<'a, S>
658
+
where
659
+
S: entry_state::State,
660
+
S::Node: entry_state::IsSet,
661
+
S::Name: entry_state::IsSet,
662
+
{
663
+
/// Build the final struct
664
+
pub fn build(self) -> Entry<'a> {
665
+
Entry {
666
+
name: self.__unsafe_private_named.0.unwrap(),
667
+
node: self.__unsafe_private_named.1.unwrap(),
668
+
extra_data: Default::default(),
669
+
}
670
+
}
671
+
/// Build the final struct with custom extra_data
672
+
pub fn build_with_data(
673
+
self,
674
+
extra_data: std::collections::BTreeMap<
675
+
jacquard_common::smol_str::SmolStr,
676
+
jacquard_common::types::value::Data<'a>,
677
+
>,
678
+
) -> Entry<'a> {
679
+
Entry {
680
+
name: self.__unsafe_private_named.0.unwrap(),
681
+
node: self.__unsafe_private_named.1.unwrap(),
682
+
extra_data: Some(extra_data),
683
+
}
684
+
}
685
+
}
686
+
687
+
#[jacquard_derive::open_union]
688
+
#[derive(
689
+
serde::Serialize,
690
+
serde::Deserialize,
691
+
Debug,
692
+
Clone,
693
+
PartialEq,
694
+
Eq,
695
+
jacquard_derive::IntoStatic
696
+
)]
697
+
#[serde(tag = "$type")]
698
+
#[serde(bound(deserialize = "'de: 'a"))]
699
+
pub enum EntryNode<'a> {
700
+
#[serde(rename = "place.wisp.fs#file")]
701
+
File(Box<crate::place_wisp::fs::File<'a>>),
702
+
#[serde(rename = "place.wisp.fs#directory")]
703
+
Directory(Box<crate::place_wisp::fs::Directory<'a>>),
704
+
#[serde(rename = "place.wisp.fs#subfs")]
705
+
Subfs(Box<crate::place_wisp::fs::Subfs<'a>>),
706
+
}
707
+
708
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
709
+
fn nsid() -> &'static str {
710
+
"place.wisp.fs"
711
+
}
712
+
fn def_name() -> &'static str {
713
+
"entry"
714
+
}
715
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
716
+
lexicon_doc_place_wisp_fs()
717
+
}
718
+
fn validate(
719
+
&self,
720
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
721
+
{
722
+
let value = &self.name;
723
+
#[allow(unused_comparisons)]
724
+
if <str>::len(value.as_ref()) > 255usize {
725
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
726
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
727
+
"name",
728
+
),
729
+
max: 255usize,
730
+
actual: <str>::len(value.as_ref()),
731
+
});
732
+
}
733
+
}
734
+
Ok(())
735
+
}
736
+
}
737
+
738
+
#[jacquard_derive::lexicon]
739
+
#[derive(
740
+
serde::Serialize,
741
+
serde::Deserialize,
742
+
Debug,
743
+
Clone,
744
+
PartialEq,
745
+
Eq,
746
+
jacquard_derive::IntoStatic
747
+
)]
748
+
#[serde(rename_all = "camelCase")]
749
+
pub struct File<'a> {
750
+
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
751
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
752
+
pub base64: std::option::Option<bool>,
753
+
/// Content blob ref
754
+
#[serde(borrow)]
755
+
pub blob: jacquard_common::types::blob::BlobRef<'a>,
756
+
/// Content encoding (e.g., gzip for compressed files)
757
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
758
+
#[serde(borrow)]
759
+
pub encoding: std::option::Option<jacquard_common::CowStr<'a>>,
760
+
/// Original MIME type before compression
761
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
762
+
#[serde(borrow)]
763
+
pub mime_type: std::option::Option<jacquard_common::CowStr<'a>>,
764
+
#[serde(borrow)]
765
+
pub r#type: jacquard_common::CowStr<'a>,
766
+
}
767
+
768
+
pub mod file_state {
769
+
770
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
771
+
#[allow(unused)]
772
+
use ::core::marker::PhantomData;
773
+
mod sealed {
774
+
pub trait Sealed {}
775
+
}
776
+
/// State trait tracking which required fields have been set
777
+
pub trait State: sealed::Sealed {
778
+
type Type;
779
+
type Blob;
780
+
}
781
+
/// Empty state - all required fields are unset
782
+
pub struct Empty(());
783
+
impl sealed::Sealed for Empty {}
784
+
impl State for Empty {
785
+
type Type = Unset;
786
+
type Blob = Unset;
787
+
}
788
+
///State transition - sets the `type` field to Set
789
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
790
+
impl<S: State> sealed::Sealed for SetType<S> {}
791
+
impl<S: State> State for SetType<S> {
792
+
type Type = Set<members::r#type>;
793
+
type Blob = S::Blob;
794
+
}
795
+
///State transition - sets the `blob` field to Set
796
+
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
797
+
impl<S: State> sealed::Sealed for SetBlob<S> {}
798
+
impl<S: State> State for SetBlob<S> {
799
+
type Type = S::Type;
800
+
type Blob = Set<members::blob>;
801
+
}
802
+
/// Marker types for field names
803
+
#[allow(non_camel_case_types)]
804
+
pub mod members {
805
+
///Marker type for the `type` field
806
+
pub struct r#type(());
807
+
///Marker type for the `blob` field
808
+
pub struct blob(());
809
+
}
810
+
}
811
+
812
+
/// Builder for constructing an instance of this type
813
+
pub struct FileBuilder<'a, S: file_state::State> {
814
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
815
+
__unsafe_private_named: (
816
+
::core::option::Option<bool>,
817
+
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
818
+
::core::option::Option<jacquard_common::CowStr<'a>>,
819
+
::core::option::Option<jacquard_common::CowStr<'a>>,
820
+
::core::option::Option<jacquard_common::CowStr<'a>>,
821
+
),
822
+
_phantom: ::core::marker::PhantomData<&'a ()>,
823
+
}
824
+
825
+
impl<'a> File<'a> {
826
+
/// Create a new builder for this type
827
+
pub fn new() -> FileBuilder<'a, file_state::Empty> {
828
+
FileBuilder::new()
829
+
}
830
+
}
831
+
832
+
impl<'a> FileBuilder<'a, file_state::Empty> {
833
+
/// Create a new builder with all fields unset
834
+
pub fn new() -> Self {
835
+
FileBuilder {
836
+
_phantom_state: ::core::marker::PhantomData,
837
+
__unsafe_private_named: (None, None, None, None, None),
838
+
_phantom: ::core::marker::PhantomData,
839
+
}
840
+
}
841
+
}
842
+
843
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
844
+
/// Set the `base64` field (optional)
845
+
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
846
+
self.__unsafe_private_named.0 = value.into();
847
+
self
848
+
}
849
+
/// Set the `base64` field to an Option value (optional)
850
+
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
851
+
self.__unsafe_private_named.0 = value;
852
+
self
853
+
}
854
+
}
855
+
856
+
impl<'a, S> FileBuilder<'a, S>
857
+
where
858
+
S: file_state::State,
859
+
S::Blob: file_state::IsUnset,
860
+
{
861
+
/// Set the `blob` field (required)
862
+
pub fn blob(
863
+
mut self,
864
+
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
865
+
) -> FileBuilder<'a, file_state::SetBlob<S>> {
866
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
867
+
FileBuilder {
868
+
_phantom_state: ::core::marker::PhantomData,
869
+
__unsafe_private_named: self.__unsafe_private_named,
870
+
_phantom: ::core::marker::PhantomData,
871
+
}
872
+
}
873
+
}
874
+
875
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
876
+
/// Set the `encoding` field (optional)
877
+
pub fn encoding(
878
+
mut self,
879
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
880
+
) -> Self {
881
+
self.__unsafe_private_named.2 = value.into();
882
+
self
883
+
}
884
+
/// Set the `encoding` field to an Option value (optional)
885
+
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
886
+
self.__unsafe_private_named.2 = value;
887
+
self
888
+
}
889
+
}
890
+
891
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
892
+
/// Set the `mimeType` field (optional)
893
+
pub fn mime_type(
894
+
mut self,
895
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
896
+
) -> Self {
897
+
self.__unsafe_private_named.3 = value.into();
898
+
self
899
+
}
900
+
/// Set the `mimeType` field to an Option value (optional)
901
+
pub fn maybe_mime_type(
902
+
mut self,
903
+
value: Option<jacquard_common::CowStr<'a>>,
904
+
) -> Self {
905
+
self.__unsafe_private_named.3 = value;
906
+
self
907
+
}
908
+
}
909
+
910
+
impl<'a, S> FileBuilder<'a, S>
911
+
where
912
+
S: file_state::State,
913
+
S::Type: file_state::IsUnset,
914
+
{
915
+
/// Set the `type` field (required)
916
+
pub fn r#type(
917
+
mut self,
918
+
value: impl Into<jacquard_common::CowStr<'a>>,
919
+
) -> FileBuilder<'a, file_state::SetType<S>> {
920
+
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
921
+
FileBuilder {
922
+
_phantom_state: ::core::marker::PhantomData,
923
+
__unsafe_private_named: self.__unsafe_private_named,
924
+
_phantom: ::core::marker::PhantomData,
925
+
}
926
+
}
927
+
}
928
+
929
+
impl<'a, S> FileBuilder<'a, S>
930
+
where
931
+
S: file_state::State,
932
+
S::Type: file_state::IsSet,
933
+
S::Blob: file_state::IsSet,
934
+
{
935
+
/// Build the final struct
936
+
pub fn build(self) -> File<'a> {
937
+
File {
938
+
base64: self.__unsafe_private_named.0,
939
+
blob: self.__unsafe_private_named.1.unwrap(),
940
+
encoding: self.__unsafe_private_named.2,
941
+
mime_type: self.__unsafe_private_named.3,
942
+
r#type: self.__unsafe_private_named.4.unwrap(),
943
+
extra_data: Default::default(),
944
+
}
945
+
}
946
+
/// Build the final struct with custom extra_data
947
+
pub fn build_with_data(
948
+
self,
949
+
extra_data: std::collections::BTreeMap<
950
+
jacquard_common::smol_str::SmolStr,
951
+
jacquard_common::types::value::Data<'a>,
952
+
>,
953
+
) -> File<'a> {
954
+
File {
955
+
base64: self.__unsafe_private_named.0,
956
+
blob: self.__unsafe_private_named.1.unwrap(),
957
+
encoding: self.__unsafe_private_named.2,
958
+
mime_type: self.__unsafe_private_named.3,
959
+
r#type: self.__unsafe_private_named.4.unwrap(),
960
+
extra_data: Some(extra_data),
961
+
}
962
+
}
963
+
}
964
+
965
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
966
+
fn nsid() -> &'static str {
967
+
"place.wisp.fs"
968
+
}
969
+
fn def_name() -> &'static str {
970
+
"file"
971
+
}
972
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
973
+
lexicon_doc_place_wisp_fs()
974
+
}
975
+
fn validate(
976
+
&self,
977
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
978
+
Ok(())
979
+
}
980
+
}
981
+
982
+
/// Virtual filesystem manifest for a Wisp site
983
+
#[jacquard_derive::lexicon]
984
+
#[derive(
985
+
serde::Serialize,
986
+
serde::Deserialize,
987
+
Debug,
988
+
Clone,
989
+
PartialEq,
990
+
Eq,
991
+
jacquard_derive::IntoStatic
992
+
)]
993
+
#[serde(rename_all = "camelCase")]
994
+
pub struct Fs<'a> {
995
+
pub created_at: jacquard_common::types::string::Datetime,
996
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
997
+
pub file_count: std::option::Option<i64>,
998
+
#[serde(borrow)]
999
+
pub root: crate::place_wisp::fs::Directory<'a>,
1000
+
#[serde(borrow)]
1001
+
pub site: jacquard_common::CowStr<'a>,
1002
+
}
1003
+
1004
+
pub mod fs_state {
1005
+
1006
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1007
+
#[allow(unused)]
1008
+
use ::core::marker::PhantomData;
1009
+
mod sealed {
1010
+
pub trait Sealed {}
1011
+
}
1012
+
/// State trait tracking which required fields have been set
1013
+
pub trait State: sealed::Sealed {
1014
+
type CreatedAt;
1015
+
type Site;
1016
+
type Root;
1017
+
}
1018
+
/// Empty state - all required fields are unset
1019
+
pub struct Empty(());
1020
+
impl sealed::Sealed for Empty {}
1021
+
impl State for Empty {
1022
+
type CreatedAt = Unset;
1023
+
type Site = Unset;
1024
+
type Root = Unset;
1025
+
}
1026
+
///State transition - sets the `created_at` field to Set
1027
+
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1028
+
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1029
+
impl<S: State> State for SetCreatedAt<S> {
1030
+
type CreatedAt = Set<members::created_at>;
1031
+
type Site = S::Site;
1032
+
type Root = S::Root;
1033
+
}
1034
+
///State transition - sets the `site` field to Set
1035
+
pub struct SetSite<S: State = Empty>(PhantomData<fn() -> S>);
1036
+
impl<S: State> sealed::Sealed for SetSite<S> {}
1037
+
impl<S: State> State for SetSite<S> {
1038
+
type CreatedAt = S::CreatedAt;
1039
+
type Site = Set<members::site>;
1040
+
type Root = S::Root;
1041
+
}
1042
+
///State transition - sets the `root` field to Set
1043
+
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1044
+
impl<S: State> sealed::Sealed for SetRoot<S> {}
1045
+
impl<S: State> State for SetRoot<S> {
1046
+
type CreatedAt = S::CreatedAt;
1047
+
type Site = S::Site;
1048
+
type Root = Set<members::root>;
1049
+
}
1050
+
/// Marker types for field names
1051
+
#[allow(non_camel_case_types)]
1052
+
pub mod members {
1053
+
///Marker type for the `created_at` field
1054
+
pub struct created_at(());
1055
+
///Marker type for the `site` field
1056
+
pub struct site(());
1057
+
///Marker type for the `root` field
1058
+
pub struct root(());
1059
+
}
1060
+
}
1061
+
1062
+
/// Builder for constructing an instance of this type
1063
+
pub struct FsBuilder<'a, S: fs_state::State> {
1064
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1065
+
__unsafe_private_named: (
1066
+
::core::option::Option<jacquard_common::types::string::Datetime>,
1067
+
::core::option::Option<i64>,
1068
+
::core::option::Option<crate::place_wisp::fs::Directory<'a>>,
1069
+
::core::option::Option<jacquard_common::CowStr<'a>>,
1070
+
),
1071
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1072
+
}
1073
+
1074
+
impl<'a> Fs<'a> {
1075
+
/// Create a new builder for this type
1076
+
pub fn new() -> FsBuilder<'a, fs_state::Empty> {
1077
+
FsBuilder::new()
1078
+
}
1079
+
}
1080
+
1081
+
impl<'a> FsBuilder<'a, fs_state::Empty> {
1082
+
/// Create a new builder with all fields unset
1083
+
pub fn new() -> Self {
1084
+
FsBuilder {
1085
+
_phantom_state: ::core::marker::PhantomData,
1086
+
__unsafe_private_named: (None, None, None, None),
1087
+
_phantom: ::core::marker::PhantomData,
1088
+
}
1089
+
}
1090
+
}
1091
+
1092
+
impl<'a, S> FsBuilder<'a, S>
1093
+
where
1094
+
S: fs_state::State,
1095
+
S::CreatedAt: fs_state::IsUnset,
1096
+
{
1097
+
/// Set the `createdAt` field (required)
1098
+
pub fn created_at(
1099
+
mut self,
1100
+
value: impl Into<jacquard_common::types::string::Datetime>,
1101
+
) -> FsBuilder<'a, fs_state::SetCreatedAt<S>> {
1102
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1103
+
FsBuilder {
1104
+
_phantom_state: ::core::marker::PhantomData,
1105
+
__unsafe_private_named: self.__unsafe_private_named,
1106
+
_phantom: ::core::marker::PhantomData,
1107
+
}
1108
+
}
1109
+
}
1110
+
1111
+
impl<'a, S: fs_state::State> FsBuilder<'a, S> {
1112
+
/// Set the `fileCount` field (optional)
1113
+
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1114
+
self.__unsafe_private_named.1 = value.into();
1115
+
self
1116
+
}
1117
+
/// Set the `fileCount` field to an Option value (optional)
1118
+
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1119
+
self.__unsafe_private_named.1 = value;
1120
+
self
1121
+
}
1122
+
}
1123
+
1124
+
impl<'a, S> FsBuilder<'a, S>
1125
+
where
1126
+
S: fs_state::State,
1127
+
S::Root: fs_state::IsUnset,
1128
+
{
1129
+
/// Set the `root` field (required)
1130
+
pub fn root(
1131
+
mut self,
1132
+
value: impl Into<crate::place_wisp::fs::Directory<'a>>,
1133
+
) -> FsBuilder<'a, fs_state::SetRoot<S>> {
1134
+
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1135
+
FsBuilder {
1136
+
_phantom_state: ::core::marker::PhantomData,
1137
+
__unsafe_private_named: self.__unsafe_private_named,
1138
+
_phantom: ::core::marker::PhantomData,
1139
+
}
1140
+
}
1141
+
}
1142
+
1143
+
impl<'a, S> FsBuilder<'a, S>
1144
+
where
1145
+
S: fs_state::State,
1146
+
S::Site: fs_state::IsUnset,
1147
+
{
1148
+
/// Set the `site` field (required)
1149
+
pub fn site(
1150
+
mut self,
1151
+
value: impl Into<jacquard_common::CowStr<'a>>,
1152
+
) -> FsBuilder<'a, fs_state::SetSite<S>> {
1153
+
self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into());
1154
+
FsBuilder {
1155
+
_phantom_state: ::core::marker::PhantomData,
1156
+
__unsafe_private_named: self.__unsafe_private_named,
1157
+
_phantom: ::core::marker::PhantomData,
1158
+
}
1159
+
}
1160
+
}
1161
+
1162
+
impl<'a, S> FsBuilder<'a, S>
1163
+
where
1164
+
S: fs_state::State,
1165
+
S::CreatedAt: fs_state::IsSet,
1166
+
S::Site: fs_state::IsSet,
1167
+
S::Root: fs_state::IsSet,
1168
+
{
1169
+
/// Build the final struct
1170
+
pub fn build(self) -> Fs<'a> {
1171
+
Fs {
1172
+
created_at: self.__unsafe_private_named.0.unwrap(),
1173
+
file_count: self.__unsafe_private_named.1,
1174
+
root: self.__unsafe_private_named.2.unwrap(),
1175
+
site: self.__unsafe_private_named.3.unwrap(),
1176
+
extra_data: Default::default(),
1177
+
}
1178
+
}
1179
+
/// Build the final struct with custom extra_data
1180
+
pub fn build_with_data(
1181
+
self,
1182
+
extra_data: std::collections::BTreeMap<
1183
+
jacquard_common::smol_str::SmolStr,
1184
+
jacquard_common::types::value::Data<'a>,
1185
+
>,
1186
+
) -> Fs<'a> {
1187
+
Fs {
1188
+
created_at: self.__unsafe_private_named.0.unwrap(),
1189
+
file_count: self.__unsafe_private_named.1,
1190
+
root: self.__unsafe_private_named.2.unwrap(),
1191
+
site: self.__unsafe_private_named.3.unwrap(),
1192
+
extra_data: Some(extra_data),
1193
+
}
1194
+
}
1195
+
}
1196
+
1197
+
impl<'a> Fs<'a> {
1198
+
pub fn uri(
1199
+
uri: impl Into<jacquard_common::CowStr<'a>>,
1200
+
) -> Result<
1201
+
jacquard_common::types::uri::RecordUri<'a, FsRecord>,
1202
+
jacquard_common::types::uri::UriError,
1203
+
> {
1204
+
jacquard_common::types::uri::RecordUri::try_from_uri(
1205
+
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1206
+
)
1207
+
}
1208
+
}
1209
+
1210
+
/// Typed wrapper for GetRecord response with this collection's record type.
1211
+
#[derive(
1212
+
serde::Serialize,
1213
+
serde::Deserialize,
1214
+
Debug,
1215
+
Clone,
1216
+
PartialEq,
1217
+
Eq,
1218
+
jacquard_derive::IntoStatic
1219
+
)]
1220
+
#[serde(rename_all = "camelCase")]
1221
+
pub struct FsGetRecordOutput<'a> {
1222
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1223
+
#[serde(borrow)]
1224
+
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1225
+
#[serde(borrow)]
1226
+
pub uri: jacquard_common::types::string::AtUri<'a>,
1227
+
#[serde(borrow)]
1228
+
pub value: Fs<'a>,
1229
+
}
1230
+
1231
+
impl From<FsGetRecordOutput<'_>> for Fs<'_> {
1232
+
fn from(output: FsGetRecordOutput<'_>) -> Self {
1233
+
use jacquard_common::IntoStatic;
1234
+
output.value.into_static()
1235
+
}
1236
+
}
1237
+
1238
+
impl jacquard_common::types::collection::Collection for Fs<'_> {
1239
+
const NSID: &'static str = "place.wisp.fs";
1240
+
type Record = FsRecord;
1241
+
}
1242
+
1243
+
/// Marker type for deserializing records from this collection.
1244
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1245
+
pub struct FsRecord;
1246
+
impl jacquard_common::xrpc::XrpcResp for FsRecord {
1247
+
const NSID: &'static str = "place.wisp.fs";
1248
+
const ENCODING: &'static str = "application/json";
1249
+
type Output<'de> = FsGetRecordOutput<'de>;
1250
+
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1251
+
}
1252
+
1253
+
impl jacquard_common::types::collection::Collection for FsRecord {
1254
+
const NSID: &'static str = "place.wisp.fs";
1255
+
type Record = FsRecord;
1256
+
}
1257
+
1258
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Fs<'a> {
1259
+
fn nsid() -> &'static str {
1260
+
"place.wisp.fs"
1261
+
}
1262
+
fn def_name() -> &'static str {
1263
+
"main"
1264
+
}
1265
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1266
+
lexicon_doc_place_wisp_fs()
1267
+
}
1268
+
fn validate(
1269
+
&self,
1270
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1271
+
if let Some(ref value) = self.file_count {
1272
+
if *value > 1000i64 {
1273
+
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1274
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1275
+
"file_count",
1276
+
),
1277
+
max: 1000i64,
1278
+
actual: *value,
1279
+
});
1280
+
}
1281
+
}
1282
+
if let Some(ref value) = self.file_count {
1283
+
if *value < 0i64 {
1284
+
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1285
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1286
+
"file_count",
1287
+
),
1288
+
min: 0i64,
1289
+
actual: *value,
1290
+
});
1291
+
}
1292
+
}
1293
+
Ok(())
1294
+
}
1295
+
}
1296
+
1297
+
#[jacquard_derive::lexicon]
1298
+
#[derive(
1299
+
serde::Serialize,
1300
+
serde::Deserialize,
1301
+
Debug,
1302
+
Clone,
1303
+
PartialEq,
1304
+
Eq,
1305
+
jacquard_derive::IntoStatic
1306
+
)]
1307
+
#[serde(rename_all = "camelCase")]
1308
+
pub struct Subfs<'a> {
1309
+
/// 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.
1310
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1311
+
pub flat: std::option::Option<bool>,
1312
+
/// AT-URI pointing to a place.wisp.subfs record containing this subtree.
1313
+
#[serde(borrow)]
1314
+
pub subject: jacquard_common::types::string::AtUri<'a>,
1315
+
#[serde(borrow)]
1316
+
pub r#type: jacquard_common::CowStr<'a>,
1317
+
}
1318
+
1319
+
pub mod subfs_state {
1320
+
1321
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1322
+
#[allow(unused)]
1323
+
use ::core::marker::PhantomData;
1324
+
mod sealed {
1325
+
pub trait Sealed {}
1326
+
}
1327
+
/// State trait tracking which required fields have been set
1328
+
pub trait State: sealed::Sealed {
1329
+
type Type;
1330
+
type Subject;
1331
+
}
1332
+
/// Empty state - all required fields are unset
1333
+
pub struct Empty(());
1334
+
impl sealed::Sealed for Empty {}
1335
+
impl State for Empty {
1336
+
type Type = Unset;
1337
+
type Subject = Unset;
1338
+
}
1339
+
///State transition - sets the `type` field to Set
1340
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1341
+
impl<S: State> sealed::Sealed for SetType<S> {}
1342
+
impl<S: State> State for SetType<S> {
1343
+
type Type = Set<members::r#type>;
1344
+
type Subject = S::Subject;
1345
+
}
1346
+
///State transition - sets the `subject` field to Set
1347
+
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1348
+
impl<S: State> sealed::Sealed for SetSubject<S> {}
1349
+
impl<S: State> State for SetSubject<S> {
1350
+
type Type = S::Type;
1351
+
type Subject = Set<members::subject>;
1352
+
}
1353
+
/// Marker types for field names
1354
+
#[allow(non_camel_case_types)]
1355
+
pub mod members {
1356
+
///Marker type for the `type` field
1357
+
pub struct r#type(());
1358
+
///Marker type for the `subject` field
1359
+
pub struct subject(());
1360
+
}
1361
+
}
1362
+
1363
+
/// Builder for constructing an instance of this type
1364
+
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1365
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1366
+
__unsafe_private_named: (
1367
+
::core::option::Option<bool>,
1368
+
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1369
+
::core::option::Option<jacquard_common::CowStr<'a>>,
1370
+
),
1371
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1372
+
}
1373
+
1374
+
impl<'a> Subfs<'a> {
1375
+
/// Create a new builder for this type
1376
+
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1377
+
SubfsBuilder::new()
1378
+
}
1379
+
}
1380
+
1381
+
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1382
+
/// Create a new builder with all fields unset
1383
+
pub fn new() -> Self {
1384
+
SubfsBuilder {
1385
+
_phantom_state: ::core::marker::PhantomData,
1386
+
__unsafe_private_named: (None, None, None),
1387
+
_phantom: ::core::marker::PhantomData,
1388
+
}
1389
+
}
1390
+
}
1391
+
1392
+
impl<'a, S: subfs_state::State> SubfsBuilder<'a, S> {
1393
+
/// Set the `flat` field (optional)
1394
+
pub fn flat(mut self, value: impl Into<Option<bool>>) -> Self {
1395
+
self.__unsafe_private_named.0 = value.into();
1396
+
self
1397
+
}
1398
+
/// Set the `flat` field to an Option value (optional)
1399
+
pub fn maybe_flat(mut self, value: Option<bool>) -> Self {
1400
+
self.__unsafe_private_named.0 = value;
1401
+
self
1402
+
}
1403
+
}
1404
+
1405
+
impl<'a, S> SubfsBuilder<'a, S>
1406
+
where
1407
+
S: subfs_state::State,
1408
+
S::Subject: subfs_state::IsUnset,
1409
+
{
1410
+
/// Set the `subject` field (required)
1411
+
pub fn subject(
1412
+
mut self,
1413
+
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1414
+
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1415
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1416
+
SubfsBuilder {
1417
+
_phantom_state: ::core::marker::PhantomData,
1418
+
__unsafe_private_named: self.__unsafe_private_named,
1419
+
_phantom: ::core::marker::PhantomData,
1420
+
}
1421
+
}
1422
+
}
1423
+
1424
+
impl<'a, S> SubfsBuilder<'a, S>
1425
+
where
1426
+
S: subfs_state::State,
1427
+
S::Type: subfs_state::IsUnset,
1428
+
{
1429
+
/// Set the `type` field (required)
1430
+
pub fn r#type(
1431
+
mut self,
1432
+
value: impl Into<jacquard_common::CowStr<'a>>,
1433
+
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1434
+
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1435
+
SubfsBuilder {
1436
+
_phantom_state: ::core::marker::PhantomData,
1437
+
__unsafe_private_named: self.__unsafe_private_named,
1438
+
_phantom: ::core::marker::PhantomData,
1439
+
}
1440
+
}
1441
+
}
1442
+
1443
+
impl<'a, S> SubfsBuilder<'a, S>
1444
+
where
1445
+
S: subfs_state::State,
1446
+
S::Type: subfs_state::IsSet,
1447
+
S::Subject: subfs_state::IsSet,
1448
+
{
1449
+
/// Build the final struct
1450
+
pub fn build(self) -> Subfs<'a> {
1451
+
Subfs {
1452
+
flat: self.__unsafe_private_named.0,
1453
+
subject: self.__unsafe_private_named.1.unwrap(),
1454
+
r#type: self.__unsafe_private_named.2.unwrap(),
1455
+
extra_data: Default::default(),
1456
+
}
1457
+
}
1458
+
/// Build the final struct with custom extra_data
1459
+
pub fn build_with_data(
1460
+
self,
1461
+
extra_data: std::collections::BTreeMap<
1462
+
jacquard_common::smol_str::SmolStr,
1463
+
jacquard_common::types::value::Data<'a>,
1464
+
>,
1465
+
) -> Subfs<'a> {
1466
+
Subfs {
1467
+
flat: self.__unsafe_private_named.0,
1468
+
subject: self.__unsafe_private_named.1.unwrap(),
1469
+
r#type: self.__unsafe_private_named.2.unwrap(),
1470
+
extra_data: Some(extra_data),
1471
+
}
1472
+
}
1473
+
}
1474
+
1475
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1476
+
fn nsid() -> &'static str {
1477
+
"place.wisp.fs"
1478
+
}
1479
+
fn def_name() -> &'static str {
1480
+
"subfs"
1481
+
}
1482
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1483
+
lexicon_doc_place_wisp_fs()
1484
+
}
1485
+
fn validate(
1486
+
&self,
1487
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1488
+
Ok(())
1489
+
}
1490
+
}
+653
cli/crates/lexicons/src/place_wisp/settings.rs
+653
cli/crates/lexicons/src/place_wisp/settings.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// Lexicon: place.wisp.settings
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
/// Custom HTTP header configuration
9
+
#[jacquard_derive::lexicon]
10
+
#[derive(
11
+
serde::Serialize,
12
+
serde::Deserialize,
13
+
Debug,
14
+
Clone,
15
+
PartialEq,
16
+
Eq,
17
+
jacquard_derive::IntoStatic,
18
+
Default
19
+
)]
20
+
#[serde(rename_all = "camelCase")]
21
+
pub struct CustomHeader<'a> {
22
+
/// HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')
23
+
#[serde(borrow)]
24
+
pub name: jacquard_common::CowStr<'a>,
25
+
/// Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.
26
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
27
+
#[serde(borrow)]
28
+
pub path: std::option::Option<jacquard_common::CowStr<'a>>,
29
+
/// HTTP header value
30
+
#[serde(borrow)]
31
+
pub value: jacquard_common::CowStr<'a>,
32
+
}
33
+
34
+
fn lexicon_doc_place_wisp_settings() -> ::jacquard_lexicon::lexicon::LexiconDoc<
35
+
'static,
36
+
> {
37
+
::jacquard_lexicon::lexicon::LexiconDoc {
38
+
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
39
+
id: ::jacquard_common::CowStr::new_static("place.wisp.settings"),
40
+
revision: None,
41
+
description: None,
42
+
defs: {
43
+
let mut map = ::std::collections::BTreeMap::new();
44
+
map.insert(
45
+
::jacquard_common::smol_str::SmolStr::new_static("customHeader"),
46
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
47
+
description: Some(
48
+
::jacquard_common::CowStr::new_static(
49
+
"Custom HTTP header configuration",
50
+
),
51
+
),
52
+
required: Some(
53
+
vec![
54
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
55
+
::jacquard_common::smol_str::SmolStr::new_static("value")
56
+
],
57
+
),
58
+
nullable: None,
59
+
properties: {
60
+
#[allow(unused_mut)]
61
+
let mut map = ::std::collections::BTreeMap::new();
62
+
map.insert(
63
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
64
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
65
+
description: Some(
66
+
::jacquard_common::CowStr::new_static(
67
+
"HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
68
+
),
69
+
),
70
+
format: None,
71
+
default: None,
72
+
min_length: None,
73
+
max_length: Some(100usize),
74
+
min_graphemes: None,
75
+
max_graphemes: None,
76
+
r#enum: None,
77
+
r#const: None,
78
+
known_values: None,
79
+
}),
80
+
);
81
+
map.insert(
82
+
::jacquard_common::smol_str::SmolStr::new_static("path"),
83
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
84
+
description: Some(
85
+
::jacquard_common::CowStr::new_static(
86
+
"Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
87
+
),
88
+
),
89
+
format: None,
90
+
default: None,
91
+
min_length: None,
92
+
max_length: Some(500usize),
93
+
min_graphemes: None,
94
+
max_graphemes: None,
95
+
r#enum: None,
96
+
r#const: None,
97
+
known_values: None,
98
+
}),
99
+
);
100
+
map.insert(
101
+
::jacquard_common::smol_str::SmolStr::new_static("value"),
102
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
103
+
description: Some(
104
+
::jacquard_common::CowStr::new_static("HTTP header value"),
105
+
),
106
+
format: None,
107
+
default: None,
108
+
min_length: None,
109
+
max_length: Some(1000usize),
110
+
min_graphemes: None,
111
+
max_graphemes: None,
112
+
r#enum: None,
113
+
r#const: None,
114
+
known_values: None,
115
+
}),
116
+
);
117
+
map
118
+
},
119
+
}),
120
+
);
121
+
map.insert(
122
+
::jacquard_common::smol_str::SmolStr::new_static("main"),
123
+
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
124
+
description: Some(
125
+
::jacquard_common::CowStr::new_static(
126
+
"Configuration settings for a static site hosted on wisp.place",
127
+
),
128
+
),
129
+
key: Some(::jacquard_common::CowStr::new_static("any")),
130
+
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
131
+
description: None,
132
+
required: None,
133
+
nullable: None,
134
+
properties: {
135
+
#[allow(unused_mut)]
136
+
let mut map = ::std::collections::BTreeMap::new();
137
+
map.insert(
138
+
::jacquard_common::smol_str::SmolStr::new_static(
139
+
"cleanUrls",
140
+
),
141
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
142
+
description: None,
143
+
default: None,
144
+
r#const: None,
145
+
}),
146
+
);
147
+
map.insert(
148
+
::jacquard_common::smol_str::SmolStr::new_static(
149
+
"custom404",
150
+
),
151
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
152
+
description: Some(
153
+
::jacquard_common::CowStr::new_static(
154
+
"Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
155
+
),
156
+
),
157
+
format: None,
158
+
default: None,
159
+
min_length: None,
160
+
max_length: Some(500usize),
161
+
min_graphemes: None,
162
+
max_graphemes: None,
163
+
r#enum: None,
164
+
r#const: None,
165
+
known_values: None,
166
+
}),
167
+
);
168
+
map.insert(
169
+
::jacquard_common::smol_str::SmolStr::new_static(
170
+
"directoryListing",
171
+
),
172
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
173
+
description: None,
174
+
default: None,
175
+
r#const: None,
176
+
}),
177
+
);
178
+
map.insert(
179
+
::jacquard_common::smol_str::SmolStr::new_static("headers"),
180
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
181
+
description: Some(
182
+
::jacquard_common::CowStr::new_static(
183
+
"Custom HTTP headers to set on responses",
184
+
),
185
+
),
186
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
187
+
description: None,
188
+
r#ref: ::jacquard_common::CowStr::new_static(
189
+
"#customHeader",
190
+
),
191
+
}),
192
+
min_length: None,
193
+
max_length: Some(50usize),
194
+
}),
195
+
);
196
+
map.insert(
197
+
::jacquard_common::smol_str::SmolStr::new_static(
198
+
"indexFiles",
199
+
),
200
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
201
+
description: Some(
202
+
::jacquard_common::CowStr::new_static(
203
+
"Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
204
+
),
205
+
),
206
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::String(::jacquard_lexicon::lexicon::LexString {
207
+
description: None,
208
+
format: None,
209
+
default: None,
210
+
min_length: None,
211
+
max_length: Some(255usize),
212
+
min_graphemes: None,
213
+
max_graphemes: None,
214
+
r#enum: None,
215
+
r#const: None,
216
+
known_values: None,
217
+
}),
218
+
min_length: None,
219
+
max_length: Some(10usize),
220
+
}),
221
+
);
222
+
map.insert(
223
+
::jacquard_common::smol_str::SmolStr::new_static("spaMode"),
224
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
225
+
description: Some(
226
+
::jacquard_common::CowStr::new_static(
227
+
"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.",
228
+
),
229
+
),
230
+
format: None,
231
+
default: None,
232
+
min_length: None,
233
+
max_length: Some(500usize),
234
+
min_graphemes: None,
235
+
max_graphemes: None,
236
+
r#enum: None,
237
+
r#const: None,
238
+
known_values: None,
239
+
}),
240
+
);
241
+
map
242
+
},
243
+
}),
244
+
}),
245
+
);
246
+
map
247
+
},
248
+
}
249
+
}
250
+
251
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for CustomHeader<'a> {
252
+
fn nsid() -> &'static str {
253
+
"place.wisp.settings"
254
+
}
255
+
fn def_name() -> &'static str {
256
+
"customHeader"
257
+
}
258
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
259
+
lexicon_doc_place_wisp_settings()
260
+
}
261
+
fn validate(
262
+
&self,
263
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
264
+
{
265
+
let value = &self.name;
266
+
#[allow(unused_comparisons)]
267
+
if <str>::len(value.as_ref()) > 100usize {
268
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
269
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
270
+
"name",
271
+
),
272
+
max: 100usize,
273
+
actual: <str>::len(value.as_ref()),
274
+
});
275
+
}
276
+
}
277
+
if let Some(ref value) = self.path {
278
+
#[allow(unused_comparisons)]
279
+
if <str>::len(value.as_ref()) > 500usize {
280
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
281
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
282
+
"path",
283
+
),
284
+
max: 500usize,
285
+
actual: <str>::len(value.as_ref()),
286
+
});
287
+
}
288
+
}
289
+
{
290
+
let value = &self.value;
291
+
#[allow(unused_comparisons)]
292
+
if <str>::len(value.as_ref()) > 1000usize {
293
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
294
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
295
+
"value",
296
+
),
297
+
max: 1000usize,
298
+
actual: <str>::len(value.as_ref()),
299
+
});
300
+
}
301
+
}
302
+
Ok(())
303
+
}
304
+
}
305
+
306
+
/// Configuration settings for a static site hosted on wisp.place
307
+
#[jacquard_derive::lexicon]
308
+
#[derive(
309
+
serde::Serialize,
310
+
serde::Deserialize,
311
+
Debug,
312
+
Clone,
313
+
PartialEq,
314
+
Eq,
315
+
jacquard_derive::IntoStatic
316
+
)]
317
+
#[serde(rename_all = "camelCase")]
318
+
pub struct Settings<'a> {
319
+
/// Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.
320
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
321
+
pub clean_urls: std::option::Option<bool>,
322
+
/// Custom 404 error page file path. Incompatible with directoryListing and spaMode.
323
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
324
+
#[serde(borrow)]
325
+
pub custom404: std::option::Option<jacquard_common::CowStr<'a>>,
326
+
/// Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.
327
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
328
+
pub directory_listing: std::option::Option<bool>,
329
+
/// Custom HTTP headers to set on responses
330
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
331
+
#[serde(borrow)]
332
+
pub headers: std::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
333
+
/// Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.
334
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
335
+
#[serde(borrow)]
336
+
pub index_files: std::option::Option<Vec<jacquard_common::CowStr<'a>>>,
337
+
/// 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.
338
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
339
+
#[serde(borrow)]
340
+
pub spa_mode: std::option::Option<jacquard_common::CowStr<'a>>,
341
+
}
342
+
343
+
pub mod settings_state {
344
+
345
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
346
+
#[allow(unused)]
347
+
use ::core::marker::PhantomData;
348
+
mod sealed {
349
+
pub trait Sealed {}
350
+
}
351
+
/// State trait tracking which required fields have been set
352
+
pub trait State: sealed::Sealed {}
353
+
/// Empty state - all required fields are unset
354
+
pub struct Empty(());
355
+
impl sealed::Sealed for Empty {}
356
+
impl State for Empty {}
357
+
/// Marker types for field names
358
+
#[allow(non_camel_case_types)]
359
+
pub mod members {}
360
+
}
361
+
362
+
/// Builder for constructing an instance of this type
363
+
pub struct SettingsBuilder<'a, S: settings_state::State> {
364
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
365
+
__unsafe_private_named: (
366
+
::core::option::Option<bool>,
367
+
::core::option::Option<jacquard_common::CowStr<'a>>,
368
+
::core::option::Option<bool>,
369
+
::core::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
370
+
::core::option::Option<Vec<jacquard_common::CowStr<'a>>>,
371
+
::core::option::Option<jacquard_common::CowStr<'a>>,
372
+
),
373
+
_phantom: ::core::marker::PhantomData<&'a ()>,
374
+
}
375
+
376
+
impl<'a> Settings<'a> {
377
+
/// Create a new builder for this type
378
+
pub fn new() -> SettingsBuilder<'a, settings_state::Empty> {
379
+
SettingsBuilder::new()
380
+
}
381
+
}
382
+
383
+
impl<'a> SettingsBuilder<'a, settings_state::Empty> {
384
+
/// Create a new builder with all fields unset
385
+
pub fn new() -> Self {
386
+
SettingsBuilder {
387
+
_phantom_state: ::core::marker::PhantomData,
388
+
__unsafe_private_named: (None, None, None, None, None, None),
389
+
_phantom: ::core::marker::PhantomData,
390
+
}
391
+
}
392
+
}
393
+
394
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
395
+
/// Set the `cleanUrls` field (optional)
396
+
pub fn clean_urls(mut self, value: impl Into<Option<bool>>) -> Self {
397
+
self.__unsafe_private_named.0 = value.into();
398
+
self
399
+
}
400
+
/// Set the `cleanUrls` field to an Option value (optional)
401
+
pub fn maybe_clean_urls(mut self, value: Option<bool>) -> Self {
402
+
self.__unsafe_private_named.0 = value;
403
+
self
404
+
}
405
+
}
406
+
407
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
408
+
/// Set the `custom404` field (optional)
409
+
pub fn custom404(
410
+
mut self,
411
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
412
+
) -> Self {
413
+
self.__unsafe_private_named.1 = value.into();
414
+
self
415
+
}
416
+
/// Set the `custom404` field to an Option value (optional)
417
+
pub fn maybe_custom404(
418
+
mut self,
419
+
value: Option<jacquard_common::CowStr<'a>>,
420
+
) -> Self {
421
+
self.__unsafe_private_named.1 = value;
422
+
self
423
+
}
424
+
}
425
+
426
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
427
+
/// Set the `directoryListing` field (optional)
428
+
pub fn directory_listing(mut self, value: impl Into<Option<bool>>) -> Self {
429
+
self.__unsafe_private_named.2 = value.into();
430
+
self
431
+
}
432
+
/// Set the `directoryListing` field to an Option value (optional)
433
+
pub fn maybe_directory_listing(mut self, value: Option<bool>) -> Self {
434
+
self.__unsafe_private_named.2 = value;
435
+
self
436
+
}
437
+
}
438
+
439
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
440
+
/// Set the `headers` field (optional)
441
+
pub fn headers(
442
+
mut self,
443
+
value: impl Into<Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>>,
444
+
) -> Self {
445
+
self.__unsafe_private_named.3 = value.into();
446
+
self
447
+
}
448
+
/// Set the `headers` field to an Option value (optional)
449
+
pub fn maybe_headers(
450
+
mut self,
451
+
value: Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
452
+
) -> Self {
453
+
self.__unsafe_private_named.3 = value;
454
+
self
455
+
}
456
+
}
457
+
458
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
459
+
/// Set the `indexFiles` field (optional)
460
+
pub fn index_files(
461
+
mut self,
462
+
value: impl Into<Option<Vec<jacquard_common::CowStr<'a>>>>,
463
+
) -> Self {
464
+
self.__unsafe_private_named.4 = value.into();
465
+
self
466
+
}
467
+
/// Set the `indexFiles` field to an Option value (optional)
468
+
pub fn maybe_index_files(
469
+
mut self,
470
+
value: Option<Vec<jacquard_common::CowStr<'a>>>,
471
+
) -> Self {
472
+
self.__unsafe_private_named.4 = value;
473
+
self
474
+
}
475
+
}
476
+
477
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
478
+
/// Set the `spaMode` field (optional)
479
+
pub fn spa_mode(
480
+
mut self,
481
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
482
+
) -> Self {
483
+
self.__unsafe_private_named.5 = value.into();
484
+
self
485
+
}
486
+
/// Set the `spaMode` field to an Option value (optional)
487
+
pub fn maybe_spa_mode(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
488
+
self.__unsafe_private_named.5 = value;
489
+
self
490
+
}
491
+
}
492
+
493
+
impl<'a, S> SettingsBuilder<'a, S>
494
+
where
495
+
S: settings_state::State,
496
+
{
497
+
/// Build the final struct
498
+
pub fn build(self) -> Settings<'a> {
499
+
Settings {
500
+
clean_urls: self.__unsafe_private_named.0,
501
+
custom404: self.__unsafe_private_named.1,
502
+
directory_listing: self.__unsafe_private_named.2,
503
+
headers: self.__unsafe_private_named.3,
504
+
index_files: self.__unsafe_private_named.4,
505
+
spa_mode: self.__unsafe_private_named.5,
506
+
extra_data: Default::default(),
507
+
}
508
+
}
509
+
/// Build the final struct with custom extra_data
510
+
pub fn build_with_data(
511
+
self,
512
+
extra_data: std::collections::BTreeMap<
513
+
jacquard_common::smol_str::SmolStr,
514
+
jacquard_common::types::value::Data<'a>,
515
+
>,
516
+
) -> Settings<'a> {
517
+
Settings {
518
+
clean_urls: self.__unsafe_private_named.0,
519
+
custom404: self.__unsafe_private_named.1,
520
+
directory_listing: self.__unsafe_private_named.2,
521
+
headers: self.__unsafe_private_named.3,
522
+
index_files: self.__unsafe_private_named.4,
523
+
spa_mode: self.__unsafe_private_named.5,
524
+
extra_data: Some(extra_data),
525
+
}
526
+
}
527
+
}
528
+
529
+
impl<'a> Settings<'a> {
530
+
pub fn uri(
531
+
uri: impl Into<jacquard_common::CowStr<'a>>,
532
+
) -> Result<
533
+
jacquard_common::types::uri::RecordUri<'a, SettingsRecord>,
534
+
jacquard_common::types::uri::UriError,
535
+
> {
536
+
jacquard_common::types::uri::RecordUri::try_from_uri(
537
+
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
538
+
)
539
+
}
540
+
}
541
+
542
+
/// Typed wrapper for GetRecord response with this collection's record type.
543
+
#[derive(
544
+
serde::Serialize,
545
+
serde::Deserialize,
546
+
Debug,
547
+
Clone,
548
+
PartialEq,
549
+
Eq,
550
+
jacquard_derive::IntoStatic
551
+
)]
552
+
#[serde(rename_all = "camelCase")]
553
+
pub struct SettingsGetRecordOutput<'a> {
554
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
555
+
#[serde(borrow)]
556
+
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
557
+
#[serde(borrow)]
558
+
pub uri: jacquard_common::types::string::AtUri<'a>,
559
+
#[serde(borrow)]
560
+
pub value: Settings<'a>,
561
+
}
562
+
563
+
impl From<SettingsGetRecordOutput<'_>> for Settings<'_> {
564
+
fn from(output: SettingsGetRecordOutput<'_>) -> Self {
565
+
use jacquard_common::IntoStatic;
566
+
output.value.into_static()
567
+
}
568
+
}
569
+
570
+
impl jacquard_common::types::collection::Collection for Settings<'_> {
571
+
const NSID: &'static str = "place.wisp.settings";
572
+
type Record = SettingsRecord;
573
+
}
574
+
575
+
/// Marker type for deserializing records from this collection.
576
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
577
+
pub struct SettingsRecord;
578
+
impl jacquard_common::xrpc::XrpcResp for SettingsRecord {
579
+
const NSID: &'static str = "place.wisp.settings";
580
+
const ENCODING: &'static str = "application/json";
581
+
type Output<'de> = SettingsGetRecordOutput<'de>;
582
+
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
583
+
}
584
+
585
+
impl jacquard_common::types::collection::Collection for SettingsRecord {
586
+
const NSID: &'static str = "place.wisp.settings";
587
+
type Record = SettingsRecord;
588
+
}
589
+
590
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Settings<'a> {
591
+
fn nsid() -> &'static str {
592
+
"place.wisp.settings"
593
+
}
594
+
fn def_name() -> &'static str {
595
+
"main"
596
+
}
597
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
598
+
lexicon_doc_place_wisp_settings()
599
+
}
600
+
fn validate(
601
+
&self,
602
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
603
+
if let Some(ref value) = self.custom404 {
604
+
#[allow(unused_comparisons)]
605
+
if <str>::len(value.as_ref()) > 500usize {
606
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
607
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
608
+
"custom404",
609
+
),
610
+
max: 500usize,
611
+
actual: <str>::len(value.as_ref()),
612
+
});
613
+
}
614
+
}
615
+
if let Some(ref value) = self.headers {
616
+
#[allow(unused_comparisons)]
617
+
if value.len() > 50usize {
618
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
619
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
620
+
"headers",
621
+
),
622
+
max: 50usize,
623
+
actual: value.len(),
624
+
});
625
+
}
626
+
}
627
+
if let Some(ref value) = self.index_files {
628
+
#[allow(unused_comparisons)]
629
+
if value.len() > 10usize {
630
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
631
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
632
+
"index_files",
633
+
),
634
+
max: 10usize,
635
+
actual: value.len(),
636
+
});
637
+
}
638
+
}
639
+
if let Some(ref value) = self.spa_mode {
640
+
#[allow(unused_comparisons)]
641
+
if <str>::len(value.as_ref()) > 500usize {
642
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
643
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
644
+
"spa_mode",
645
+
),
646
+
max: 500usize,
647
+
actual: <str>::len(value.as_ref()),
648
+
});
649
+
}
650
+
}
651
+
Ok(())
652
+
}
653
+
}
+1408
cli/crates/lexicons/src/place_wisp/subfs.rs
+1408
cli/crates/lexicons/src/place_wisp/subfs.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// Lexicon: place.wisp.subfs
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
#[jacquard_derive::lexicon]
9
+
#[derive(
10
+
serde::Serialize,
11
+
serde::Deserialize,
12
+
Debug,
13
+
Clone,
14
+
PartialEq,
15
+
Eq,
16
+
jacquard_derive::IntoStatic
17
+
)]
18
+
#[serde(rename_all = "camelCase")]
19
+
pub struct Directory<'a> {
20
+
#[serde(borrow)]
21
+
pub entries: Vec<crate::place_wisp::subfs::Entry<'a>>,
22
+
#[serde(borrow)]
23
+
pub r#type: jacquard_common::CowStr<'a>,
24
+
}
25
+
26
+
pub mod directory_state {
27
+
28
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
+
#[allow(unused)]
30
+
use ::core::marker::PhantomData;
31
+
mod sealed {
32
+
pub trait Sealed {}
33
+
}
34
+
/// State trait tracking which required fields have been set
35
+
pub trait State: sealed::Sealed {
36
+
type Type;
37
+
type Entries;
38
+
}
39
+
/// Empty state - all required fields are unset
40
+
pub struct Empty(());
41
+
impl sealed::Sealed for Empty {}
42
+
impl State for Empty {
43
+
type Type = Unset;
44
+
type Entries = Unset;
45
+
}
46
+
///State transition - sets the `type` field to Set
47
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
+
impl<S: State> sealed::Sealed for SetType<S> {}
49
+
impl<S: State> State for SetType<S> {
50
+
type Type = Set<members::r#type>;
51
+
type Entries = S::Entries;
52
+
}
53
+
///State transition - sets the `entries` field to Set
54
+
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
+
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
+
impl<S: State> State for SetEntries<S> {
57
+
type Type = S::Type;
58
+
type Entries = Set<members::entries>;
59
+
}
60
+
/// Marker types for field names
61
+
#[allow(non_camel_case_types)]
62
+
pub mod members {
63
+
///Marker type for the `type` field
64
+
pub struct r#type(());
65
+
///Marker type for the `entries` field
66
+
pub struct entries(());
67
+
}
68
+
}
69
+
70
+
/// Builder for constructing an instance of this type
71
+
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
+
__unsafe_private_named: (
74
+
::core::option::Option<Vec<crate::place_wisp::subfs::Entry<'a>>>,
75
+
::core::option::Option<jacquard_common::CowStr<'a>>,
76
+
),
77
+
_phantom: ::core::marker::PhantomData<&'a ()>,
78
+
}
79
+
80
+
impl<'a> Directory<'a> {
81
+
/// Create a new builder for this type
82
+
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
+
DirectoryBuilder::new()
84
+
}
85
+
}
86
+
87
+
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
+
/// Create a new builder with all fields unset
89
+
pub fn new() -> Self {
90
+
DirectoryBuilder {
91
+
_phantom_state: ::core::marker::PhantomData,
92
+
__unsafe_private_named: (None, None),
93
+
_phantom: ::core::marker::PhantomData,
94
+
}
95
+
}
96
+
}
97
+
98
+
impl<'a, S> DirectoryBuilder<'a, S>
99
+
where
100
+
S: directory_state::State,
101
+
S::Entries: directory_state::IsUnset,
102
+
{
103
+
/// Set the `entries` field (required)
104
+
pub fn entries(
105
+
mut self,
106
+
value: impl Into<Vec<crate::place_wisp::subfs::Entry<'a>>>,
107
+
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
+
DirectoryBuilder {
110
+
_phantom_state: ::core::marker::PhantomData,
111
+
__unsafe_private_named: self.__unsafe_private_named,
112
+
_phantom: ::core::marker::PhantomData,
113
+
}
114
+
}
115
+
}
116
+
117
+
impl<'a, S> DirectoryBuilder<'a, S>
118
+
where
119
+
S: directory_state::State,
120
+
S::Type: directory_state::IsUnset,
121
+
{
122
+
/// Set the `type` field (required)
123
+
pub fn r#type(
124
+
mut self,
125
+
value: impl Into<jacquard_common::CowStr<'a>>,
126
+
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
+
DirectoryBuilder {
129
+
_phantom_state: ::core::marker::PhantomData,
130
+
__unsafe_private_named: self.__unsafe_private_named,
131
+
_phantom: ::core::marker::PhantomData,
132
+
}
133
+
}
134
+
}
135
+
136
+
impl<'a, S> DirectoryBuilder<'a, S>
137
+
where
138
+
S: directory_state::State,
139
+
S::Type: directory_state::IsSet,
140
+
S::Entries: directory_state::IsSet,
141
+
{
142
+
/// Build the final struct
143
+
pub fn build(self) -> Directory<'a> {
144
+
Directory {
145
+
entries: self.__unsafe_private_named.0.unwrap(),
146
+
r#type: self.__unsafe_private_named.1.unwrap(),
147
+
extra_data: Default::default(),
148
+
}
149
+
}
150
+
/// Build the final struct with custom extra_data
151
+
pub fn build_with_data(
152
+
self,
153
+
extra_data: std::collections::BTreeMap<
154
+
jacquard_common::smol_str::SmolStr,
155
+
jacquard_common::types::value::Data<'a>,
156
+
>,
157
+
) -> Directory<'a> {
158
+
Directory {
159
+
entries: self.__unsafe_private_named.0.unwrap(),
160
+
r#type: self.__unsafe_private_named.1.unwrap(),
161
+
extra_data: Some(extra_data),
162
+
}
163
+
}
164
+
}
165
+
166
+
fn lexicon_doc_place_wisp_subfs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
+
::jacquard_lexicon::lexicon::LexiconDoc {
168
+
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
+
id: ::jacquard_common::CowStr::new_static("place.wisp.subfs"),
170
+
revision: None,
171
+
description: None,
172
+
defs: {
173
+
let mut map = ::std::collections::BTreeMap::new();
174
+
map.insert(
175
+
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
+
description: None,
178
+
required: Some(
179
+
vec![
180
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
+
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
+
],
183
+
),
184
+
nullable: None,
185
+
properties: {
186
+
#[allow(unused_mut)]
187
+
let mut map = ::std::collections::BTreeMap::new();
188
+
map.insert(
189
+
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
+
description: None,
192
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
+
description: None,
194
+
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
+
}),
196
+
min_length: None,
197
+
max_length: Some(500usize),
198
+
}),
199
+
);
200
+
map.insert(
201
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
+
description: None,
204
+
format: None,
205
+
default: None,
206
+
min_length: None,
207
+
max_length: None,
208
+
min_graphemes: None,
209
+
max_graphemes: None,
210
+
r#enum: None,
211
+
r#const: None,
212
+
known_values: None,
213
+
}),
214
+
);
215
+
map
216
+
},
217
+
}),
218
+
);
219
+
map.insert(
220
+
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
+
description: None,
223
+
required: Some(
224
+
vec![
225
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
+
::jacquard_common::smol_str::SmolStr::new_static("node")
227
+
],
228
+
),
229
+
nullable: None,
230
+
properties: {
231
+
#[allow(unused_mut)]
232
+
let mut map = ::std::collections::BTreeMap::new();
233
+
map.insert(
234
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
+
description: None,
237
+
format: None,
238
+
default: None,
239
+
min_length: None,
240
+
max_length: Some(255usize),
241
+
min_graphemes: None,
242
+
max_graphemes: None,
243
+
r#enum: None,
244
+
r#const: None,
245
+
known_values: None,
246
+
}),
247
+
);
248
+
map.insert(
249
+
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
+
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
+
description: None,
252
+
refs: vec![
253
+
::jacquard_common::CowStr::new_static("#file"),
254
+
::jacquard_common::CowStr::new_static("#directory"),
255
+
::jacquard_common::CowStr::new_static("#subfs")
256
+
],
257
+
closed: None,
258
+
}),
259
+
);
260
+
map
261
+
},
262
+
}),
263
+
);
264
+
map.insert(
265
+
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
+
description: None,
268
+
required: Some(
269
+
vec![
270
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
+
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
+
],
273
+
),
274
+
nullable: None,
275
+
properties: {
276
+
#[allow(unused_mut)]
277
+
let mut map = ::std::collections::BTreeMap::new();
278
+
map.insert(
279
+
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
+
description: None,
282
+
default: None,
283
+
r#const: None,
284
+
}),
285
+
);
286
+
map.insert(
287
+
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
+
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
+
description: None,
290
+
accept: None,
291
+
max_size: None,
292
+
}),
293
+
);
294
+
map.insert(
295
+
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
+
description: Some(
298
+
::jacquard_common::CowStr::new_static(
299
+
"Content encoding (e.g., gzip for compressed files)",
300
+
),
301
+
),
302
+
format: None,
303
+
default: None,
304
+
min_length: None,
305
+
max_length: None,
306
+
min_graphemes: None,
307
+
max_graphemes: None,
308
+
r#enum: None,
309
+
r#const: None,
310
+
known_values: None,
311
+
}),
312
+
);
313
+
map.insert(
314
+
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
+
description: Some(
317
+
::jacquard_common::CowStr::new_static(
318
+
"Original MIME type before compression",
319
+
),
320
+
),
321
+
format: None,
322
+
default: None,
323
+
min_length: None,
324
+
max_length: None,
325
+
min_graphemes: None,
326
+
max_graphemes: None,
327
+
r#enum: None,
328
+
r#const: None,
329
+
known_values: None,
330
+
}),
331
+
);
332
+
map.insert(
333
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
+
description: None,
336
+
format: None,
337
+
default: None,
338
+
min_length: None,
339
+
max_length: None,
340
+
min_graphemes: None,
341
+
max_graphemes: None,
342
+
r#enum: None,
343
+
r#const: None,
344
+
known_values: None,
345
+
}),
346
+
);
347
+
map
348
+
},
349
+
}),
350
+
);
351
+
map.insert(
352
+
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
+
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
+
description: Some(
355
+
::jacquard_common::CowStr::new_static(
356
+
"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.",
357
+
),
358
+
),
359
+
key: None,
360
+
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
+
description: None,
362
+
required: Some(
363
+
vec![
364
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
365
+
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
366
+
],
367
+
),
368
+
nullable: None,
369
+
properties: {
370
+
#[allow(unused_mut)]
371
+
let mut map = ::std::collections::BTreeMap::new();
372
+
map.insert(
373
+
::jacquard_common::smol_str::SmolStr::new_static(
374
+
"createdAt",
375
+
),
376
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
377
+
description: None,
378
+
format: Some(
379
+
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
380
+
),
381
+
default: None,
382
+
min_length: None,
383
+
max_length: None,
384
+
min_graphemes: None,
385
+
max_graphemes: None,
386
+
r#enum: None,
387
+
r#const: None,
388
+
known_values: None,
389
+
}),
390
+
);
391
+
map.insert(
392
+
::jacquard_common::smol_str::SmolStr::new_static(
393
+
"fileCount",
394
+
),
395
+
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
396
+
description: None,
397
+
default: None,
398
+
minimum: Some(0i64),
399
+
maximum: Some(1000i64),
400
+
r#enum: None,
401
+
r#const: None,
402
+
}),
403
+
);
404
+
map.insert(
405
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
406
+
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
407
+
description: None,
408
+
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
409
+
}),
410
+
);
411
+
map
412
+
},
413
+
}),
414
+
}),
415
+
);
416
+
map.insert(
417
+
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
418
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
419
+
description: None,
420
+
required: Some(
421
+
vec![
422
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
423
+
::jacquard_common::smol_str::SmolStr::new_static("subject")
424
+
],
425
+
),
426
+
nullable: None,
427
+
properties: {
428
+
#[allow(unused_mut)]
429
+
let mut map = ::std::collections::BTreeMap::new();
430
+
map.insert(
431
+
::jacquard_common::smol_str::SmolStr::new_static("subject"),
432
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
433
+
description: Some(
434
+
::jacquard_common::CowStr::new_static(
435
+
"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.",
436
+
),
437
+
),
438
+
format: Some(
439
+
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
440
+
),
441
+
default: None,
442
+
min_length: None,
443
+
max_length: None,
444
+
min_graphemes: None,
445
+
max_graphemes: None,
446
+
r#enum: None,
447
+
r#const: None,
448
+
known_values: None,
449
+
}),
450
+
);
451
+
map.insert(
452
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
453
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
454
+
description: None,
455
+
format: None,
456
+
default: None,
457
+
min_length: None,
458
+
max_length: None,
459
+
min_graphemes: None,
460
+
max_graphemes: None,
461
+
r#enum: None,
462
+
r#const: None,
463
+
known_values: None,
464
+
}),
465
+
);
466
+
map
467
+
},
468
+
}),
469
+
);
470
+
map
471
+
},
472
+
}
473
+
}
474
+
475
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
476
+
fn nsid() -> &'static str {
477
+
"place.wisp.subfs"
478
+
}
479
+
fn def_name() -> &'static str {
480
+
"directory"
481
+
}
482
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
483
+
lexicon_doc_place_wisp_subfs()
484
+
}
485
+
fn validate(
486
+
&self,
487
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
488
+
{
489
+
let value = &self.entries;
490
+
#[allow(unused_comparisons)]
491
+
if value.len() > 500usize {
492
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
493
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
494
+
"entries",
495
+
),
496
+
max: 500usize,
497
+
actual: value.len(),
498
+
});
499
+
}
500
+
}
501
+
Ok(())
502
+
}
503
+
}
504
+
505
+
#[jacquard_derive::lexicon]
506
+
#[derive(
507
+
serde::Serialize,
508
+
serde::Deserialize,
509
+
Debug,
510
+
Clone,
511
+
PartialEq,
512
+
Eq,
513
+
jacquard_derive::IntoStatic
514
+
)]
515
+
#[serde(rename_all = "camelCase")]
516
+
pub struct Entry<'a> {
517
+
#[serde(borrow)]
518
+
pub name: jacquard_common::CowStr<'a>,
519
+
#[serde(borrow)]
520
+
pub node: EntryNode<'a>,
521
+
}
522
+
523
+
pub mod entry_state {
524
+
525
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
526
+
#[allow(unused)]
527
+
use ::core::marker::PhantomData;
528
+
mod sealed {
529
+
pub trait Sealed {}
530
+
}
531
+
/// State trait tracking which required fields have been set
532
+
pub trait State: sealed::Sealed {
533
+
type Name;
534
+
type Node;
535
+
}
536
+
/// Empty state - all required fields are unset
537
+
pub struct Empty(());
538
+
impl sealed::Sealed for Empty {}
539
+
impl State for Empty {
540
+
type Name = Unset;
541
+
type Node = Unset;
542
+
}
543
+
///State transition - sets the `name` field to Set
544
+
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
545
+
impl<S: State> sealed::Sealed for SetName<S> {}
546
+
impl<S: State> State for SetName<S> {
547
+
type Name = Set<members::name>;
548
+
type Node = S::Node;
549
+
}
550
+
///State transition - sets the `node` field to Set
551
+
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
552
+
impl<S: State> sealed::Sealed for SetNode<S> {}
553
+
impl<S: State> State for SetNode<S> {
554
+
type Name = S::Name;
555
+
type Node = Set<members::node>;
556
+
}
557
+
/// Marker types for field names
558
+
#[allow(non_camel_case_types)]
559
+
pub mod members {
560
+
///Marker type for the `name` field
561
+
pub struct name(());
562
+
///Marker type for the `node` field
563
+
pub struct node(());
564
+
}
565
+
}
566
+
567
+
/// Builder for constructing an instance of this type
568
+
pub struct EntryBuilder<'a, S: entry_state::State> {
569
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
570
+
__unsafe_private_named: (
571
+
::core::option::Option<jacquard_common::CowStr<'a>>,
572
+
::core::option::Option<EntryNode<'a>>,
573
+
),
574
+
_phantom: ::core::marker::PhantomData<&'a ()>,
575
+
}
576
+
577
+
impl<'a> Entry<'a> {
578
+
/// Create a new builder for this type
579
+
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
580
+
EntryBuilder::new()
581
+
}
582
+
}
583
+
584
+
impl<'a> EntryBuilder<'a, entry_state::Empty> {
585
+
/// Create a new builder with all fields unset
586
+
pub fn new() -> Self {
587
+
EntryBuilder {
588
+
_phantom_state: ::core::marker::PhantomData,
589
+
__unsafe_private_named: (None, None),
590
+
_phantom: ::core::marker::PhantomData,
591
+
}
592
+
}
593
+
}
594
+
595
+
impl<'a, S> EntryBuilder<'a, S>
596
+
where
597
+
S: entry_state::State,
598
+
S::Name: entry_state::IsUnset,
599
+
{
600
+
/// Set the `name` field (required)
601
+
pub fn name(
602
+
mut self,
603
+
value: impl Into<jacquard_common::CowStr<'a>>,
604
+
) -> EntryBuilder<'a, entry_state::SetName<S>> {
605
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
606
+
EntryBuilder {
607
+
_phantom_state: ::core::marker::PhantomData,
608
+
__unsafe_private_named: self.__unsafe_private_named,
609
+
_phantom: ::core::marker::PhantomData,
610
+
}
611
+
}
612
+
}
613
+
614
+
impl<'a, S> EntryBuilder<'a, S>
615
+
where
616
+
S: entry_state::State,
617
+
S::Node: entry_state::IsUnset,
618
+
{
619
+
/// Set the `node` field (required)
620
+
pub fn node(
621
+
mut self,
622
+
value: impl Into<EntryNode<'a>>,
623
+
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
624
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
625
+
EntryBuilder {
626
+
_phantom_state: ::core::marker::PhantomData,
627
+
__unsafe_private_named: self.__unsafe_private_named,
628
+
_phantom: ::core::marker::PhantomData,
629
+
}
630
+
}
631
+
}
632
+
633
+
impl<'a, S> EntryBuilder<'a, S>
634
+
where
635
+
S: entry_state::State,
636
+
S::Name: entry_state::IsSet,
637
+
S::Node: entry_state::IsSet,
638
+
{
639
+
/// Build the final struct
640
+
pub fn build(self) -> Entry<'a> {
641
+
Entry {
642
+
name: self.__unsafe_private_named.0.unwrap(),
643
+
node: self.__unsafe_private_named.1.unwrap(),
644
+
extra_data: Default::default(),
645
+
}
646
+
}
647
+
/// Build the final struct with custom extra_data
648
+
pub fn build_with_data(
649
+
self,
650
+
extra_data: std::collections::BTreeMap<
651
+
jacquard_common::smol_str::SmolStr,
652
+
jacquard_common::types::value::Data<'a>,
653
+
>,
654
+
) -> Entry<'a> {
655
+
Entry {
656
+
name: self.__unsafe_private_named.0.unwrap(),
657
+
node: self.__unsafe_private_named.1.unwrap(),
658
+
extra_data: Some(extra_data),
659
+
}
660
+
}
661
+
}
662
+
663
+
#[jacquard_derive::open_union]
664
+
#[derive(
665
+
serde::Serialize,
666
+
serde::Deserialize,
667
+
Debug,
668
+
Clone,
669
+
PartialEq,
670
+
Eq,
671
+
jacquard_derive::IntoStatic
672
+
)]
673
+
#[serde(tag = "$type")]
674
+
#[serde(bound(deserialize = "'de: 'a"))]
675
+
pub enum EntryNode<'a> {
676
+
#[serde(rename = "place.wisp.subfs#file")]
677
+
File(Box<crate::place_wisp::subfs::File<'a>>),
678
+
#[serde(rename = "place.wisp.subfs#directory")]
679
+
Directory(Box<crate::place_wisp::subfs::Directory<'a>>),
680
+
#[serde(rename = "place.wisp.subfs#subfs")]
681
+
Subfs(Box<crate::place_wisp::subfs::Subfs<'a>>),
682
+
}
683
+
684
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
685
+
fn nsid() -> &'static str {
686
+
"place.wisp.subfs"
687
+
}
688
+
fn def_name() -> &'static str {
689
+
"entry"
690
+
}
691
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
692
+
lexicon_doc_place_wisp_subfs()
693
+
}
694
+
fn validate(
695
+
&self,
696
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
697
+
{
698
+
let value = &self.name;
699
+
#[allow(unused_comparisons)]
700
+
if <str>::len(value.as_ref()) > 255usize {
701
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
702
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
703
+
"name",
704
+
),
705
+
max: 255usize,
706
+
actual: <str>::len(value.as_ref()),
707
+
});
708
+
}
709
+
}
710
+
Ok(())
711
+
}
712
+
}
713
+
714
+
#[jacquard_derive::lexicon]
715
+
#[derive(
716
+
serde::Serialize,
717
+
serde::Deserialize,
718
+
Debug,
719
+
Clone,
720
+
PartialEq,
721
+
Eq,
722
+
jacquard_derive::IntoStatic
723
+
)]
724
+
#[serde(rename_all = "camelCase")]
725
+
pub struct File<'a> {
726
+
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
727
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
728
+
pub base64: std::option::Option<bool>,
729
+
/// Content blob ref
730
+
#[serde(borrow)]
731
+
pub blob: jacquard_common::types::blob::BlobRef<'a>,
732
+
/// Content encoding (e.g., gzip for compressed files)
733
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
734
+
#[serde(borrow)]
735
+
pub encoding: std::option::Option<jacquard_common::CowStr<'a>>,
736
+
/// Original MIME type before compression
737
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
738
+
#[serde(borrow)]
739
+
pub mime_type: std::option::Option<jacquard_common::CowStr<'a>>,
740
+
#[serde(borrow)]
741
+
pub r#type: jacquard_common::CowStr<'a>,
742
+
}
743
+
744
+
pub mod file_state {
745
+
746
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
747
+
#[allow(unused)]
748
+
use ::core::marker::PhantomData;
749
+
mod sealed {
750
+
pub trait Sealed {}
751
+
}
752
+
/// State trait tracking which required fields have been set
753
+
pub trait State: sealed::Sealed {
754
+
type Blob;
755
+
type Type;
756
+
}
757
+
/// Empty state - all required fields are unset
758
+
pub struct Empty(());
759
+
impl sealed::Sealed for Empty {}
760
+
impl State for Empty {
761
+
type Blob = Unset;
762
+
type Type = Unset;
763
+
}
764
+
///State transition - sets the `blob` field to Set
765
+
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
766
+
impl<S: State> sealed::Sealed for SetBlob<S> {}
767
+
impl<S: State> State for SetBlob<S> {
768
+
type Blob = Set<members::blob>;
769
+
type Type = S::Type;
770
+
}
771
+
///State transition - sets the `type` field to Set
772
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
773
+
impl<S: State> sealed::Sealed for SetType<S> {}
774
+
impl<S: State> State for SetType<S> {
775
+
type Blob = S::Blob;
776
+
type Type = Set<members::r#type>;
777
+
}
778
+
/// Marker types for field names
779
+
#[allow(non_camel_case_types)]
780
+
pub mod members {
781
+
///Marker type for the `blob` field
782
+
pub struct blob(());
783
+
///Marker type for the `type` field
784
+
pub struct r#type(());
785
+
}
786
+
}
787
+
788
+
/// Builder for constructing an instance of this type
789
+
pub struct FileBuilder<'a, S: file_state::State> {
790
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
791
+
__unsafe_private_named: (
792
+
::core::option::Option<bool>,
793
+
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
794
+
::core::option::Option<jacquard_common::CowStr<'a>>,
795
+
::core::option::Option<jacquard_common::CowStr<'a>>,
796
+
::core::option::Option<jacquard_common::CowStr<'a>>,
797
+
),
798
+
_phantom: ::core::marker::PhantomData<&'a ()>,
799
+
}
800
+
801
+
impl<'a> File<'a> {
802
+
/// Create a new builder for this type
803
+
pub fn new() -> FileBuilder<'a, file_state::Empty> {
804
+
FileBuilder::new()
805
+
}
806
+
}
807
+
808
+
impl<'a> FileBuilder<'a, file_state::Empty> {
809
+
/// Create a new builder with all fields unset
810
+
pub fn new() -> Self {
811
+
FileBuilder {
812
+
_phantom_state: ::core::marker::PhantomData,
813
+
__unsafe_private_named: (None, None, None, None, None),
814
+
_phantom: ::core::marker::PhantomData,
815
+
}
816
+
}
817
+
}
818
+
819
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
820
+
/// Set the `base64` field (optional)
821
+
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
822
+
self.__unsafe_private_named.0 = value.into();
823
+
self
824
+
}
825
+
/// Set the `base64` field to an Option value (optional)
826
+
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
827
+
self.__unsafe_private_named.0 = value;
828
+
self
829
+
}
830
+
}
831
+
832
+
impl<'a, S> FileBuilder<'a, S>
833
+
where
834
+
S: file_state::State,
835
+
S::Blob: file_state::IsUnset,
836
+
{
837
+
/// Set the `blob` field (required)
838
+
pub fn blob(
839
+
mut self,
840
+
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
841
+
) -> FileBuilder<'a, file_state::SetBlob<S>> {
842
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
843
+
FileBuilder {
844
+
_phantom_state: ::core::marker::PhantomData,
845
+
__unsafe_private_named: self.__unsafe_private_named,
846
+
_phantom: ::core::marker::PhantomData,
847
+
}
848
+
}
849
+
}
850
+
851
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
852
+
/// Set the `encoding` field (optional)
853
+
pub fn encoding(
854
+
mut self,
855
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
856
+
) -> Self {
857
+
self.__unsafe_private_named.2 = value.into();
858
+
self
859
+
}
860
+
/// Set the `encoding` field to an Option value (optional)
861
+
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
862
+
self.__unsafe_private_named.2 = value;
863
+
self
864
+
}
865
+
}
866
+
867
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
868
+
/// Set the `mimeType` field (optional)
869
+
pub fn mime_type(
870
+
mut self,
871
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
872
+
) -> Self {
873
+
self.__unsafe_private_named.3 = value.into();
874
+
self
875
+
}
876
+
/// Set the `mimeType` field to an Option value (optional)
877
+
pub fn maybe_mime_type(
878
+
mut self,
879
+
value: Option<jacquard_common::CowStr<'a>>,
880
+
) -> Self {
881
+
self.__unsafe_private_named.3 = value;
882
+
self
883
+
}
884
+
}
885
+
886
+
impl<'a, S> FileBuilder<'a, S>
887
+
where
888
+
S: file_state::State,
889
+
S::Type: file_state::IsUnset,
890
+
{
891
+
/// Set the `type` field (required)
892
+
pub fn r#type(
893
+
mut self,
894
+
value: impl Into<jacquard_common::CowStr<'a>>,
895
+
) -> FileBuilder<'a, file_state::SetType<S>> {
896
+
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
897
+
FileBuilder {
898
+
_phantom_state: ::core::marker::PhantomData,
899
+
__unsafe_private_named: self.__unsafe_private_named,
900
+
_phantom: ::core::marker::PhantomData,
901
+
}
902
+
}
903
+
}
904
+
905
+
impl<'a, S> FileBuilder<'a, S>
906
+
where
907
+
S: file_state::State,
908
+
S::Blob: file_state::IsSet,
909
+
S::Type: file_state::IsSet,
910
+
{
911
+
/// Build the final struct
912
+
pub fn build(self) -> File<'a> {
913
+
File {
914
+
base64: self.__unsafe_private_named.0,
915
+
blob: self.__unsafe_private_named.1.unwrap(),
916
+
encoding: self.__unsafe_private_named.2,
917
+
mime_type: self.__unsafe_private_named.3,
918
+
r#type: self.__unsafe_private_named.4.unwrap(),
919
+
extra_data: Default::default(),
920
+
}
921
+
}
922
+
/// Build the final struct with custom extra_data
923
+
pub fn build_with_data(
924
+
self,
925
+
extra_data: std::collections::BTreeMap<
926
+
jacquard_common::smol_str::SmolStr,
927
+
jacquard_common::types::value::Data<'a>,
928
+
>,
929
+
) -> File<'a> {
930
+
File {
931
+
base64: self.__unsafe_private_named.0,
932
+
blob: self.__unsafe_private_named.1.unwrap(),
933
+
encoding: self.__unsafe_private_named.2,
934
+
mime_type: self.__unsafe_private_named.3,
935
+
r#type: self.__unsafe_private_named.4.unwrap(),
936
+
extra_data: Some(extra_data),
937
+
}
938
+
}
939
+
}
940
+
941
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
942
+
fn nsid() -> &'static str {
943
+
"place.wisp.subfs"
944
+
}
945
+
fn def_name() -> &'static str {
946
+
"file"
947
+
}
948
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
949
+
lexicon_doc_place_wisp_subfs()
950
+
}
951
+
fn validate(
952
+
&self,
953
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
954
+
Ok(())
955
+
}
956
+
}
957
+
958
+
/// 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.
959
+
#[jacquard_derive::lexicon]
960
+
#[derive(
961
+
serde::Serialize,
962
+
serde::Deserialize,
963
+
Debug,
964
+
Clone,
965
+
PartialEq,
966
+
Eq,
967
+
jacquard_derive::IntoStatic
968
+
)]
969
+
#[serde(rename_all = "camelCase")]
970
+
pub struct SubfsRecord<'a> {
971
+
pub created_at: jacquard_common::types::string::Datetime,
972
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
973
+
pub file_count: std::option::Option<i64>,
974
+
#[serde(borrow)]
975
+
pub root: crate::place_wisp::subfs::Directory<'a>,
976
+
}
977
+
978
+
pub mod subfs_record_state {
979
+
980
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
981
+
#[allow(unused)]
982
+
use ::core::marker::PhantomData;
983
+
mod sealed {
984
+
pub trait Sealed {}
985
+
}
986
+
/// State trait tracking which required fields have been set
987
+
pub trait State: sealed::Sealed {
988
+
type Root;
989
+
type CreatedAt;
990
+
}
991
+
/// Empty state - all required fields are unset
992
+
pub struct Empty(());
993
+
impl sealed::Sealed for Empty {}
994
+
impl State for Empty {
995
+
type Root = Unset;
996
+
type CreatedAt = Unset;
997
+
}
998
+
///State transition - sets the `root` field to Set
999
+
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1000
+
impl<S: State> sealed::Sealed for SetRoot<S> {}
1001
+
impl<S: State> State for SetRoot<S> {
1002
+
type Root = Set<members::root>;
1003
+
type CreatedAt = S::CreatedAt;
1004
+
}
1005
+
///State transition - sets the `created_at` field to Set
1006
+
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1007
+
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1008
+
impl<S: State> State for SetCreatedAt<S> {
1009
+
type Root = S::Root;
1010
+
type CreatedAt = Set<members::created_at>;
1011
+
}
1012
+
/// Marker types for field names
1013
+
#[allow(non_camel_case_types)]
1014
+
pub mod members {
1015
+
///Marker type for the `root` field
1016
+
pub struct root(());
1017
+
///Marker type for the `created_at` field
1018
+
pub struct created_at(());
1019
+
}
1020
+
}
1021
+
1022
+
/// Builder for constructing an instance of this type
1023
+
pub struct SubfsRecordBuilder<'a, S: subfs_record_state::State> {
1024
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1025
+
__unsafe_private_named: (
1026
+
::core::option::Option<jacquard_common::types::string::Datetime>,
1027
+
::core::option::Option<i64>,
1028
+
::core::option::Option<crate::place_wisp::subfs::Directory<'a>>,
1029
+
),
1030
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1031
+
}
1032
+
1033
+
impl<'a> SubfsRecord<'a> {
1034
+
/// Create a new builder for this type
1035
+
pub fn new() -> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1036
+
SubfsRecordBuilder::new()
1037
+
}
1038
+
}
1039
+
1040
+
impl<'a> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1041
+
/// Create a new builder with all fields unset
1042
+
pub fn new() -> Self {
1043
+
SubfsRecordBuilder {
1044
+
_phantom_state: ::core::marker::PhantomData,
1045
+
__unsafe_private_named: (None, None, None),
1046
+
_phantom: ::core::marker::PhantomData,
1047
+
}
1048
+
}
1049
+
}
1050
+
1051
+
impl<'a, S> SubfsRecordBuilder<'a, S>
1052
+
where
1053
+
S: subfs_record_state::State,
1054
+
S::CreatedAt: subfs_record_state::IsUnset,
1055
+
{
1056
+
/// Set the `createdAt` field (required)
1057
+
pub fn created_at(
1058
+
mut self,
1059
+
value: impl Into<jacquard_common::types::string::Datetime>,
1060
+
) -> SubfsRecordBuilder<'a, subfs_record_state::SetCreatedAt<S>> {
1061
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1062
+
SubfsRecordBuilder {
1063
+
_phantom_state: ::core::marker::PhantomData,
1064
+
__unsafe_private_named: self.__unsafe_private_named,
1065
+
_phantom: ::core::marker::PhantomData,
1066
+
}
1067
+
}
1068
+
}
1069
+
1070
+
impl<'a, S: subfs_record_state::State> SubfsRecordBuilder<'a, S> {
1071
+
/// Set the `fileCount` field (optional)
1072
+
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1073
+
self.__unsafe_private_named.1 = value.into();
1074
+
self
1075
+
}
1076
+
/// Set the `fileCount` field to an Option value (optional)
1077
+
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1078
+
self.__unsafe_private_named.1 = value;
1079
+
self
1080
+
}
1081
+
}
1082
+
1083
+
impl<'a, S> SubfsRecordBuilder<'a, S>
1084
+
where
1085
+
S: subfs_record_state::State,
1086
+
S::Root: subfs_record_state::IsUnset,
1087
+
{
1088
+
/// Set the `root` field (required)
1089
+
pub fn root(
1090
+
mut self,
1091
+
value: impl Into<crate::place_wisp::subfs::Directory<'a>>,
1092
+
) -> SubfsRecordBuilder<'a, subfs_record_state::SetRoot<S>> {
1093
+
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1094
+
SubfsRecordBuilder {
1095
+
_phantom_state: ::core::marker::PhantomData,
1096
+
__unsafe_private_named: self.__unsafe_private_named,
1097
+
_phantom: ::core::marker::PhantomData,
1098
+
}
1099
+
}
1100
+
}
1101
+
1102
+
impl<'a, S> SubfsRecordBuilder<'a, S>
1103
+
where
1104
+
S: subfs_record_state::State,
1105
+
S::Root: subfs_record_state::IsSet,
1106
+
S::CreatedAt: subfs_record_state::IsSet,
1107
+
{
1108
+
/// Build the final struct
1109
+
pub fn build(self) -> SubfsRecord<'a> {
1110
+
SubfsRecord {
1111
+
created_at: self.__unsafe_private_named.0.unwrap(),
1112
+
file_count: self.__unsafe_private_named.1,
1113
+
root: self.__unsafe_private_named.2.unwrap(),
1114
+
extra_data: Default::default(),
1115
+
}
1116
+
}
1117
+
/// Build the final struct with custom extra_data
1118
+
pub fn build_with_data(
1119
+
self,
1120
+
extra_data: std::collections::BTreeMap<
1121
+
jacquard_common::smol_str::SmolStr,
1122
+
jacquard_common::types::value::Data<'a>,
1123
+
>,
1124
+
) -> SubfsRecord<'a> {
1125
+
SubfsRecord {
1126
+
created_at: self.__unsafe_private_named.0.unwrap(),
1127
+
file_count: self.__unsafe_private_named.1,
1128
+
root: self.__unsafe_private_named.2.unwrap(),
1129
+
extra_data: Some(extra_data),
1130
+
}
1131
+
}
1132
+
}
1133
+
1134
+
impl<'a> SubfsRecord<'a> {
1135
+
pub fn uri(
1136
+
uri: impl Into<jacquard_common::CowStr<'a>>,
1137
+
) -> Result<
1138
+
jacquard_common::types::uri::RecordUri<'a, SubfsRecordRecord>,
1139
+
jacquard_common::types::uri::UriError,
1140
+
> {
1141
+
jacquard_common::types::uri::RecordUri::try_from_uri(
1142
+
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1143
+
)
1144
+
}
1145
+
}
1146
+
1147
+
/// Typed wrapper for GetRecord response with this collection's record type.
1148
+
#[derive(
1149
+
serde::Serialize,
1150
+
serde::Deserialize,
1151
+
Debug,
1152
+
Clone,
1153
+
PartialEq,
1154
+
Eq,
1155
+
jacquard_derive::IntoStatic
1156
+
)]
1157
+
#[serde(rename_all = "camelCase")]
1158
+
pub struct SubfsRecordGetRecordOutput<'a> {
1159
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1160
+
#[serde(borrow)]
1161
+
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1162
+
#[serde(borrow)]
1163
+
pub uri: jacquard_common::types::string::AtUri<'a>,
1164
+
#[serde(borrow)]
1165
+
pub value: SubfsRecord<'a>,
1166
+
}
1167
+
1168
+
impl From<SubfsRecordGetRecordOutput<'_>> for SubfsRecord<'_> {
1169
+
fn from(output: SubfsRecordGetRecordOutput<'_>) -> Self {
1170
+
use jacquard_common::IntoStatic;
1171
+
output.value.into_static()
1172
+
}
1173
+
}
1174
+
1175
+
impl jacquard_common::types::collection::Collection for SubfsRecord<'_> {
1176
+
const NSID: &'static str = "place.wisp.subfs";
1177
+
type Record = SubfsRecordRecord;
1178
+
}
1179
+
1180
+
/// Marker type for deserializing records from this collection.
1181
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1182
+
pub struct SubfsRecordRecord;
1183
+
impl jacquard_common::xrpc::XrpcResp for SubfsRecordRecord {
1184
+
const NSID: &'static str = "place.wisp.subfs";
1185
+
const ENCODING: &'static str = "application/json";
1186
+
type Output<'de> = SubfsRecordGetRecordOutput<'de>;
1187
+
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1188
+
}
1189
+
1190
+
impl jacquard_common::types::collection::Collection for SubfsRecordRecord {
1191
+
const NSID: &'static str = "place.wisp.subfs";
1192
+
type Record = SubfsRecordRecord;
1193
+
}
1194
+
1195
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for SubfsRecord<'a> {
1196
+
fn nsid() -> &'static str {
1197
+
"place.wisp.subfs"
1198
+
}
1199
+
fn def_name() -> &'static str {
1200
+
"main"
1201
+
}
1202
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1203
+
lexicon_doc_place_wisp_subfs()
1204
+
}
1205
+
fn validate(
1206
+
&self,
1207
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1208
+
if let Some(ref value) = self.file_count {
1209
+
if *value > 1000i64 {
1210
+
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1211
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1212
+
"file_count",
1213
+
),
1214
+
max: 1000i64,
1215
+
actual: *value,
1216
+
});
1217
+
}
1218
+
}
1219
+
if let Some(ref value) = self.file_count {
1220
+
if *value < 0i64 {
1221
+
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1222
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1223
+
"file_count",
1224
+
),
1225
+
min: 0i64,
1226
+
actual: *value,
1227
+
});
1228
+
}
1229
+
}
1230
+
Ok(())
1231
+
}
1232
+
}
1233
+
1234
+
#[jacquard_derive::lexicon]
1235
+
#[derive(
1236
+
serde::Serialize,
1237
+
serde::Deserialize,
1238
+
Debug,
1239
+
Clone,
1240
+
PartialEq,
1241
+
Eq,
1242
+
jacquard_derive::IntoStatic
1243
+
)]
1244
+
#[serde(rename_all = "camelCase")]
1245
+
pub struct Subfs<'a> {
1246
+
/// 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.
1247
+
#[serde(borrow)]
1248
+
pub subject: jacquard_common::types::string::AtUri<'a>,
1249
+
#[serde(borrow)]
1250
+
pub r#type: jacquard_common::CowStr<'a>,
1251
+
}
1252
+
1253
+
pub mod subfs_state {
1254
+
1255
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1256
+
#[allow(unused)]
1257
+
use ::core::marker::PhantomData;
1258
+
mod sealed {
1259
+
pub trait Sealed {}
1260
+
}
1261
+
/// State trait tracking which required fields have been set
1262
+
pub trait State: sealed::Sealed {
1263
+
type Subject;
1264
+
type Type;
1265
+
}
1266
+
/// Empty state - all required fields are unset
1267
+
pub struct Empty(());
1268
+
impl sealed::Sealed for Empty {}
1269
+
impl State for Empty {
1270
+
type Subject = Unset;
1271
+
type Type = Unset;
1272
+
}
1273
+
///State transition - sets the `subject` field to Set
1274
+
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1275
+
impl<S: State> sealed::Sealed for SetSubject<S> {}
1276
+
impl<S: State> State for SetSubject<S> {
1277
+
type Subject = Set<members::subject>;
1278
+
type Type = S::Type;
1279
+
}
1280
+
///State transition - sets the `type` field to Set
1281
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1282
+
impl<S: State> sealed::Sealed for SetType<S> {}
1283
+
impl<S: State> State for SetType<S> {
1284
+
type Subject = S::Subject;
1285
+
type Type = Set<members::r#type>;
1286
+
}
1287
+
/// Marker types for field names
1288
+
#[allow(non_camel_case_types)]
1289
+
pub mod members {
1290
+
///Marker type for the `subject` field
1291
+
pub struct subject(());
1292
+
///Marker type for the `type` field
1293
+
pub struct r#type(());
1294
+
}
1295
+
}
1296
+
1297
+
/// Builder for constructing an instance of this type
1298
+
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1299
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1300
+
__unsafe_private_named: (
1301
+
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1302
+
::core::option::Option<jacquard_common::CowStr<'a>>,
1303
+
),
1304
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1305
+
}
1306
+
1307
+
impl<'a> Subfs<'a> {
1308
+
/// Create a new builder for this type
1309
+
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1310
+
SubfsBuilder::new()
1311
+
}
1312
+
}
1313
+
1314
+
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1315
+
/// Create a new builder with all fields unset
1316
+
pub fn new() -> Self {
1317
+
SubfsBuilder {
1318
+
_phantom_state: ::core::marker::PhantomData,
1319
+
__unsafe_private_named: (None, None),
1320
+
_phantom: ::core::marker::PhantomData,
1321
+
}
1322
+
}
1323
+
}
1324
+
1325
+
impl<'a, S> SubfsBuilder<'a, S>
1326
+
where
1327
+
S: subfs_state::State,
1328
+
S::Subject: subfs_state::IsUnset,
1329
+
{
1330
+
/// Set the `subject` field (required)
1331
+
pub fn subject(
1332
+
mut self,
1333
+
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1334
+
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1335
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1336
+
SubfsBuilder {
1337
+
_phantom_state: ::core::marker::PhantomData,
1338
+
__unsafe_private_named: self.__unsafe_private_named,
1339
+
_phantom: ::core::marker::PhantomData,
1340
+
}
1341
+
}
1342
+
}
1343
+
1344
+
impl<'a, S> SubfsBuilder<'a, S>
1345
+
where
1346
+
S: subfs_state::State,
1347
+
S::Type: subfs_state::IsUnset,
1348
+
{
1349
+
/// Set the `type` field (required)
1350
+
pub fn r#type(
1351
+
mut self,
1352
+
value: impl Into<jacquard_common::CowStr<'a>>,
1353
+
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1354
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1355
+
SubfsBuilder {
1356
+
_phantom_state: ::core::marker::PhantomData,
1357
+
__unsafe_private_named: self.__unsafe_private_named,
1358
+
_phantom: ::core::marker::PhantomData,
1359
+
}
1360
+
}
1361
+
}
1362
+
1363
+
impl<'a, S> SubfsBuilder<'a, S>
1364
+
where
1365
+
S: subfs_state::State,
1366
+
S::Subject: subfs_state::IsSet,
1367
+
S::Type: subfs_state::IsSet,
1368
+
{
1369
+
/// Build the final struct
1370
+
pub fn build(self) -> Subfs<'a> {
1371
+
Subfs {
1372
+
subject: self.__unsafe_private_named.0.unwrap(),
1373
+
r#type: self.__unsafe_private_named.1.unwrap(),
1374
+
extra_data: Default::default(),
1375
+
}
1376
+
}
1377
+
/// Build the final struct with custom extra_data
1378
+
pub fn build_with_data(
1379
+
self,
1380
+
extra_data: std::collections::BTreeMap<
1381
+
jacquard_common::smol_str::SmolStr,
1382
+
jacquard_common::types::value::Data<'a>,
1383
+
>,
1384
+
) -> Subfs<'a> {
1385
+
Subfs {
1386
+
subject: self.__unsafe_private_named.0.unwrap(),
1387
+
r#type: self.__unsafe_private_named.1.unwrap(),
1388
+
extra_data: Some(extra_data),
1389
+
}
1390
+
}
1391
+
}
1392
+
1393
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1394
+
fn nsid() -> &'static str {
1395
+
"place.wisp.subfs"
1396
+
}
1397
+
fn def_name() -> &'static str {
1398
+
"subfs"
1399
+
}
1400
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1401
+
lexicon_doc_place_wisp_subfs()
1402
+
}
1403
+
fn validate(
1404
+
&self,
1405
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1406
+
Ok(())
1407
+
}
1408
+
}
+8
cli/crates/lexicons/src/place_wisp.rs
+8
cli/crates/lexicons/src/place_wisp.rs
+16
cli/default.nix
+16
cli/default.nix
···
1
+
{
2
+
rustPlatform,
3
+
glibc,
4
+
}:
5
+
rustPlatform.buildRustPackage {
6
+
name = "wisp-cli";
7
+
src = ./.;
8
+
cargoLock = {
9
+
lockFile = ./Cargo.lock;
10
+
outputHashes = {
11
+
"jacquard-0.9.5" = "sha256-75bas4VAYFcZAcBspSqS4vlJe8nmFn9ncTgeoT/OvnA=";
12
+
};
13
+
};
14
+
buildInputs = [glibc.static];
15
+
RUSTFLAGS = ["-C" "target-feature=+crt-static"];
16
+
}
+96
cli/flake.lock
+96
cli/flake.lock
···
1
+
{
2
+
"nodes": {
3
+
"flake-utils": {
4
+
"inputs": {
5
+
"systems": "systems"
6
+
},
7
+
"locked": {
8
+
"lastModified": 1731533236,
9
+
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
10
+
"owner": "numtide",
11
+
"repo": "flake-utils",
12
+
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
13
+
"type": "github"
14
+
},
15
+
"original": {
16
+
"owner": "numtide",
17
+
"repo": "flake-utils",
18
+
"type": "github"
19
+
}
20
+
},
21
+
"nixpkgs": {
22
+
"locked": {
23
+
"lastModified": 1767640445,
24
+
"narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=",
25
+
"owner": "NixOS",
26
+
"repo": "nixpkgs",
27
+
"rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5",
28
+
"type": "github"
29
+
},
30
+
"original": {
31
+
"owner": "NixOS",
32
+
"ref": "nixos-unstable",
33
+
"repo": "nixpkgs",
34
+
"type": "github"
35
+
}
36
+
},
37
+
"nixpkgs_2": {
38
+
"locked": {
39
+
"lastModified": 1744536153,
40
+
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
41
+
"owner": "NixOS",
42
+
"repo": "nixpkgs",
43
+
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
44
+
"type": "github"
45
+
},
46
+
"original": {
47
+
"owner": "NixOS",
48
+
"ref": "nixpkgs-unstable",
49
+
"repo": "nixpkgs",
50
+
"type": "github"
51
+
}
52
+
},
53
+
"root": {
54
+
"inputs": {
55
+
"flake-utils": "flake-utils",
56
+
"nixpkgs": "nixpkgs",
57
+
"rust-overlay": "rust-overlay"
58
+
}
59
+
},
60
+
"rust-overlay": {
61
+
"inputs": {
62
+
"nixpkgs": "nixpkgs_2"
63
+
},
64
+
"locked": {
65
+
"lastModified": 1767667566,
66
+
"narHash": "sha256-COy+yxZGuhQRVD1r4bWVgeFt1GB+IB1k5WRpDKbLfI8=",
67
+
"owner": "oxalica",
68
+
"repo": "rust-overlay",
69
+
"rev": "056ce5b125ab32ffe78c7d3e394d9da44733c95e",
70
+
"type": "github"
71
+
},
72
+
"original": {
73
+
"owner": "oxalica",
74
+
"repo": "rust-overlay",
75
+
"type": "github"
76
+
}
77
+
},
78
+
"systems": {
79
+
"locked": {
80
+
"lastModified": 1681028828,
81
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
82
+
"owner": "nix-systems",
83
+
"repo": "default",
84
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
85
+
"type": "github"
86
+
},
87
+
"original": {
88
+
"owner": "nix-systems",
89
+
"repo": "default",
90
+
"type": "github"
91
+
}
92
+
}
93
+
},
94
+
"root": "root",
95
+
"version": 7
96
+
}
+136
cli/flake.nix
+136
cli/flake.nix
···
1
+
{
2
+
inputs = {
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4
+
rust-overlay.url = "github:oxalica/rust-overlay";
5
+
flake-utils.url = "github:numtide/flake-utils";
6
+
};
7
+
8
+
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
9
+
flake-utils.lib.eachDefaultSystem (system:
10
+
let
11
+
overlays = [ (import rust-overlay) ];
12
+
pkgs = import nixpkgs { inherit system overlays; };
13
+
14
+
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
15
+
targets = [
16
+
"x86_64-unknown-linux-musl"
17
+
"aarch64-unknown-linux-musl"
18
+
"x86_64-apple-darwin"
19
+
"aarch64-apple-darwin"
20
+
];
21
+
};
22
+
23
+
cargoLockConfig = {
24
+
lockFile = ./Cargo.lock;
25
+
outputHashes = {
26
+
"jacquard-0.9.5" = "sha256-75bas4VAYFcZAcBspSqS4vlJe8nmFn9ncTgeoT/OvnA=";
27
+
};
28
+
};
29
+
30
+
# Native build for current system
31
+
native = pkgs.rustPlatform.buildRustPackage {
32
+
pname = "wisp-cli";
33
+
version = "0.4.2";
34
+
src = ./.;
35
+
cargoLock = cargoLockConfig;
36
+
nativeBuildInputs = [ rustToolchain ];
37
+
};
38
+
39
+
# Cross-compilation targets (Linux from macOS needs zigbuild)
40
+
linuxTargets = let
41
+
zigbuildPkgs = pkgs;
42
+
in {
43
+
x86_64-linux = pkgs.stdenv.mkDerivation {
44
+
pname = "wisp-cli-x86_64-linux";
45
+
version = "0.4.2";
46
+
src = ./.;
47
+
48
+
nativeBuildInputs = [
49
+
rustToolchain
50
+
pkgs.cargo-zigbuild
51
+
pkgs.zig
52
+
];
53
+
54
+
buildPhase = ''
55
+
export HOME=$(mktemp -d)
56
+
cargo zigbuild --release --target x86_64-unknown-linux-musl
57
+
'';
58
+
59
+
installPhase = ''
60
+
mkdir -p $out/bin
61
+
cp target/x86_64-unknown-linux-musl/release/wisp-cli $out/bin/
62
+
'';
63
+
64
+
# Skip Nix's cargo vendor - we use network
65
+
dontConfigure = true;
66
+
dontFixup = true;
67
+
};
68
+
69
+
aarch64-linux = pkgs.stdenv.mkDerivation {
70
+
pname = "wisp-cli-aarch64-linux";
71
+
version = "0.4.2";
72
+
src = ./.;
73
+
74
+
nativeBuildInputs = [
75
+
rustToolchain
76
+
pkgs.cargo-zigbuild
77
+
pkgs.zig
78
+
];
79
+
80
+
buildPhase = ''
81
+
export HOME=$(mktemp -d)
82
+
cargo zigbuild --release --target aarch64-unknown-linux-musl
83
+
'';
84
+
85
+
installPhase = ''
86
+
mkdir -p $out/bin
87
+
cp target/aarch64-unknown-linux-musl/release/wisp-cli $out/bin/
88
+
'';
89
+
90
+
dontConfigure = true;
91
+
dontFixup = true;
92
+
};
93
+
};
94
+
95
+
in {
96
+
packages = {
97
+
default = native;
98
+
inherit native;
99
+
100
+
# macOS universal binary
101
+
macos-universal = pkgs.stdenv.mkDerivation {
102
+
pname = "wisp-cli-macos-universal";
103
+
version = "0.4.2";
104
+
src = ./.;
105
+
106
+
nativeBuildInputs = [ rustToolchain pkgs.darwin.lipo ];
107
+
108
+
buildPhase = ''
109
+
export HOME=$(mktemp -d)
110
+
cargo build --release --target aarch64-apple-darwin
111
+
cargo build --release --target x86_64-apple-darwin
112
+
'';
113
+
114
+
installPhase = ''
115
+
mkdir -p $out/bin
116
+
lipo -create \
117
+
target/aarch64-apple-darwin/release/wisp-cli \
118
+
target/x86_64-apple-darwin/release/wisp-cli \
119
+
-output $out/bin/wisp-cli
120
+
'';
121
+
122
+
dontConfigure = true;
123
+
dontFixup = true;
124
+
};
125
+
} // (if pkgs.stdenv.isDarwin then linuxTargets else {});
126
+
127
+
devShells.default = pkgs.mkShell {
128
+
buildInputs = [
129
+
rustToolchain
130
+
pkgs.cargo-zigbuild
131
+
pkgs.zig
132
+
];
133
+
};
134
+
}
135
+
);
136
+
}
+1
-1
cli/src/blob_map.rs
+1
-1
cli/src/blob_map.rs
···
2
2
use jacquard_common::IntoStatic;
3
3
use std::collections::HashMap;
4
4
5
-
use crate::place_wisp::fs::{Directory, EntryNode};
5
+
use wisp_lexicons::place_wisp::fs::{Directory, EntryNode};
6
6
7
7
/// Extract blob information from a directory tree
8
8
/// Returns a map of file paths to their blob refs and CIDs
-43
cli/src/builder_types.rs
-43
cli/src/builder_types.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// This file was automatically generated from Lexicon schemas.
4
-
// Any manual changes will be overwritten on the next regeneration.
5
-
6
-
/// Marker type indicating a builder field has been set
7
-
pub struct Set<T>(pub T);
8
-
impl<T> Set<T> {
9
-
/// Extract the inner value
10
-
#[inline]
11
-
pub fn into_inner(self) -> T {
12
-
self.0
13
-
}
14
-
}
15
-
16
-
/// Marker type indicating a builder field has not been set
17
-
pub struct Unset;
18
-
/// Trait indicating a builder field is set (has a value)
19
-
#[rustversion::attr(
20
-
since(1.78.0),
21
-
diagnostic::on_unimplemented(
22
-
message = "the field `{Self}` was not set, but this method requires it to be set",
23
-
label = "the field `{Self}` was not set"
24
-
)
25
-
)]
26
-
pub trait IsSet: private::Sealed {}
27
-
/// Trait indicating a builder field is unset (no value yet)
28
-
#[rustversion::attr(
29
-
since(1.78.0),
30
-
diagnostic::on_unimplemented(
31
-
message = "the field `{Self}` was already set, but this method requires it to be unset",
32
-
label = "the field `{Self}` was already set"
33
-
)
34
-
)]
35
-
pub trait IsUnset: private::Sealed {}
36
-
impl<T> IsSet for Set<T> {}
37
-
impl IsUnset for Unset {}
38
-
mod private {
39
-
/// Sealed trait to prevent external implementations
40
-
pub trait Sealed {}
41
-
impl<T> Sealed for super::Set<T> {}
42
-
impl Sealed for super::Unset {}
43
-
}
-9
cli/src/lib.rs
-9
cli/src/lib.rs
+28
-31
cli/src/main.rs
+28
-31
cli/src/main.rs
···
1
-
mod builder_types;
2
-
mod place_wisp;
3
1
mod cid;
4
2
mod blob_map;
5
3
mod metadata;
···
28
26
use futures::stream::{self, StreamExt};
29
27
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
30
28
31
-
use place_wisp::fs::*;
32
-
use place_wisp::settings::*;
29
+
use wisp_lexicons::place_wisp::fs::*;
30
+
use wisp_lexicons::place_wisp::settings::*;
33
31
34
32
/// Maximum number of concurrent file uploads to the PDS
35
33
const MAX_CONCURRENT_UPLOADS: usize = 2;
···
43
41
struct Args {
44
42
#[command(subcommand)]
45
43
command: Option<Commands>,
46
-
44
+
47
45
// Deploy arguments (when no subcommand is specified)
48
46
/// Handle (e.g., alice.bsky.social), DID, or PDS URL
49
-
#[arg(global = true, conflicts_with = "command")]
50
47
input: Option<CowStr<'static>>,
51
48
52
49
/// Path to the directory containing your static site
53
-
#[arg(short, long, global = true, conflicts_with = "command")]
50
+
#[arg(short, long)]
54
51
path: Option<PathBuf>,
55
52
56
53
/// Site name (defaults to directory name)
57
-
#[arg(short, long, global = true, conflicts_with = "command")]
54
+
#[arg(short, long)]
58
55
site: Option<String>,
59
56
60
57
/// Path to auth store file
61
-
#[arg(long, global = true, conflicts_with = "command")]
58
+
#[arg(long)]
62
59
store: Option<String>,
63
60
64
61
/// App Password for authentication
65
-
#[arg(long, global = true, conflicts_with = "command")]
62
+
#[arg(long)]
66
63
password: Option<CowStr<'static>>,
67
64
68
65
/// Enable directory listing mode for paths without index files
69
-
#[arg(long, global = true, conflicts_with = "command")]
66
+
#[arg(long)]
70
67
directory: bool,
71
68
72
69
/// Enable SPA mode (serve index.html for all routes)
73
-
#[arg(long, global = true, conflicts_with = "command")]
70
+
#[arg(long)]
74
71
spa: bool,
75
72
76
73
/// Skip confirmation prompts (automatically accept warnings)
77
-
#[arg(short = 'y', long, global = true, conflicts_with = "command")]
74
+
#[arg(short = 'y', long)]
78
75
yes: bool,
79
76
}
80
77
···
124
121
125
122
/// Output directory for the downloaded site
126
123
#[arg(short, long, default_value = ".")]
127
-
output: PathBuf,
124
+
path: PathBuf,
128
125
},
129
126
/// Serve a site locally with real-time firehose updates
130
127
Serve {
···
137
134
138
135
/// Output directory for the site files
139
136
#[arg(short, long, default_value = ".")]
140
-
output: PathBuf,
137
+
path: PathBuf,
141
138
142
139
/// Port to serve on
143
-
#[arg(short, long, default_value = "8080")]
140
+
#[arg(short = 'P', long, default_value = "8080")]
144
141
port: u16,
145
142
},
146
143
}
···
158
155
run_with_oauth(input, store, path, site, directory, spa, yes).await
159
156
}
160
157
}
161
-
Some(Commands::Pull { input, site, output }) => {
162
-
pull::pull_site(input, CowStr::from(site), output).await
158
+
Some(Commands::Pull { input, site, path }) => {
159
+
pull::pull_site(input, CowStr::from(site), path).await
163
160
}
164
-
Some(Commands::Serve { input, site, output, port }) => {
165
-
serve::serve_site(input, CowStr::from(site), output, port).await
161
+
Some(Commands::Serve { input, site, path, port }) => {
162
+
serve::serve_site(input, CowStr::from(site), path, port).await
166
163
}
167
164
None => {
168
165
// Legacy mode: if input is provided, assume deploy command
···
512
509
let chunk_file_count = subfs_utils::count_files_in_directory(chunk);
513
510
let chunk_size = subfs_utils::estimate_directory_size(chunk);
514
511
515
-
let chunk_manifest = crate::place_wisp::subfs::SubfsRecord::new()
512
+
let chunk_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new()
516
513
.root(convert_fs_dir_to_subfs_dir(chunk.clone()))
517
514
.file_count(Some(chunk_file_count as i64))
518
515
.created_at(Datetime::now())
···
535
532
// Each chunk reference MUST have flat: true to merge chunk contents
536
533
println!(" โ Creating parent subfs with {} chunk references...", chunk_uris.len());
537
534
use jacquard_common::CowStr;
538
-
use crate::place_wisp::fs::{Subfs};
535
+
use wisp_lexicons::place_wisp::fs::{Subfs};
539
536
540
537
// Convert to fs::Subfs (which has the 'flat' field) instead of subfs::Subfs
541
538
let parent_entries_fs: Vec<Entry> = chunk_uris.iter().enumerate().map(|(i, (uri, _))| {
···
565
562
let parent_tid = Tid::now_0();
566
563
let parent_rkey = parent_tid.to_string();
567
564
568
-
let parent_manifest = crate::place_wisp::subfs::SubfsRecord::new()
565
+
let parent_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new()
569
566
.root(parent_root_subfs)
570
567
.file_count(Some(largest_dir.file_count as i64))
571
568
.created_at(Datetime::now())
···
584
581
let subfs_tid = Tid::now_0();
585
582
let subfs_rkey = subfs_tid.to_string();
586
583
587
-
let subfs_manifest = crate::place_wisp::subfs::SubfsRecord::new()
584
+
let subfs_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new()
588
585
.root(convert_fs_dir_to_subfs_dir(largest_dir.directory.clone()))
589
586
.file_count(Some(largest_dir.file_count as i64))
590
587
.created_at(Datetime::now())
···
952
949
953
950
/// Convert fs::Directory to subfs::Directory
954
951
/// They have the same structure, but different types
955
-
fn convert_fs_dir_to_subfs_dir(fs_dir: place_wisp::fs::Directory<'static>) -> place_wisp::subfs::Directory<'static> {
956
-
use place_wisp::subfs::{Directory as SubfsDirectory, Entry as SubfsEntry, EntryNode as SubfsEntryNode, File as SubfsFile};
952
+
fn convert_fs_dir_to_subfs_dir(fs_dir: wisp_lexicons::place_wisp::fs::Directory<'static>) -> wisp_lexicons::place_wisp::subfs::Directory<'static> {
953
+
use wisp_lexicons::place_wisp::subfs::{Directory as SubfsDirectory, Entry as SubfsEntry, EntryNode as SubfsEntryNode, File as SubfsFile};
957
954
958
955
let subfs_entries: Vec<SubfsEntry> = fs_dir.entries.into_iter().map(|entry| {
959
956
let node = match entry.node {
960
-
place_wisp::fs::EntryNode::File(file) => {
957
+
wisp_lexicons::place_wisp::fs::EntryNode::File(file) => {
961
958
SubfsEntryNode::File(Box::new(SubfsFile::new()
962
959
.r#type(file.r#type)
963
960
.blob(file.blob)
···
966
963
.base64(file.base64)
967
964
.build()))
968
965
}
969
-
place_wisp::fs::EntryNode::Directory(dir) => {
966
+
wisp_lexicons::place_wisp::fs::EntryNode::Directory(dir) => {
970
967
SubfsEntryNode::Directory(Box::new(convert_fs_dir_to_subfs_dir(*dir)))
971
968
}
972
-
place_wisp::fs::EntryNode::Subfs(subfs) => {
969
+
wisp_lexicons::place_wisp::fs::EntryNode::Subfs(subfs) => {
973
970
// Nested subfs in the directory we're converting
974
971
// Note: subfs::Subfs doesn't have the 'flat' field - that's only in fs::Subfs
975
-
SubfsEntryNode::Subfs(Box::new(place_wisp::subfs::Subfs::new()
972
+
SubfsEntryNode::Subfs(Box::new(wisp_lexicons::place_wisp::subfs::Subfs::new()
976
973
.r#type(subfs.r#type)
977
974
.subject(subfs.subject)
978
975
.build()))
979
976
}
980
-
place_wisp::fs::EntryNode::Unknown(unknown) => {
977
+
wisp_lexicons::place_wisp::fs::EntryNode::Unknown(unknown) => {
981
978
SubfsEntryNode::Unknown(unknown)
982
979
}
983
980
};
-9
cli/src/mod.rs
-9
cli/src/mod.rs
-1490
cli/src/place_wisp/fs.rs
-1490
cli/src/place_wisp/fs.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// Lexicon: place.wisp.fs
4
-
//
5
-
// This file was automatically generated from Lexicon schemas.
6
-
// Any manual changes will be overwritten on the next regeneration.
7
-
8
-
#[jacquard_derive::lexicon]
9
-
#[derive(
10
-
serde::Serialize,
11
-
serde::Deserialize,
12
-
Debug,
13
-
Clone,
14
-
PartialEq,
15
-
Eq,
16
-
jacquard_derive::IntoStatic
17
-
)]
18
-
#[serde(rename_all = "camelCase")]
19
-
pub struct Directory<'a> {
20
-
#[serde(borrow)]
21
-
pub entries: Vec<crate::place_wisp::fs::Entry<'a>>,
22
-
#[serde(borrow)]
23
-
pub r#type: jacquard_common::CowStr<'a>,
24
-
}
25
-
26
-
pub mod directory_state {
27
-
28
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
-
#[allow(unused)]
30
-
use ::core::marker::PhantomData;
31
-
mod sealed {
32
-
pub trait Sealed {}
33
-
}
34
-
/// State trait tracking which required fields have been set
35
-
pub trait State: sealed::Sealed {
36
-
type Type;
37
-
type Entries;
38
-
}
39
-
/// Empty state - all required fields are unset
40
-
pub struct Empty(());
41
-
impl sealed::Sealed for Empty {}
42
-
impl State for Empty {
43
-
type Type = Unset;
44
-
type Entries = Unset;
45
-
}
46
-
///State transition - sets the `type` field to Set
47
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
-
impl<S: State> sealed::Sealed for SetType<S> {}
49
-
impl<S: State> State for SetType<S> {
50
-
type Type = Set<members::r#type>;
51
-
type Entries = S::Entries;
52
-
}
53
-
///State transition - sets the `entries` field to Set
54
-
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
-
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
-
impl<S: State> State for SetEntries<S> {
57
-
type Type = S::Type;
58
-
type Entries = Set<members::entries>;
59
-
}
60
-
/// Marker types for field names
61
-
#[allow(non_camel_case_types)]
62
-
pub mod members {
63
-
///Marker type for the `type` field
64
-
pub struct r#type(());
65
-
///Marker type for the `entries` field
66
-
pub struct entries(());
67
-
}
68
-
}
69
-
70
-
/// Builder for constructing an instance of this type
71
-
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
-
__unsafe_private_named: (
74
-
::core::option::Option<Vec<crate::place_wisp::fs::Entry<'a>>>,
75
-
::core::option::Option<jacquard_common::CowStr<'a>>,
76
-
),
77
-
_phantom: ::core::marker::PhantomData<&'a ()>,
78
-
}
79
-
80
-
impl<'a> Directory<'a> {
81
-
/// Create a new builder for this type
82
-
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
-
DirectoryBuilder::new()
84
-
}
85
-
}
86
-
87
-
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
-
/// Create a new builder with all fields unset
89
-
pub fn new() -> Self {
90
-
DirectoryBuilder {
91
-
_phantom_state: ::core::marker::PhantomData,
92
-
__unsafe_private_named: (None, None),
93
-
_phantom: ::core::marker::PhantomData,
94
-
}
95
-
}
96
-
}
97
-
98
-
impl<'a, S> DirectoryBuilder<'a, S>
99
-
where
100
-
S: directory_state::State,
101
-
S::Entries: directory_state::IsUnset,
102
-
{
103
-
/// Set the `entries` field (required)
104
-
pub fn entries(
105
-
mut self,
106
-
value: impl Into<Vec<crate::place_wisp::fs::Entry<'a>>>,
107
-
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
-
DirectoryBuilder {
110
-
_phantom_state: ::core::marker::PhantomData,
111
-
__unsafe_private_named: self.__unsafe_private_named,
112
-
_phantom: ::core::marker::PhantomData,
113
-
}
114
-
}
115
-
}
116
-
117
-
impl<'a, S> DirectoryBuilder<'a, S>
118
-
where
119
-
S: directory_state::State,
120
-
S::Type: directory_state::IsUnset,
121
-
{
122
-
/// Set the `type` field (required)
123
-
pub fn r#type(
124
-
mut self,
125
-
value: impl Into<jacquard_common::CowStr<'a>>,
126
-
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
-
DirectoryBuilder {
129
-
_phantom_state: ::core::marker::PhantomData,
130
-
__unsafe_private_named: self.__unsafe_private_named,
131
-
_phantom: ::core::marker::PhantomData,
132
-
}
133
-
}
134
-
}
135
-
136
-
impl<'a, S> DirectoryBuilder<'a, S>
137
-
where
138
-
S: directory_state::State,
139
-
S::Type: directory_state::IsSet,
140
-
S::Entries: directory_state::IsSet,
141
-
{
142
-
/// Build the final struct
143
-
pub fn build(self) -> Directory<'a> {
144
-
Directory {
145
-
entries: self.__unsafe_private_named.0.unwrap(),
146
-
r#type: self.__unsafe_private_named.1.unwrap(),
147
-
extra_data: Default::default(),
148
-
}
149
-
}
150
-
/// Build the final struct with custom extra_data
151
-
pub fn build_with_data(
152
-
self,
153
-
extra_data: std::collections::BTreeMap<
154
-
jacquard_common::smol_str::SmolStr,
155
-
jacquard_common::types::value::Data<'a>,
156
-
>,
157
-
) -> Directory<'a> {
158
-
Directory {
159
-
entries: self.__unsafe_private_named.0.unwrap(),
160
-
r#type: self.__unsafe_private_named.1.unwrap(),
161
-
extra_data: Some(extra_data),
162
-
}
163
-
}
164
-
}
165
-
166
-
fn lexicon_doc_place_wisp_fs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
-
::jacquard_lexicon::lexicon::LexiconDoc {
168
-
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
-
id: ::jacquard_common::CowStr::new_static("place.wisp.fs"),
170
-
revision: None,
171
-
description: None,
172
-
defs: {
173
-
let mut map = ::std::collections::BTreeMap::new();
174
-
map.insert(
175
-
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
-
description: None,
178
-
required: Some(
179
-
vec![
180
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
-
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
-
],
183
-
),
184
-
nullable: None,
185
-
properties: {
186
-
#[allow(unused_mut)]
187
-
let mut map = ::std::collections::BTreeMap::new();
188
-
map.insert(
189
-
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
-
description: None,
192
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
-
description: None,
194
-
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
-
}),
196
-
min_length: None,
197
-
max_length: Some(500usize),
198
-
}),
199
-
);
200
-
map.insert(
201
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
-
description: None,
204
-
format: None,
205
-
default: None,
206
-
min_length: None,
207
-
max_length: None,
208
-
min_graphemes: None,
209
-
max_graphemes: None,
210
-
r#enum: None,
211
-
r#const: None,
212
-
known_values: None,
213
-
}),
214
-
);
215
-
map
216
-
},
217
-
}),
218
-
);
219
-
map.insert(
220
-
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
-
description: None,
223
-
required: Some(
224
-
vec![
225
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
-
::jacquard_common::smol_str::SmolStr::new_static("node")
227
-
],
228
-
),
229
-
nullable: None,
230
-
properties: {
231
-
#[allow(unused_mut)]
232
-
let mut map = ::std::collections::BTreeMap::new();
233
-
map.insert(
234
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
-
description: None,
237
-
format: None,
238
-
default: None,
239
-
min_length: None,
240
-
max_length: Some(255usize),
241
-
min_graphemes: None,
242
-
max_graphemes: None,
243
-
r#enum: None,
244
-
r#const: None,
245
-
known_values: None,
246
-
}),
247
-
);
248
-
map.insert(
249
-
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
-
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
-
description: None,
252
-
refs: vec![
253
-
::jacquard_common::CowStr::new_static("#file"),
254
-
::jacquard_common::CowStr::new_static("#directory"),
255
-
::jacquard_common::CowStr::new_static("#subfs")
256
-
],
257
-
closed: None,
258
-
}),
259
-
);
260
-
map
261
-
},
262
-
}),
263
-
);
264
-
map.insert(
265
-
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
-
description: None,
268
-
required: Some(
269
-
vec![
270
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
-
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
-
],
273
-
),
274
-
nullable: None,
275
-
properties: {
276
-
#[allow(unused_mut)]
277
-
let mut map = ::std::collections::BTreeMap::new();
278
-
map.insert(
279
-
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
-
description: None,
282
-
default: None,
283
-
r#const: None,
284
-
}),
285
-
);
286
-
map.insert(
287
-
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
-
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
-
description: None,
290
-
accept: None,
291
-
max_size: None,
292
-
}),
293
-
);
294
-
map.insert(
295
-
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
-
description: Some(
298
-
::jacquard_common::CowStr::new_static(
299
-
"Content encoding (e.g., gzip for compressed files)",
300
-
),
301
-
),
302
-
format: None,
303
-
default: None,
304
-
min_length: None,
305
-
max_length: None,
306
-
min_graphemes: None,
307
-
max_graphemes: None,
308
-
r#enum: None,
309
-
r#const: None,
310
-
known_values: None,
311
-
}),
312
-
);
313
-
map.insert(
314
-
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
-
description: Some(
317
-
::jacquard_common::CowStr::new_static(
318
-
"Original MIME type before compression",
319
-
),
320
-
),
321
-
format: None,
322
-
default: None,
323
-
min_length: None,
324
-
max_length: None,
325
-
min_graphemes: None,
326
-
max_graphemes: None,
327
-
r#enum: None,
328
-
r#const: None,
329
-
known_values: None,
330
-
}),
331
-
);
332
-
map.insert(
333
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
-
description: None,
336
-
format: None,
337
-
default: None,
338
-
min_length: None,
339
-
max_length: None,
340
-
min_graphemes: None,
341
-
max_graphemes: None,
342
-
r#enum: None,
343
-
r#const: None,
344
-
known_values: None,
345
-
}),
346
-
);
347
-
map
348
-
},
349
-
}),
350
-
);
351
-
map.insert(
352
-
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
-
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
-
description: Some(
355
-
::jacquard_common::CowStr::new_static(
356
-
"Virtual filesystem manifest for a Wisp site",
357
-
),
358
-
),
359
-
key: None,
360
-
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
-
description: None,
362
-
required: Some(
363
-
vec![
364
-
::jacquard_common::smol_str::SmolStr::new_static("site"),
365
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
366
-
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
367
-
],
368
-
),
369
-
nullable: None,
370
-
properties: {
371
-
#[allow(unused_mut)]
372
-
let mut map = ::std::collections::BTreeMap::new();
373
-
map.insert(
374
-
::jacquard_common::smol_str::SmolStr::new_static(
375
-
"createdAt",
376
-
),
377
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
378
-
description: None,
379
-
format: Some(
380
-
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
381
-
),
382
-
default: None,
383
-
min_length: None,
384
-
max_length: None,
385
-
min_graphemes: None,
386
-
max_graphemes: None,
387
-
r#enum: None,
388
-
r#const: None,
389
-
known_values: None,
390
-
}),
391
-
);
392
-
map.insert(
393
-
::jacquard_common::smol_str::SmolStr::new_static(
394
-
"fileCount",
395
-
),
396
-
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
397
-
description: None,
398
-
default: None,
399
-
minimum: Some(0i64),
400
-
maximum: Some(1000i64),
401
-
r#enum: None,
402
-
r#const: None,
403
-
}),
404
-
);
405
-
map.insert(
406
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
407
-
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
408
-
description: None,
409
-
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
410
-
}),
411
-
);
412
-
map.insert(
413
-
::jacquard_common::smol_str::SmolStr::new_static("site"),
414
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
415
-
description: None,
416
-
format: None,
417
-
default: None,
418
-
min_length: None,
419
-
max_length: None,
420
-
min_graphemes: None,
421
-
max_graphemes: None,
422
-
r#enum: None,
423
-
r#const: None,
424
-
known_values: None,
425
-
}),
426
-
);
427
-
map
428
-
},
429
-
}),
430
-
}),
431
-
);
432
-
map.insert(
433
-
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
434
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
435
-
description: None,
436
-
required: Some(
437
-
vec![
438
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
439
-
::jacquard_common::smol_str::SmolStr::new_static("subject")
440
-
],
441
-
),
442
-
nullable: None,
443
-
properties: {
444
-
#[allow(unused_mut)]
445
-
let mut map = ::std::collections::BTreeMap::new();
446
-
map.insert(
447
-
::jacquard_common::smol_str::SmolStr::new_static("flat"),
448
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
449
-
description: None,
450
-
default: None,
451
-
r#const: None,
452
-
}),
453
-
);
454
-
map.insert(
455
-
::jacquard_common::smol_str::SmolStr::new_static("subject"),
456
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
457
-
description: Some(
458
-
::jacquard_common::CowStr::new_static(
459
-
"AT-URI pointing to a place.wisp.subfs record containing this subtree.",
460
-
),
461
-
),
462
-
format: Some(
463
-
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
464
-
),
465
-
default: None,
466
-
min_length: None,
467
-
max_length: None,
468
-
min_graphemes: None,
469
-
max_graphemes: None,
470
-
r#enum: None,
471
-
r#const: None,
472
-
known_values: None,
473
-
}),
474
-
);
475
-
map.insert(
476
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
477
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
478
-
description: None,
479
-
format: None,
480
-
default: None,
481
-
min_length: None,
482
-
max_length: None,
483
-
min_graphemes: None,
484
-
max_graphemes: None,
485
-
r#enum: None,
486
-
r#const: None,
487
-
known_values: None,
488
-
}),
489
-
);
490
-
map
491
-
},
492
-
}),
493
-
);
494
-
map
495
-
},
496
-
}
497
-
}
498
-
499
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
500
-
fn nsid() -> &'static str {
501
-
"place.wisp.fs"
502
-
}
503
-
fn def_name() -> &'static str {
504
-
"directory"
505
-
}
506
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
507
-
lexicon_doc_place_wisp_fs()
508
-
}
509
-
fn validate(
510
-
&self,
511
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
512
-
{
513
-
let value = &self.entries;
514
-
#[allow(unused_comparisons)]
515
-
if value.len() > 500usize {
516
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
517
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
518
-
"entries",
519
-
),
520
-
max: 500usize,
521
-
actual: value.len(),
522
-
});
523
-
}
524
-
}
525
-
Ok(())
526
-
}
527
-
}
528
-
529
-
#[jacquard_derive::lexicon]
530
-
#[derive(
531
-
serde::Serialize,
532
-
serde::Deserialize,
533
-
Debug,
534
-
Clone,
535
-
PartialEq,
536
-
Eq,
537
-
jacquard_derive::IntoStatic
538
-
)]
539
-
#[serde(rename_all = "camelCase")]
540
-
pub struct Entry<'a> {
541
-
#[serde(borrow)]
542
-
pub name: jacquard_common::CowStr<'a>,
543
-
#[serde(borrow)]
544
-
pub node: EntryNode<'a>,
545
-
}
546
-
547
-
pub mod entry_state {
548
-
549
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
550
-
#[allow(unused)]
551
-
use ::core::marker::PhantomData;
552
-
mod sealed {
553
-
pub trait Sealed {}
554
-
}
555
-
/// State trait tracking which required fields have been set
556
-
pub trait State: sealed::Sealed {
557
-
type Name;
558
-
type Node;
559
-
}
560
-
/// Empty state - all required fields are unset
561
-
pub struct Empty(());
562
-
impl sealed::Sealed for Empty {}
563
-
impl State for Empty {
564
-
type Name = Unset;
565
-
type Node = Unset;
566
-
}
567
-
///State transition - sets the `name` field to Set
568
-
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
569
-
impl<S: State> sealed::Sealed for SetName<S> {}
570
-
impl<S: State> State for SetName<S> {
571
-
type Name = Set<members::name>;
572
-
type Node = S::Node;
573
-
}
574
-
///State transition - sets the `node` field to Set
575
-
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
576
-
impl<S: State> sealed::Sealed for SetNode<S> {}
577
-
impl<S: State> State for SetNode<S> {
578
-
type Name = S::Name;
579
-
type Node = Set<members::node>;
580
-
}
581
-
/// Marker types for field names
582
-
#[allow(non_camel_case_types)]
583
-
pub mod members {
584
-
///Marker type for the `name` field
585
-
pub struct name(());
586
-
///Marker type for the `node` field
587
-
pub struct node(());
588
-
}
589
-
}
590
-
591
-
/// Builder for constructing an instance of this type
592
-
pub struct EntryBuilder<'a, S: entry_state::State> {
593
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
594
-
__unsafe_private_named: (
595
-
::core::option::Option<jacquard_common::CowStr<'a>>,
596
-
::core::option::Option<EntryNode<'a>>,
597
-
),
598
-
_phantom: ::core::marker::PhantomData<&'a ()>,
599
-
}
600
-
601
-
impl<'a> Entry<'a> {
602
-
/// Create a new builder for this type
603
-
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
604
-
EntryBuilder::new()
605
-
}
606
-
}
607
-
608
-
impl<'a> EntryBuilder<'a, entry_state::Empty> {
609
-
/// Create a new builder with all fields unset
610
-
pub fn new() -> Self {
611
-
EntryBuilder {
612
-
_phantom_state: ::core::marker::PhantomData,
613
-
__unsafe_private_named: (None, None),
614
-
_phantom: ::core::marker::PhantomData,
615
-
}
616
-
}
617
-
}
618
-
619
-
impl<'a, S> EntryBuilder<'a, S>
620
-
where
621
-
S: entry_state::State,
622
-
S::Name: entry_state::IsUnset,
623
-
{
624
-
/// Set the `name` field (required)
625
-
pub fn name(
626
-
mut self,
627
-
value: impl Into<jacquard_common::CowStr<'a>>,
628
-
) -> EntryBuilder<'a, entry_state::SetName<S>> {
629
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
630
-
EntryBuilder {
631
-
_phantom_state: ::core::marker::PhantomData,
632
-
__unsafe_private_named: self.__unsafe_private_named,
633
-
_phantom: ::core::marker::PhantomData,
634
-
}
635
-
}
636
-
}
637
-
638
-
impl<'a, S> EntryBuilder<'a, S>
639
-
where
640
-
S: entry_state::State,
641
-
S::Node: entry_state::IsUnset,
642
-
{
643
-
/// Set the `node` field (required)
644
-
pub fn node(
645
-
mut self,
646
-
value: impl Into<EntryNode<'a>>,
647
-
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
648
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
649
-
EntryBuilder {
650
-
_phantom_state: ::core::marker::PhantomData,
651
-
__unsafe_private_named: self.__unsafe_private_named,
652
-
_phantom: ::core::marker::PhantomData,
653
-
}
654
-
}
655
-
}
656
-
657
-
impl<'a, S> EntryBuilder<'a, S>
658
-
where
659
-
S: entry_state::State,
660
-
S::Name: entry_state::IsSet,
661
-
S::Node: entry_state::IsSet,
662
-
{
663
-
/// Build the final struct
664
-
pub fn build(self) -> Entry<'a> {
665
-
Entry {
666
-
name: self.__unsafe_private_named.0.unwrap(),
667
-
node: self.__unsafe_private_named.1.unwrap(),
668
-
extra_data: Default::default(),
669
-
}
670
-
}
671
-
/// Build the final struct with custom extra_data
672
-
pub fn build_with_data(
673
-
self,
674
-
extra_data: std::collections::BTreeMap<
675
-
jacquard_common::smol_str::SmolStr,
676
-
jacquard_common::types::value::Data<'a>,
677
-
>,
678
-
) -> Entry<'a> {
679
-
Entry {
680
-
name: self.__unsafe_private_named.0.unwrap(),
681
-
node: self.__unsafe_private_named.1.unwrap(),
682
-
extra_data: Some(extra_data),
683
-
}
684
-
}
685
-
}
686
-
687
-
#[jacquard_derive::open_union]
688
-
#[derive(
689
-
serde::Serialize,
690
-
serde::Deserialize,
691
-
Debug,
692
-
Clone,
693
-
PartialEq,
694
-
Eq,
695
-
jacquard_derive::IntoStatic
696
-
)]
697
-
#[serde(tag = "$type")]
698
-
#[serde(bound(deserialize = "'de: 'a"))]
699
-
pub enum EntryNode<'a> {
700
-
#[serde(rename = "place.wisp.fs#file")]
701
-
File(Box<crate::place_wisp::fs::File<'a>>),
702
-
#[serde(rename = "place.wisp.fs#directory")]
703
-
Directory(Box<crate::place_wisp::fs::Directory<'a>>),
704
-
#[serde(rename = "place.wisp.fs#subfs")]
705
-
Subfs(Box<crate::place_wisp::fs::Subfs<'a>>),
706
-
}
707
-
708
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
709
-
fn nsid() -> &'static str {
710
-
"place.wisp.fs"
711
-
}
712
-
fn def_name() -> &'static str {
713
-
"entry"
714
-
}
715
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
716
-
lexicon_doc_place_wisp_fs()
717
-
}
718
-
fn validate(
719
-
&self,
720
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
721
-
{
722
-
let value = &self.name;
723
-
#[allow(unused_comparisons)]
724
-
if <str>::len(value.as_ref()) > 255usize {
725
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
726
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
727
-
"name",
728
-
),
729
-
max: 255usize,
730
-
actual: <str>::len(value.as_ref()),
731
-
});
732
-
}
733
-
}
734
-
Ok(())
735
-
}
736
-
}
737
-
738
-
#[jacquard_derive::lexicon]
739
-
#[derive(
740
-
serde::Serialize,
741
-
serde::Deserialize,
742
-
Debug,
743
-
Clone,
744
-
PartialEq,
745
-
Eq,
746
-
jacquard_derive::IntoStatic
747
-
)]
748
-
#[serde(rename_all = "camelCase")]
749
-
pub struct File<'a> {
750
-
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
751
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
752
-
pub base64: Option<bool>,
753
-
/// Content blob ref
754
-
#[serde(borrow)]
755
-
pub blob: jacquard_common::types::blob::BlobRef<'a>,
756
-
/// Content encoding (e.g., gzip for compressed files)
757
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
758
-
#[serde(borrow)]
759
-
pub encoding: Option<jacquard_common::CowStr<'a>>,
760
-
/// Original MIME type before compression
761
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
762
-
#[serde(borrow)]
763
-
pub mime_type: Option<jacquard_common::CowStr<'a>>,
764
-
#[serde(borrow)]
765
-
pub r#type: jacquard_common::CowStr<'a>,
766
-
}
767
-
768
-
pub mod file_state {
769
-
770
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
771
-
#[allow(unused)]
772
-
use ::core::marker::PhantomData;
773
-
mod sealed {
774
-
pub trait Sealed {}
775
-
}
776
-
/// State trait tracking which required fields have been set
777
-
pub trait State: sealed::Sealed {
778
-
type Type;
779
-
type Blob;
780
-
}
781
-
/// Empty state - all required fields are unset
782
-
pub struct Empty(());
783
-
impl sealed::Sealed for Empty {}
784
-
impl State for Empty {
785
-
type Type = Unset;
786
-
type Blob = Unset;
787
-
}
788
-
///State transition - sets the `type` field to Set
789
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
790
-
impl<S: State> sealed::Sealed for SetType<S> {}
791
-
impl<S: State> State for SetType<S> {
792
-
type Type = Set<members::r#type>;
793
-
type Blob = S::Blob;
794
-
}
795
-
///State transition - sets the `blob` field to Set
796
-
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
797
-
impl<S: State> sealed::Sealed for SetBlob<S> {}
798
-
impl<S: State> State for SetBlob<S> {
799
-
type Type = S::Type;
800
-
type Blob = Set<members::blob>;
801
-
}
802
-
/// Marker types for field names
803
-
#[allow(non_camel_case_types)]
804
-
pub mod members {
805
-
///Marker type for the `type` field
806
-
pub struct r#type(());
807
-
///Marker type for the `blob` field
808
-
pub struct blob(());
809
-
}
810
-
}
811
-
812
-
/// Builder for constructing an instance of this type
813
-
pub struct FileBuilder<'a, S: file_state::State> {
814
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
815
-
__unsafe_private_named: (
816
-
::core::option::Option<bool>,
817
-
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
818
-
::core::option::Option<jacquard_common::CowStr<'a>>,
819
-
::core::option::Option<jacquard_common::CowStr<'a>>,
820
-
::core::option::Option<jacquard_common::CowStr<'a>>,
821
-
),
822
-
_phantom: ::core::marker::PhantomData<&'a ()>,
823
-
}
824
-
825
-
impl<'a> File<'a> {
826
-
/// Create a new builder for this type
827
-
pub fn new() -> FileBuilder<'a, file_state::Empty> {
828
-
FileBuilder::new()
829
-
}
830
-
}
831
-
832
-
impl<'a> FileBuilder<'a, file_state::Empty> {
833
-
/// Create a new builder with all fields unset
834
-
pub fn new() -> Self {
835
-
FileBuilder {
836
-
_phantom_state: ::core::marker::PhantomData,
837
-
__unsafe_private_named: (None, None, None, None, None),
838
-
_phantom: ::core::marker::PhantomData,
839
-
}
840
-
}
841
-
}
842
-
843
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
844
-
/// Set the `base64` field (optional)
845
-
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
846
-
self.__unsafe_private_named.0 = value.into();
847
-
self
848
-
}
849
-
/// Set the `base64` field to an Option value (optional)
850
-
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
851
-
self.__unsafe_private_named.0 = value;
852
-
self
853
-
}
854
-
}
855
-
856
-
impl<'a, S> FileBuilder<'a, S>
857
-
where
858
-
S: file_state::State,
859
-
S::Blob: file_state::IsUnset,
860
-
{
861
-
/// Set the `blob` field (required)
862
-
pub fn blob(
863
-
mut self,
864
-
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
865
-
) -> FileBuilder<'a, file_state::SetBlob<S>> {
866
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
867
-
FileBuilder {
868
-
_phantom_state: ::core::marker::PhantomData,
869
-
__unsafe_private_named: self.__unsafe_private_named,
870
-
_phantom: ::core::marker::PhantomData,
871
-
}
872
-
}
873
-
}
874
-
875
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
876
-
/// Set the `encoding` field (optional)
877
-
pub fn encoding(
878
-
mut self,
879
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
880
-
) -> Self {
881
-
self.__unsafe_private_named.2 = value.into();
882
-
self
883
-
}
884
-
/// Set the `encoding` field to an Option value (optional)
885
-
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
886
-
self.__unsafe_private_named.2 = value;
887
-
self
888
-
}
889
-
}
890
-
891
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
892
-
/// Set the `mimeType` field (optional)
893
-
pub fn mime_type(
894
-
mut self,
895
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
896
-
) -> Self {
897
-
self.__unsafe_private_named.3 = value.into();
898
-
self
899
-
}
900
-
/// Set the `mimeType` field to an Option value (optional)
901
-
pub fn maybe_mime_type(
902
-
mut self,
903
-
value: Option<jacquard_common::CowStr<'a>>,
904
-
) -> Self {
905
-
self.__unsafe_private_named.3 = value;
906
-
self
907
-
}
908
-
}
909
-
910
-
impl<'a, S> FileBuilder<'a, S>
911
-
where
912
-
S: file_state::State,
913
-
S::Type: file_state::IsUnset,
914
-
{
915
-
/// Set the `type` field (required)
916
-
pub fn r#type(
917
-
mut self,
918
-
value: impl Into<jacquard_common::CowStr<'a>>,
919
-
) -> FileBuilder<'a, file_state::SetType<S>> {
920
-
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
921
-
FileBuilder {
922
-
_phantom_state: ::core::marker::PhantomData,
923
-
__unsafe_private_named: self.__unsafe_private_named,
924
-
_phantom: ::core::marker::PhantomData,
925
-
}
926
-
}
927
-
}
928
-
929
-
impl<'a, S> FileBuilder<'a, S>
930
-
where
931
-
S: file_state::State,
932
-
S::Type: file_state::IsSet,
933
-
S::Blob: file_state::IsSet,
934
-
{
935
-
/// Build the final struct
936
-
pub fn build(self) -> File<'a> {
937
-
File {
938
-
base64: self.__unsafe_private_named.0,
939
-
blob: self.__unsafe_private_named.1.unwrap(),
940
-
encoding: self.__unsafe_private_named.2,
941
-
mime_type: self.__unsafe_private_named.3,
942
-
r#type: self.__unsafe_private_named.4.unwrap(),
943
-
extra_data: Default::default(),
944
-
}
945
-
}
946
-
/// Build the final struct with custom extra_data
947
-
pub fn build_with_data(
948
-
self,
949
-
extra_data: std::collections::BTreeMap<
950
-
jacquard_common::smol_str::SmolStr,
951
-
jacquard_common::types::value::Data<'a>,
952
-
>,
953
-
) -> File<'a> {
954
-
File {
955
-
base64: self.__unsafe_private_named.0,
956
-
blob: self.__unsafe_private_named.1.unwrap(),
957
-
encoding: self.__unsafe_private_named.2,
958
-
mime_type: self.__unsafe_private_named.3,
959
-
r#type: self.__unsafe_private_named.4.unwrap(),
960
-
extra_data: Some(extra_data),
961
-
}
962
-
}
963
-
}
964
-
965
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
966
-
fn nsid() -> &'static str {
967
-
"place.wisp.fs"
968
-
}
969
-
fn def_name() -> &'static str {
970
-
"file"
971
-
}
972
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
973
-
lexicon_doc_place_wisp_fs()
974
-
}
975
-
fn validate(
976
-
&self,
977
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
978
-
Ok(())
979
-
}
980
-
}
981
-
982
-
/// Virtual filesystem manifest for a Wisp site
983
-
#[jacquard_derive::lexicon]
984
-
#[derive(
985
-
serde::Serialize,
986
-
serde::Deserialize,
987
-
Debug,
988
-
Clone,
989
-
PartialEq,
990
-
Eq,
991
-
jacquard_derive::IntoStatic
992
-
)]
993
-
#[serde(rename_all = "camelCase")]
994
-
pub struct Fs<'a> {
995
-
pub created_at: jacquard_common::types::string::Datetime,
996
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
997
-
pub file_count: Option<i64>,
998
-
#[serde(borrow)]
999
-
pub root: crate::place_wisp::fs::Directory<'a>,
1000
-
#[serde(borrow)]
1001
-
pub site: jacquard_common::CowStr<'a>,
1002
-
}
1003
-
1004
-
pub mod fs_state {
1005
-
1006
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1007
-
#[allow(unused)]
1008
-
use ::core::marker::PhantomData;
1009
-
mod sealed {
1010
-
pub trait Sealed {}
1011
-
}
1012
-
/// State trait tracking which required fields have been set
1013
-
pub trait State: sealed::Sealed {
1014
-
type Site;
1015
-
type Root;
1016
-
type CreatedAt;
1017
-
}
1018
-
/// Empty state - all required fields are unset
1019
-
pub struct Empty(());
1020
-
impl sealed::Sealed for Empty {}
1021
-
impl State for Empty {
1022
-
type Site = Unset;
1023
-
type Root = Unset;
1024
-
type CreatedAt = Unset;
1025
-
}
1026
-
///State transition - sets the `site` field to Set
1027
-
pub struct SetSite<S: State = Empty>(PhantomData<fn() -> S>);
1028
-
impl<S: State> sealed::Sealed for SetSite<S> {}
1029
-
impl<S: State> State for SetSite<S> {
1030
-
type Site = Set<members::site>;
1031
-
type Root = S::Root;
1032
-
type CreatedAt = S::CreatedAt;
1033
-
}
1034
-
///State transition - sets the `root` field to Set
1035
-
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1036
-
impl<S: State> sealed::Sealed for SetRoot<S> {}
1037
-
impl<S: State> State for SetRoot<S> {
1038
-
type Site = S::Site;
1039
-
type Root = Set<members::root>;
1040
-
type CreatedAt = S::CreatedAt;
1041
-
}
1042
-
///State transition - sets the `created_at` field to Set
1043
-
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1044
-
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1045
-
impl<S: State> State for SetCreatedAt<S> {
1046
-
type Site = S::Site;
1047
-
type Root = S::Root;
1048
-
type CreatedAt = Set<members::created_at>;
1049
-
}
1050
-
/// Marker types for field names
1051
-
#[allow(non_camel_case_types)]
1052
-
pub mod members {
1053
-
///Marker type for the `site` field
1054
-
pub struct site(());
1055
-
///Marker type for the `root` field
1056
-
pub struct root(());
1057
-
///Marker type for the `created_at` field
1058
-
pub struct created_at(());
1059
-
}
1060
-
}
1061
-
1062
-
/// Builder for constructing an instance of this type
1063
-
pub struct FsBuilder<'a, S: fs_state::State> {
1064
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1065
-
__unsafe_private_named: (
1066
-
::core::option::Option<jacquard_common::types::string::Datetime>,
1067
-
::core::option::Option<i64>,
1068
-
::core::option::Option<crate::place_wisp::fs::Directory<'a>>,
1069
-
::core::option::Option<jacquard_common::CowStr<'a>>,
1070
-
),
1071
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1072
-
}
1073
-
1074
-
impl<'a> Fs<'a> {
1075
-
/// Create a new builder for this type
1076
-
pub fn new() -> FsBuilder<'a, fs_state::Empty> {
1077
-
FsBuilder::new()
1078
-
}
1079
-
}
1080
-
1081
-
impl<'a> FsBuilder<'a, fs_state::Empty> {
1082
-
/// Create a new builder with all fields unset
1083
-
pub fn new() -> Self {
1084
-
FsBuilder {
1085
-
_phantom_state: ::core::marker::PhantomData,
1086
-
__unsafe_private_named: (None, None, None, None),
1087
-
_phantom: ::core::marker::PhantomData,
1088
-
}
1089
-
}
1090
-
}
1091
-
1092
-
impl<'a, S> FsBuilder<'a, S>
1093
-
where
1094
-
S: fs_state::State,
1095
-
S::CreatedAt: fs_state::IsUnset,
1096
-
{
1097
-
/// Set the `createdAt` field (required)
1098
-
pub fn created_at(
1099
-
mut self,
1100
-
value: impl Into<jacquard_common::types::string::Datetime>,
1101
-
) -> FsBuilder<'a, fs_state::SetCreatedAt<S>> {
1102
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1103
-
FsBuilder {
1104
-
_phantom_state: ::core::marker::PhantomData,
1105
-
__unsafe_private_named: self.__unsafe_private_named,
1106
-
_phantom: ::core::marker::PhantomData,
1107
-
}
1108
-
}
1109
-
}
1110
-
1111
-
impl<'a, S: fs_state::State> FsBuilder<'a, S> {
1112
-
/// Set the `fileCount` field (optional)
1113
-
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1114
-
self.__unsafe_private_named.1 = value.into();
1115
-
self
1116
-
}
1117
-
/// Set the `fileCount` field to an Option value (optional)
1118
-
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1119
-
self.__unsafe_private_named.1 = value;
1120
-
self
1121
-
}
1122
-
}
1123
-
1124
-
impl<'a, S> FsBuilder<'a, S>
1125
-
where
1126
-
S: fs_state::State,
1127
-
S::Root: fs_state::IsUnset,
1128
-
{
1129
-
/// Set the `root` field (required)
1130
-
pub fn root(
1131
-
mut self,
1132
-
value: impl Into<crate::place_wisp::fs::Directory<'a>>,
1133
-
) -> FsBuilder<'a, fs_state::SetRoot<S>> {
1134
-
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1135
-
FsBuilder {
1136
-
_phantom_state: ::core::marker::PhantomData,
1137
-
__unsafe_private_named: self.__unsafe_private_named,
1138
-
_phantom: ::core::marker::PhantomData,
1139
-
}
1140
-
}
1141
-
}
1142
-
1143
-
impl<'a, S> FsBuilder<'a, S>
1144
-
where
1145
-
S: fs_state::State,
1146
-
S::Site: fs_state::IsUnset,
1147
-
{
1148
-
/// Set the `site` field (required)
1149
-
pub fn site(
1150
-
mut self,
1151
-
value: impl Into<jacquard_common::CowStr<'a>>,
1152
-
) -> FsBuilder<'a, fs_state::SetSite<S>> {
1153
-
self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into());
1154
-
FsBuilder {
1155
-
_phantom_state: ::core::marker::PhantomData,
1156
-
__unsafe_private_named: self.__unsafe_private_named,
1157
-
_phantom: ::core::marker::PhantomData,
1158
-
}
1159
-
}
1160
-
}
1161
-
1162
-
impl<'a, S> FsBuilder<'a, S>
1163
-
where
1164
-
S: fs_state::State,
1165
-
S::Site: fs_state::IsSet,
1166
-
S::Root: fs_state::IsSet,
1167
-
S::CreatedAt: fs_state::IsSet,
1168
-
{
1169
-
/// Build the final struct
1170
-
pub fn build(self) -> Fs<'a> {
1171
-
Fs {
1172
-
created_at: self.__unsafe_private_named.0.unwrap(),
1173
-
file_count: self.__unsafe_private_named.1,
1174
-
root: self.__unsafe_private_named.2.unwrap(),
1175
-
site: self.__unsafe_private_named.3.unwrap(),
1176
-
extra_data: Default::default(),
1177
-
}
1178
-
}
1179
-
/// Build the final struct with custom extra_data
1180
-
pub fn build_with_data(
1181
-
self,
1182
-
extra_data: std::collections::BTreeMap<
1183
-
jacquard_common::smol_str::SmolStr,
1184
-
jacquard_common::types::value::Data<'a>,
1185
-
>,
1186
-
) -> Fs<'a> {
1187
-
Fs {
1188
-
created_at: self.__unsafe_private_named.0.unwrap(),
1189
-
file_count: self.__unsafe_private_named.1,
1190
-
root: self.__unsafe_private_named.2.unwrap(),
1191
-
site: self.__unsafe_private_named.3.unwrap(),
1192
-
extra_data: Some(extra_data),
1193
-
}
1194
-
}
1195
-
}
1196
-
1197
-
impl<'a> Fs<'a> {
1198
-
pub fn uri(
1199
-
uri: impl Into<jacquard_common::CowStr<'a>>,
1200
-
) -> Result<
1201
-
jacquard_common::types::uri::RecordUri<'a, FsRecord>,
1202
-
jacquard_common::types::uri::UriError,
1203
-
> {
1204
-
jacquard_common::types::uri::RecordUri::try_from_uri(
1205
-
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1206
-
)
1207
-
}
1208
-
}
1209
-
1210
-
/// Typed wrapper for GetRecord response with this collection's record type.
1211
-
#[derive(
1212
-
serde::Serialize,
1213
-
serde::Deserialize,
1214
-
Debug,
1215
-
Clone,
1216
-
PartialEq,
1217
-
Eq,
1218
-
jacquard_derive::IntoStatic
1219
-
)]
1220
-
#[serde(rename_all = "camelCase")]
1221
-
pub struct FsGetRecordOutput<'a> {
1222
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1223
-
#[serde(borrow)]
1224
-
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1225
-
#[serde(borrow)]
1226
-
pub uri: jacquard_common::types::string::AtUri<'a>,
1227
-
#[serde(borrow)]
1228
-
pub value: Fs<'a>,
1229
-
}
1230
-
1231
-
impl From<FsGetRecordOutput<'_>> for Fs<'_> {
1232
-
fn from(output: FsGetRecordOutput<'_>) -> Self {
1233
-
use jacquard_common::IntoStatic;
1234
-
output.value.into_static()
1235
-
}
1236
-
}
1237
-
1238
-
impl jacquard_common::types::collection::Collection for Fs<'_> {
1239
-
const NSID: &'static str = "place.wisp.fs";
1240
-
type Record = FsRecord;
1241
-
}
1242
-
1243
-
/// Marker type for deserializing records from this collection.
1244
-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1245
-
pub struct FsRecord;
1246
-
impl jacquard_common::xrpc::XrpcResp for FsRecord {
1247
-
const NSID: &'static str = "place.wisp.fs";
1248
-
const ENCODING: &'static str = "application/json";
1249
-
type Output<'de> = FsGetRecordOutput<'de>;
1250
-
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1251
-
}
1252
-
1253
-
impl jacquard_common::types::collection::Collection for FsRecord {
1254
-
const NSID: &'static str = "place.wisp.fs";
1255
-
type Record = FsRecord;
1256
-
}
1257
-
1258
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Fs<'a> {
1259
-
fn nsid() -> &'static str {
1260
-
"place.wisp.fs"
1261
-
}
1262
-
fn def_name() -> &'static str {
1263
-
"main"
1264
-
}
1265
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1266
-
lexicon_doc_place_wisp_fs()
1267
-
}
1268
-
fn validate(
1269
-
&self,
1270
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1271
-
if let Some(ref value) = self.file_count {
1272
-
if *value > 1000i64 {
1273
-
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1274
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1275
-
"file_count",
1276
-
),
1277
-
max: 1000i64,
1278
-
actual: *value,
1279
-
});
1280
-
}
1281
-
}
1282
-
if let Some(ref value) = self.file_count {
1283
-
if *value < 0i64 {
1284
-
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1285
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1286
-
"file_count",
1287
-
),
1288
-
min: 0i64,
1289
-
actual: *value,
1290
-
});
1291
-
}
1292
-
}
1293
-
Ok(())
1294
-
}
1295
-
}
1296
-
1297
-
#[jacquard_derive::lexicon]
1298
-
#[derive(
1299
-
serde::Serialize,
1300
-
serde::Deserialize,
1301
-
Debug,
1302
-
Clone,
1303
-
PartialEq,
1304
-
Eq,
1305
-
jacquard_derive::IntoStatic
1306
-
)]
1307
-
#[serde(rename_all = "camelCase")]
1308
-
pub struct Subfs<'a> {
1309
-
/// If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), 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.
1310
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1311
-
pub flat: Option<bool>,
1312
-
/// AT-URI pointing to a place.wisp.subfs record containing this subtree.
1313
-
#[serde(borrow)]
1314
-
pub subject: jacquard_common::types::string::AtUri<'a>,
1315
-
#[serde(borrow)]
1316
-
pub r#type: jacquard_common::CowStr<'a>,
1317
-
}
1318
-
1319
-
pub mod subfs_state {
1320
-
1321
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1322
-
#[allow(unused)]
1323
-
use ::core::marker::PhantomData;
1324
-
mod sealed {
1325
-
pub trait Sealed {}
1326
-
}
1327
-
/// State trait tracking which required fields have been set
1328
-
pub trait State: sealed::Sealed {
1329
-
type Type;
1330
-
type Subject;
1331
-
}
1332
-
/// Empty state - all required fields are unset
1333
-
pub struct Empty(());
1334
-
impl sealed::Sealed for Empty {}
1335
-
impl State for Empty {
1336
-
type Type = Unset;
1337
-
type Subject = Unset;
1338
-
}
1339
-
///State transition - sets the `type` field to Set
1340
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1341
-
impl<S: State> sealed::Sealed for SetType<S> {}
1342
-
impl<S: State> State for SetType<S> {
1343
-
type Type = Set<members::r#type>;
1344
-
type Subject = S::Subject;
1345
-
}
1346
-
///State transition - sets the `subject` field to Set
1347
-
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1348
-
impl<S: State> sealed::Sealed for SetSubject<S> {}
1349
-
impl<S: State> State for SetSubject<S> {
1350
-
type Type = S::Type;
1351
-
type Subject = Set<members::subject>;
1352
-
}
1353
-
/// Marker types for field names
1354
-
#[allow(non_camel_case_types)]
1355
-
pub mod members {
1356
-
///Marker type for the `type` field
1357
-
pub struct r#type(());
1358
-
///Marker type for the `subject` field
1359
-
pub struct subject(());
1360
-
}
1361
-
}
1362
-
1363
-
/// Builder for constructing an instance of this type
1364
-
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1365
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1366
-
__unsafe_private_named: (
1367
-
::core::option::Option<bool>,
1368
-
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1369
-
::core::option::Option<jacquard_common::CowStr<'a>>,
1370
-
),
1371
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1372
-
}
1373
-
1374
-
impl<'a> Subfs<'a> {
1375
-
/// Create a new builder for this type
1376
-
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1377
-
SubfsBuilder::new()
1378
-
}
1379
-
}
1380
-
1381
-
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1382
-
/// Create a new builder with all fields unset
1383
-
pub fn new() -> Self {
1384
-
SubfsBuilder {
1385
-
_phantom_state: ::core::marker::PhantomData,
1386
-
__unsafe_private_named: (None, None, None),
1387
-
_phantom: ::core::marker::PhantomData,
1388
-
}
1389
-
}
1390
-
}
1391
-
1392
-
impl<'a, S: subfs_state::State> SubfsBuilder<'a, S> {
1393
-
/// Set the `flat` field (optional)
1394
-
pub fn flat(mut self, value: impl Into<Option<bool>>) -> Self {
1395
-
self.__unsafe_private_named.0 = value.into();
1396
-
self
1397
-
}
1398
-
/// Set the `flat` field to an Option value (optional)
1399
-
pub fn maybe_flat(mut self, value: Option<bool>) -> Self {
1400
-
self.__unsafe_private_named.0 = value;
1401
-
self
1402
-
}
1403
-
}
1404
-
1405
-
impl<'a, S> SubfsBuilder<'a, S>
1406
-
where
1407
-
S: subfs_state::State,
1408
-
S::Subject: subfs_state::IsUnset,
1409
-
{
1410
-
/// Set the `subject` field (required)
1411
-
pub fn subject(
1412
-
mut self,
1413
-
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1414
-
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1415
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1416
-
SubfsBuilder {
1417
-
_phantom_state: ::core::marker::PhantomData,
1418
-
__unsafe_private_named: self.__unsafe_private_named,
1419
-
_phantom: ::core::marker::PhantomData,
1420
-
}
1421
-
}
1422
-
}
1423
-
1424
-
impl<'a, S> SubfsBuilder<'a, S>
1425
-
where
1426
-
S: subfs_state::State,
1427
-
S::Type: subfs_state::IsUnset,
1428
-
{
1429
-
/// Set the `type` field (required)
1430
-
pub fn r#type(
1431
-
mut self,
1432
-
value: impl Into<jacquard_common::CowStr<'a>>,
1433
-
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1434
-
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1435
-
SubfsBuilder {
1436
-
_phantom_state: ::core::marker::PhantomData,
1437
-
__unsafe_private_named: self.__unsafe_private_named,
1438
-
_phantom: ::core::marker::PhantomData,
1439
-
}
1440
-
}
1441
-
}
1442
-
1443
-
impl<'a, S> SubfsBuilder<'a, S>
1444
-
where
1445
-
S: subfs_state::State,
1446
-
S::Type: subfs_state::IsSet,
1447
-
S::Subject: subfs_state::IsSet,
1448
-
{
1449
-
/// Build the final struct
1450
-
pub fn build(self) -> Subfs<'a> {
1451
-
Subfs {
1452
-
flat: self.__unsafe_private_named.0,
1453
-
subject: self.__unsafe_private_named.1.unwrap(),
1454
-
r#type: self.__unsafe_private_named.2.unwrap(),
1455
-
extra_data: Default::default(),
1456
-
}
1457
-
}
1458
-
/// Build the final struct with custom extra_data
1459
-
pub fn build_with_data(
1460
-
self,
1461
-
extra_data: std::collections::BTreeMap<
1462
-
jacquard_common::smol_str::SmolStr,
1463
-
jacquard_common::types::value::Data<'a>,
1464
-
>,
1465
-
) -> Subfs<'a> {
1466
-
Subfs {
1467
-
flat: self.__unsafe_private_named.0,
1468
-
subject: self.__unsafe_private_named.1.unwrap(),
1469
-
r#type: self.__unsafe_private_named.2.unwrap(),
1470
-
extra_data: Some(extra_data),
1471
-
}
1472
-
}
1473
-
}
1474
-
1475
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1476
-
fn nsid() -> &'static str {
1477
-
"place.wisp.fs"
1478
-
}
1479
-
fn def_name() -> &'static str {
1480
-
"subfs"
1481
-
}
1482
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1483
-
lexicon_doc_place_wisp_fs()
1484
-
}
1485
-
fn validate(
1486
-
&self,
1487
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1488
-
Ok(())
1489
-
}
1490
-
}
-653
cli/src/place_wisp/settings.rs
-653
cli/src/place_wisp/settings.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// Lexicon: place.wisp.settings
4
-
//
5
-
// This file was automatically generated from Lexicon schemas.
6
-
// Any manual changes will be overwritten on the next regeneration.
7
-
8
-
/// Custom HTTP header configuration
9
-
#[jacquard_derive::lexicon]
10
-
#[derive(
11
-
serde::Serialize,
12
-
serde::Deserialize,
13
-
Debug,
14
-
Clone,
15
-
PartialEq,
16
-
Eq,
17
-
jacquard_derive::IntoStatic,
18
-
Default
19
-
)]
20
-
#[serde(rename_all = "camelCase")]
21
-
pub struct CustomHeader<'a> {
22
-
/// HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')
23
-
#[serde(borrow)]
24
-
pub name: jacquard_common::CowStr<'a>,
25
-
/// Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.
26
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
27
-
#[serde(borrow)]
28
-
pub path: std::option::Option<jacquard_common::CowStr<'a>>,
29
-
/// HTTP header value
30
-
#[serde(borrow)]
31
-
pub value: jacquard_common::CowStr<'a>,
32
-
}
33
-
34
-
fn lexicon_doc_place_wisp_settings() -> ::jacquard_lexicon::lexicon::LexiconDoc<
35
-
'static,
36
-
> {
37
-
::jacquard_lexicon::lexicon::LexiconDoc {
38
-
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
39
-
id: ::jacquard_common::CowStr::new_static("place.wisp.settings"),
40
-
revision: None,
41
-
description: None,
42
-
defs: {
43
-
let mut map = ::std::collections::BTreeMap::new();
44
-
map.insert(
45
-
::jacquard_common::smol_str::SmolStr::new_static("customHeader"),
46
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
47
-
description: Some(
48
-
::jacquard_common::CowStr::new_static(
49
-
"Custom HTTP header configuration",
50
-
),
51
-
),
52
-
required: Some(
53
-
vec![
54
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
55
-
::jacquard_common::smol_str::SmolStr::new_static("value")
56
-
],
57
-
),
58
-
nullable: None,
59
-
properties: {
60
-
#[allow(unused_mut)]
61
-
let mut map = ::std::collections::BTreeMap::new();
62
-
map.insert(
63
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
64
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
65
-
description: Some(
66
-
::jacquard_common::CowStr::new_static(
67
-
"HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
68
-
),
69
-
),
70
-
format: None,
71
-
default: None,
72
-
min_length: None,
73
-
max_length: Some(100usize),
74
-
min_graphemes: None,
75
-
max_graphemes: None,
76
-
r#enum: None,
77
-
r#const: None,
78
-
known_values: None,
79
-
}),
80
-
);
81
-
map.insert(
82
-
::jacquard_common::smol_str::SmolStr::new_static("path"),
83
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
84
-
description: Some(
85
-
::jacquard_common::CowStr::new_static(
86
-
"Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
87
-
),
88
-
),
89
-
format: None,
90
-
default: None,
91
-
min_length: None,
92
-
max_length: Some(500usize),
93
-
min_graphemes: None,
94
-
max_graphemes: None,
95
-
r#enum: None,
96
-
r#const: None,
97
-
known_values: None,
98
-
}),
99
-
);
100
-
map.insert(
101
-
::jacquard_common::smol_str::SmolStr::new_static("value"),
102
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
103
-
description: Some(
104
-
::jacquard_common::CowStr::new_static("HTTP header value"),
105
-
),
106
-
format: None,
107
-
default: None,
108
-
min_length: None,
109
-
max_length: Some(1000usize),
110
-
min_graphemes: None,
111
-
max_graphemes: None,
112
-
r#enum: None,
113
-
r#const: None,
114
-
known_values: None,
115
-
}),
116
-
);
117
-
map
118
-
},
119
-
}),
120
-
);
121
-
map.insert(
122
-
::jacquard_common::smol_str::SmolStr::new_static("main"),
123
-
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
124
-
description: Some(
125
-
::jacquard_common::CowStr::new_static(
126
-
"Configuration settings for a static site hosted on wisp.place",
127
-
),
128
-
),
129
-
key: Some(::jacquard_common::CowStr::new_static("any")),
130
-
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
131
-
description: None,
132
-
required: None,
133
-
nullable: None,
134
-
properties: {
135
-
#[allow(unused_mut)]
136
-
let mut map = ::std::collections::BTreeMap::new();
137
-
map.insert(
138
-
::jacquard_common::smol_str::SmolStr::new_static(
139
-
"cleanUrls",
140
-
),
141
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
142
-
description: None,
143
-
default: None,
144
-
r#const: None,
145
-
}),
146
-
);
147
-
map.insert(
148
-
::jacquard_common::smol_str::SmolStr::new_static(
149
-
"custom404",
150
-
),
151
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
152
-
description: Some(
153
-
::jacquard_common::CowStr::new_static(
154
-
"Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
155
-
),
156
-
),
157
-
format: None,
158
-
default: None,
159
-
min_length: None,
160
-
max_length: Some(500usize),
161
-
min_graphemes: None,
162
-
max_graphemes: None,
163
-
r#enum: None,
164
-
r#const: None,
165
-
known_values: None,
166
-
}),
167
-
);
168
-
map.insert(
169
-
::jacquard_common::smol_str::SmolStr::new_static(
170
-
"directoryListing",
171
-
),
172
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
173
-
description: None,
174
-
default: None,
175
-
r#const: None,
176
-
}),
177
-
);
178
-
map.insert(
179
-
::jacquard_common::smol_str::SmolStr::new_static("headers"),
180
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
181
-
description: Some(
182
-
::jacquard_common::CowStr::new_static(
183
-
"Custom HTTP headers to set on responses",
184
-
),
185
-
),
186
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
187
-
description: None,
188
-
r#ref: ::jacquard_common::CowStr::new_static(
189
-
"#customHeader",
190
-
),
191
-
}),
192
-
min_length: None,
193
-
max_length: Some(50usize),
194
-
}),
195
-
);
196
-
map.insert(
197
-
::jacquard_common::smol_str::SmolStr::new_static(
198
-
"indexFiles",
199
-
),
200
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
201
-
description: Some(
202
-
::jacquard_common::CowStr::new_static(
203
-
"Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
204
-
),
205
-
),
206
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::String(::jacquard_lexicon::lexicon::LexString {
207
-
description: None,
208
-
format: None,
209
-
default: None,
210
-
min_length: None,
211
-
max_length: Some(255usize),
212
-
min_graphemes: None,
213
-
max_graphemes: None,
214
-
r#enum: None,
215
-
r#const: None,
216
-
known_values: None,
217
-
}),
218
-
min_length: None,
219
-
max_length: Some(10usize),
220
-
}),
221
-
);
222
-
map.insert(
223
-
::jacquard_common::smol_str::SmolStr::new_static("spaMode"),
224
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
225
-
description: Some(
226
-
::jacquard_common::CowStr::new_static(
227
-
"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.",
228
-
),
229
-
),
230
-
format: None,
231
-
default: None,
232
-
min_length: None,
233
-
max_length: Some(500usize),
234
-
min_graphemes: None,
235
-
max_graphemes: None,
236
-
r#enum: None,
237
-
r#const: None,
238
-
known_values: None,
239
-
}),
240
-
);
241
-
map
242
-
},
243
-
}),
244
-
}),
245
-
);
246
-
map
247
-
},
248
-
}
249
-
}
250
-
251
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for CustomHeader<'a> {
252
-
fn nsid() -> &'static str {
253
-
"place.wisp.settings"
254
-
}
255
-
fn def_name() -> &'static str {
256
-
"customHeader"
257
-
}
258
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
259
-
lexicon_doc_place_wisp_settings()
260
-
}
261
-
fn validate(
262
-
&self,
263
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
264
-
{
265
-
let value = &self.name;
266
-
#[allow(unused_comparisons)]
267
-
if <str>::len(value.as_ref()) > 100usize {
268
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
269
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
270
-
"name",
271
-
),
272
-
max: 100usize,
273
-
actual: <str>::len(value.as_ref()),
274
-
});
275
-
}
276
-
}
277
-
if let Some(ref value) = self.path {
278
-
#[allow(unused_comparisons)]
279
-
if <str>::len(value.as_ref()) > 500usize {
280
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
281
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
282
-
"path",
283
-
),
284
-
max: 500usize,
285
-
actual: <str>::len(value.as_ref()),
286
-
});
287
-
}
288
-
}
289
-
{
290
-
let value = &self.value;
291
-
#[allow(unused_comparisons)]
292
-
if <str>::len(value.as_ref()) > 1000usize {
293
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
294
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
295
-
"value",
296
-
),
297
-
max: 1000usize,
298
-
actual: <str>::len(value.as_ref()),
299
-
});
300
-
}
301
-
}
302
-
Ok(())
303
-
}
304
-
}
305
-
306
-
/// Configuration settings for a static site hosted on wisp.place
307
-
#[jacquard_derive::lexicon]
308
-
#[derive(
309
-
serde::Serialize,
310
-
serde::Deserialize,
311
-
Debug,
312
-
Clone,
313
-
PartialEq,
314
-
Eq,
315
-
jacquard_derive::IntoStatic
316
-
)]
317
-
#[serde(rename_all = "camelCase")]
318
-
pub struct Settings<'a> {
319
-
/// Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.
320
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
321
-
pub clean_urls: std::option::Option<bool>,
322
-
/// Custom 404 error page file path. Incompatible with directoryListing and spaMode.
323
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
324
-
#[serde(borrow)]
325
-
pub custom404: std::option::Option<jacquard_common::CowStr<'a>>,
326
-
/// Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.
327
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
328
-
pub directory_listing: std::option::Option<bool>,
329
-
/// Custom HTTP headers to set on responses
330
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
331
-
#[serde(borrow)]
332
-
pub headers: std::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
333
-
/// Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.
334
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
335
-
#[serde(borrow)]
336
-
pub index_files: std::option::Option<Vec<jacquard_common::CowStr<'a>>>,
337
-
/// 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.
338
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
339
-
#[serde(borrow)]
340
-
pub spa_mode: std::option::Option<jacquard_common::CowStr<'a>>,
341
-
}
342
-
343
-
pub mod settings_state {
344
-
345
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
346
-
#[allow(unused)]
347
-
use ::core::marker::PhantomData;
348
-
mod sealed {
349
-
pub trait Sealed {}
350
-
}
351
-
/// State trait tracking which required fields have been set
352
-
pub trait State: sealed::Sealed {}
353
-
/// Empty state - all required fields are unset
354
-
pub struct Empty(());
355
-
impl sealed::Sealed for Empty {}
356
-
impl State for Empty {}
357
-
/// Marker types for field names
358
-
#[allow(non_camel_case_types)]
359
-
pub mod members {}
360
-
}
361
-
362
-
/// Builder for constructing an instance of this type
363
-
pub struct SettingsBuilder<'a, S: settings_state::State> {
364
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
365
-
__unsafe_private_named: (
366
-
::core::option::Option<bool>,
367
-
::core::option::Option<jacquard_common::CowStr<'a>>,
368
-
::core::option::Option<bool>,
369
-
::core::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
370
-
::core::option::Option<Vec<jacquard_common::CowStr<'a>>>,
371
-
::core::option::Option<jacquard_common::CowStr<'a>>,
372
-
),
373
-
_phantom: ::core::marker::PhantomData<&'a ()>,
374
-
}
375
-
376
-
impl<'a> Settings<'a> {
377
-
/// Create a new builder for this type
378
-
pub fn new() -> SettingsBuilder<'a, settings_state::Empty> {
379
-
SettingsBuilder::new()
380
-
}
381
-
}
382
-
383
-
impl<'a> SettingsBuilder<'a, settings_state::Empty> {
384
-
/// Create a new builder with all fields unset
385
-
pub fn new() -> Self {
386
-
SettingsBuilder {
387
-
_phantom_state: ::core::marker::PhantomData,
388
-
__unsafe_private_named: (None, None, None, None, None, None),
389
-
_phantom: ::core::marker::PhantomData,
390
-
}
391
-
}
392
-
}
393
-
394
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
395
-
/// Set the `cleanUrls` field (optional)
396
-
pub fn clean_urls(mut self, value: impl Into<Option<bool>>) -> Self {
397
-
self.__unsafe_private_named.0 = value.into();
398
-
self
399
-
}
400
-
/// Set the `cleanUrls` field to an Option value (optional)
401
-
pub fn maybe_clean_urls(mut self, value: Option<bool>) -> Self {
402
-
self.__unsafe_private_named.0 = value;
403
-
self
404
-
}
405
-
}
406
-
407
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
408
-
/// Set the `custom404` field (optional)
409
-
pub fn custom404(
410
-
mut self,
411
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
412
-
) -> Self {
413
-
self.__unsafe_private_named.1 = value.into();
414
-
self
415
-
}
416
-
/// Set the `custom404` field to an Option value (optional)
417
-
pub fn maybe_custom404(
418
-
mut self,
419
-
value: Option<jacquard_common::CowStr<'a>>,
420
-
) -> Self {
421
-
self.__unsafe_private_named.1 = value;
422
-
self
423
-
}
424
-
}
425
-
426
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
427
-
/// Set the `directoryListing` field (optional)
428
-
pub fn directory_listing(mut self, value: impl Into<Option<bool>>) -> Self {
429
-
self.__unsafe_private_named.2 = value.into();
430
-
self
431
-
}
432
-
/// Set the `directoryListing` field to an Option value (optional)
433
-
pub fn maybe_directory_listing(mut self, value: Option<bool>) -> Self {
434
-
self.__unsafe_private_named.2 = value;
435
-
self
436
-
}
437
-
}
438
-
439
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
440
-
/// Set the `headers` field (optional)
441
-
pub fn headers(
442
-
mut self,
443
-
value: impl Into<Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>>,
444
-
) -> Self {
445
-
self.__unsafe_private_named.3 = value.into();
446
-
self
447
-
}
448
-
/// Set the `headers` field to an Option value (optional)
449
-
pub fn maybe_headers(
450
-
mut self,
451
-
value: Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
452
-
) -> Self {
453
-
self.__unsafe_private_named.3 = value;
454
-
self
455
-
}
456
-
}
457
-
458
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
459
-
/// Set the `indexFiles` field (optional)
460
-
pub fn index_files(
461
-
mut self,
462
-
value: impl Into<Option<Vec<jacquard_common::CowStr<'a>>>>,
463
-
) -> Self {
464
-
self.__unsafe_private_named.4 = value.into();
465
-
self
466
-
}
467
-
/// Set the `indexFiles` field to an Option value (optional)
468
-
pub fn maybe_index_files(
469
-
mut self,
470
-
value: Option<Vec<jacquard_common::CowStr<'a>>>,
471
-
) -> Self {
472
-
self.__unsafe_private_named.4 = value;
473
-
self
474
-
}
475
-
}
476
-
477
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
478
-
/// Set the `spaMode` field (optional)
479
-
pub fn spa_mode(
480
-
mut self,
481
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
482
-
) -> Self {
483
-
self.__unsafe_private_named.5 = value.into();
484
-
self
485
-
}
486
-
/// Set the `spaMode` field to an Option value (optional)
487
-
pub fn maybe_spa_mode(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
488
-
self.__unsafe_private_named.5 = value;
489
-
self
490
-
}
491
-
}
492
-
493
-
impl<'a, S> SettingsBuilder<'a, S>
494
-
where
495
-
S: settings_state::State,
496
-
{
497
-
/// Build the final struct
498
-
pub fn build(self) -> Settings<'a> {
499
-
Settings {
500
-
clean_urls: self.__unsafe_private_named.0,
501
-
custom404: self.__unsafe_private_named.1,
502
-
directory_listing: self.__unsafe_private_named.2,
503
-
headers: self.__unsafe_private_named.3,
504
-
index_files: self.__unsafe_private_named.4,
505
-
spa_mode: self.__unsafe_private_named.5,
506
-
extra_data: Default::default(),
507
-
}
508
-
}
509
-
/// Build the final struct with custom extra_data
510
-
pub fn build_with_data(
511
-
self,
512
-
extra_data: std::collections::BTreeMap<
513
-
jacquard_common::smol_str::SmolStr,
514
-
jacquard_common::types::value::Data<'a>,
515
-
>,
516
-
) -> Settings<'a> {
517
-
Settings {
518
-
clean_urls: self.__unsafe_private_named.0,
519
-
custom404: self.__unsafe_private_named.1,
520
-
directory_listing: self.__unsafe_private_named.2,
521
-
headers: self.__unsafe_private_named.3,
522
-
index_files: self.__unsafe_private_named.4,
523
-
spa_mode: self.__unsafe_private_named.5,
524
-
extra_data: Some(extra_data),
525
-
}
526
-
}
527
-
}
528
-
529
-
impl<'a> Settings<'a> {
530
-
pub fn uri(
531
-
uri: impl Into<jacquard_common::CowStr<'a>>,
532
-
) -> Result<
533
-
jacquard_common::types::uri::RecordUri<'a, SettingsRecord>,
534
-
jacquard_common::types::uri::UriError,
535
-
> {
536
-
jacquard_common::types::uri::RecordUri::try_from_uri(
537
-
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
538
-
)
539
-
}
540
-
}
541
-
542
-
/// Typed wrapper for GetRecord response with this collection's record type.
543
-
#[derive(
544
-
serde::Serialize,
545
-
serde::Deserialize,
546
-
Debug,
547
-
Clone,
548
-
PartialEq,
549
-
Eq,
550
-
jacquard_derive::IntoStatic
551
-
)]
552
-
#[serde(rename_all = "camelCase")]
553
-
pub struct SettingsGetRecordOutput<'a> {
554
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
555
-
#[serde(borrow)]
556
-
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
557
-
#[serde(borrow)]
558
-
pub uri: jacquard_common::types::string::AtUri<'a>,
559
-
#[serde(borrow)]
560
-
pub value: Settings<'a>,
561
-
}
562
-
563
-
impl From<SettingsGetRecordOutput<'_>> for Settings<'_> {
564
-
fn from(output: SettingsGetRecordOutput<'_>) -> Self {
565
-
use jacquard_common::IntoStatic;
566
-
output.value.into_static()
567
-
}
568
-
}
569
-
570
-
impl jacquard_common::types::collection::Collection for Settings<'_> {
571
-
const NSID: &'static str = "place.wisp.settings";
572
-
type Record = SettingsRecord;
573
-
}
574
-
575
-
/// Marker type for deserializing records from this collection.
576
-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
577
-
pub struct SettingsRecord;
578
-
impl jacquard_common::xrpc::XrpcResp for SettingsRecord {
579
-
const NSID: &'static str = "place.wisp.settings";
580
-
const ENCODING: &'static str = "application/json";
581
-
type Output<'de> = SettingsGetRecordOutput<'de>;
582
-
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
583
-
}
584
-
585
-
impl jacquard_common::types::collection::Collection for SettingsRecord {
586
-
const NSID: &'static str = "place.wisp.settings";
587
-
type Record = SettingsRecord;
588
-
}
589
-
590
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Settings<'a> {
591
-
fn nsid() -> &'static str {
592
-
"place.wisp.settings"
593
-
}
594
-
fn def_name() -> &'static str {
595
-
"main"
596
-
}
597
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
598
-
lexicon_doc_place_wisp_settings()
599
-
}
600
-
fn validate(
601
-
&self,
602
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
603
-
if let Some(ref value) = self.custom404 {
604
-
#[allow(unused_comparisons)]
605
-
if <str>::len(value.as_ref()) > 500usize {
606
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
607
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
608
-
"custom404",
609
-
),
610
-
max: 500usize,
611
-
actual: <str>::len(value.as_ref()),
612
-
});
613
-
}
614
-
}
615
-
if let Some(ref value) = self.headers {
616
-
#[allow(unused_comparisons)]
617
-
if value.len() > 50usize {
618
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
619
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
620
-
"headers",
621
-
),
622
-
max: 50usize,
623
-
actual: value.len(),
624
-
});
625
-
}
626
-
}
627
-
if let Some(ref value) = self.index_files {
628
-
#[allow(unused_comparisons)]
629
-
if value.len() > 10usize {
630
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
631
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
632
-
"index_files",
633
-
),
634
-
max: 10usize,
635
-
actual: value.len(),
636
-
});
637
-
}
638
-
}
639
-
if let Some(ref value) = self.spa_mode {
640
-
#[allow(unused_comparisons)]
641
-
if <str>::len(value.as_ref()) > 500usize {
642
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
643
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
644
-
"spa_mode",
645
-
),
646
-
max: 500usize,
647
-
actual: <str>::len(value.as_ref()),
648
-
});
649
-
}
650
-
}
651
-
Ok(())
652
-
}
653
-
}
-1408
cli/src/place_wisp/subfs.rs
-1408
cli/src/place_wisp/subfs.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// Lexicon: place.wisp.subfs
4
-
//
5
-
// This file was automatically generated from Lexicon schemas.
6
-
// Any manual changes will be overwritten on the next regeneration.
7
-
8
-
#[jacquard_derive::lexicon]
9
-
#[derive(
10
-
serde::Serialize,
11
-
serde::Deserialize,
12
-
Debug,
13
-
Clone,
14
-
PartialEq,
15
-
Eq,
16
-
jacquard_derive::IntoStatic
17
-
)]
18
-
#[serde(rename_all = "camelCase")]
19
-
pub struct Directory<'a> {
20
-
#[serde(borrow)]
21
-
pub entries: Vec<crate::place_wisp::subfs::Entry<'a>>,
22
-
#[serde(borrow)]
23
-
pub r#type: jacquard_common::CowStr<'a>,
24
-
}
25
-
26
-
pub mod directory_state {
27
-
28
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
-
#[allow(unused)]
30
-
use ::core::marker::PhantomData;
31
-
mod sealed {
32
-
pub trait Sealed {}
33
-
}
34
-
/// State trait tracking which required fields have been set
35
-
pub trait State: sealed::Sealed {
36
-
type Type;
37
-
type Entries;
38
-
}
39
-
/// Empty state - all required fields are unset
40
-
pub struct Empty(());
41
-
impl sealed::Sealed for Empty {}
42
-
impl State for Empty {
43
-
type Type = Unset;
44
-
type Entries = Unset;
45
-
}
46
-
///State transition - sets the `type` field to Set
47
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
-
impl<S: State> sealed::Sealed for SetType<S> {}
49
-
impl<S: State> State for SetType<S> {
50
-
type Type = Set<members::r#type>;
51
-
type Entries = S::Entries;
52
-
}
53
-
///State transition - sets the `entries` field to Set
54
-
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
-
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
-
impl<S: State> State for SetEntries<S> {
57
-
type Type = S::Type;
58
-
type Entries = Set<members::entries>;
59
-
}
60
-
/// Marker types for field names
61
-
#[allow(non_camel_case_types)]
62
-
pub mod members {
63
-
///Marker type for the `type` field
64
-
pub struct r#type(());
65
-
///Marker type for the `entries` field
66
-
pub struct entries(());
67
-
}
68
-
}
69
-
70
-
/// Builder for constructing an instance of this type
71
-
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
-
__unsafe_private_named: (
74
-
::core::option::Option<Vec<crate::place_wisp::subfs::Entry<'a>>>,
75
-
::core::option::Option<jacquard_common::CowStr<'a>>,
76
-
),
77
-
_phantom: ::core::marker::PhantomData<&'a ()>,
78
-
}
79
-
80
-
impl<'a> Directory<'a> {
81
-
/// Create a new builder for this type
82
-
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
-
DirectoryBuilder::new()
84
-
}
85
-
}
86
-
87
-
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
-
/// Create a new builder with all fields unset
89
-
pub fn new() -> Self {
90
-
DirectoryBuilder {
91
-
_phantom_state: ::core::marker::PhantomData,
92
-
__unsafe_private_named: (None, None),
93
-
_phantom: ::core::marker::PhantomData,
94
-
}
95
-
}
96
-
}
97
-
98
-
impl<'a, S> DirectoryBuilder<'a, S>
99
-
where
100
-
S: directory_state::State,
101
-
S::Entries: directory_state::IsUnset,
102
-
{
103
-
/// Set the `entries` field (required)
104
-
pub fn entries(
105
-
mut self,
106
-
value: impl Into<Vec<crate::place_wisp::subfs::Entry<'a>>>,
107
-
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
-
DirectoryBuilder {
110
-
_phantom_state: ::core::marker::PhantomData,
111
-
__unsafe_private_named: self.__unsafe_private_named,
112
-
_phantom: ::core::marker::PhantomData,
113
-
}
114
-
}
115
-
}
116
-
117
-
impl<'a, S> DirectoryBuilder<'a, S>
118
-
where
119
-
S: directory_state::State,
120
-
S::Type: directory_state::IsUnset,
121
-
{
122
-
/// Set the `type` field (required)
123
-
pub fn r#type(
124
-
mut self,
125
-
value: impl Into<jacquard_common::CowStr<'a>>,
126
-
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
-
DirectoryBuilder {
129
-
_phantom_state: ::core::marker::PhantomData,
130
-
__unsafe_private_named: self.__unsafe_private_named,
131
-
_phantom: ::core::marker::PhantomData,
132
-
}
133
-
}
134
-
}
135
-
136
-
impl<'a, S> DirectoryBuilder<'a, S>
137
-
where
138
-
S: directory_state::State,
139
-
S::Type: directory_state::IsSet,
140
-
S::Entries: directory_state::IsSet,
141
-
{
142
-
/// Build the final struct
143
-
pub fn build(self) -> Directory<'a> {
144
-
Directory {
145
-
entries: self.__unsafe_private_named.0.unwrap(),
146
-
r#type: self.__unsafe_private_named.1.unwrap(),
147
-
extra_data: Default::default(),
148
-
}
149
-
}
150
-
/// Build the final struct with custom extra_data
151
-
pub fn build_with_data(
152
-
self,
153
-
extra_data: std::collections::BTreeMap<
154
-
jacquard_common::smol_str::SmolStr,
155
-
jacquard_common::types::value::Data<'a>,
156
-
>,
157
-
) -> Directory<'a> {
158
-
Directory {
159
-
entries: self.__unsafe_private_named.0.unwrap(),
160
-
r#type: self.__unsafe_private_named.1.unwrap(),
161
-
extra_data: Some(extra_data),
162
-
}
163
-
}
164
-
}
165
-
166
-
fn lexicon_doc_place_wisp_subfs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
-
::jacquard_lexicon::lexicon::LexiconDoc {
168
-
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
-
id: ::jacquard_common::CowStr::new_static("place.wisp.subfs"),
170
-
revision: None,
171
-
description: None,
172
-
defs: {
173
-
let mut map = ::std::collections::BTreeMap::new();
174
-
map.insert(
175
-
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
-
description: None,
178
-
required: Some(
179
-
vec![
180
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
-
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
-
],
183
-
),
184
-
nullable: None,
185
-
properties: {
186
-
#[allow(unused_mut)]
187
-
let mut map = ::std::collections::BTreeMap::new();
188
-
map.insert(
189
-
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
-
description: None,
192
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
-
description: None,
194
-
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
-
}),
196
-
min_length: None,
197
-
max_length: Some(500usize),
198
-
}),
199
-
);
200
-
map.insert(
201
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
-
description: None,
204
-
format: None,
205
-
default: None,
206
-
min_length: None,
207
-
max_length: None,
208
-
min_graphemes: None,
209
-
max_graphemes: None,
210
-
r#enum: None,
211
-
r#const: None,
212
-
known_values: None,
213
-
}),
214
-
);
215
-
map
216
-
},
217
-
}),
218
-
);
219
-
map.insert(
220
-
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
-
description: None,
223
-
required: Some(
224
-
vec![
225
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
-
::jacquard_common::smol_str::SmolStr::new_static("node")
227
-
],
228
-
),
229
-
nullable: None,
230
-
properties: {
231
-
#[allow(unused_mut)]
232
-
let mut map = ::std::collections::BTreeMap::new();
233
-
map.insert(
234
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
-
description: None,
237
-
format: None,
238
-
default: None,
239
-
min_length: None,
240
-
max_length: Some(255usize),
241
-
min_graphemes: None,
242
-
max_graphemes: None,
243
-
r#enum: None,
244
-
r#const: None,
245
-
known_values: None,
246
-
}),
247
-
);
248
-
map.insert(
249
-
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
-
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
-
description: None,
252
-
refs: vec![
253
-
::jacquard_common::CowStr::new_static("#file"),
254
-
::jacquard_common::CowStr::new_static("#directory"),
255
-
::jacquard_common::CowStr::new_static("#subfs")
256
-
],
257
-
closed: None,
258
-
}),
259
-
);
260
-
map
261
-
},
262
-
}),
263
-
);
264
-
map.insert(
265
-
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
-
description: None,
268
-
required: Some(
269
-
vec![
270
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
-
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
-
],
273
-
),
274
-
nullable: None,
275
-
properties: {
276
-
#[allow(unused_mut)]
277
-
let mut map = ::std::collections::BTreeMap::new();
278
-
map.insert(
279
-
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
-
description: None,
282
-
default: None,
283
-
r#const: None,
284
-
}),
285
-
);
286
-
map.insert(
287
-
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
-
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
-
description: None,
290
-
accept: None,
291
-
max_size: None,
292
-
}),
293
-
);
294
-
map.insert(
295
-
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
-
description: Some(
298
-
::jacquard_common::CowStr::new_static(
299
-
"Content encoding (e.g., gzip for compressed files)",
300
-
),
301
-
),
302
-
format: None,
303
-
default: None,
304
-
min_length: None,
305
-
max_length: None,
306
-
min_graphemes: None,
307
-
max_graphemes: None,
308
-
r#enum: None,
309
-
r#const: None,
310
-
known_values: None,
311
-
}),
312
-
);
313
-
map.insert(
314
-
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
-
description: Some(
317
-
::jacquard_common::CowStr::new_static(
318
-
"Original MIME type before compression",
319
-
),
320
-
),
321
-
format: None,
322
-
default: None,
323
-
min_length: None,
324
-
max_length: None,
325
-
min_graphemes: None,
326
-
max_graphemes: None,
327
-
r#enum: None,
328
-
r#const: None,
329
-
known_values: None,
330
-
}),
331
-
);
332
-
map.insert(
333
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
-
description: None,
336
-
format: None,
337
-
default: None,
338
-
min_length: None,
339
-
max_length: None,
340
-
min_graphemes: None,
341
-
max_graphemes: None,
342
-
r#enum: None,
343
-
r#const: None,
344
-
known_values: None,
345
-
}),
346
-
);
347
-
map
348
-
},
349
-
}),
350
-
);
351
-
map.insert(
352
-
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
-
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
-
description: Some(
355
-
::jacquard_common::CowStr::new_static(
356
-
"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.",
357
-
),
358
-
),
359
-
key: None,
360
-
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
-
description: None,
362
-
required: Some(
363
-
vec![
364
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
365
-
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
366
-
],
367
-
),
368
-
nullable: None,
369
-
properties: {
370
-
#[allow(unused_mut)]
371
-
let mut map = ::std::collections::BTreeMap::new();
372
-
map.insert(
373
-
::jacquard_common::smol_str::SmolStr::new_static(
374
-
"createdAt",
375
-
),
376
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
377
-
description: None,
378
-
format: Some(
379
-
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
380
-
),
381
-
default: None,
382
-
min_length: None,
383
-
max_length: None,
384
-
min_graphemes: None,
385
-
max_graphemes: None,
386
-
r#enum: None,
387
-
r#const: None,
388
-
known_values: None,
389
-
}),
390
-
);
391
-
map.insert(
392
-
::jacquard_common::smol_str::SmolStr::new_static(
393
-
"fileCount",
394
-
),
395
-
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
396
-
description: None,
397
-
default: None,
398
-
minimum: Some(0i64),
399
-
maximum: Some(1000i64),
400
-
r#enum: None,
401
-
r#const: None,
402
-
}),
403
-
);
404
-
map.insert(
405
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
406
-
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
407
-
description: None,
408
-
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
409
-
}),
410
-
);
411
-
map
412
-
},
413
-
}),
414
-
}),
415
-
);
416
-
map.insert(
417
-
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
418
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
419
-
description: None,
420
-
required: Some(
421
-
vec![
422
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
423
-
::jacquard_common::smol_str::SmolStr::new_static("subject")
424
-
],
425
-
),
426
-
nullable: None,
427
-
properties: {
428
-
#[allow(unused_mut)]
429
-
let mut map = ::std::collections::BTreeMap::new();
430
-
map.insert(
431
-
::jacquard_common::smol_str::SmolStr::new_static("subject"),
432
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
433
-
description: Some(
434
-
::jacquard_common::CowStr::new_static(
435
-
"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.",
436
-
),
437
-
),
438
-
format: Some(
439
-
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
440
-
),
441
-
default: None,
442
-
min_length: None,
443
-
max_length: None,
444
-
min_graphemes: None,
445
-
max_graphemes: None,
446
-
r#enum: None,
447
-
r#const: None,
448
-
known_values: None,
449
-
}),
450
-
);
451
-
map.insert(
452
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
453
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
454
-
description: None,
455
-
format: None,
456
-
default: None,
457
-
min_length: None,
458
-
max_length: None,
459
-
min_graphemes: None,
460
-
max_graphemes: None,
461
-
r#enum: None,
462
-
r#const: None,
463
-
known_values: None,
464
-
}),
465
-
);
466
-
map
467
-
},
468
-
}),
469
-
);
470
-
map
471
-
},
472
-
}
473
-
}
474
-
475
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
476
-
fn nsid() -> &'static str {
477
-
"place.wisp.subfs"
478
-
}
479
-
fn def_name() -> &'static str {
480
-
"directory"
481
-
}
482
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
483
-
lexicon_doc_place_wisp_subfs()
484
-
}
485
-
fn validate(
486
-
&self,
487
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
488
-
{
489
-
let value = &self.entries;
490
-
#[allow(unused_comparisons)]
491
-
if value.len() > 500usize {
492
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
493
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
494
-
"entries",
495
-
),
496
-
max: 500usize,
497
-
actual: value.len(),
498
-
});
499
-
}
500
-
}
501
-
Ok(())
502
-
}
503
-
}
504
-
505
-
#[jacquard_derive::lexicon]
506
-
#[derive(
507
-
serde::Serialize,
508
-
serde::Deserialize,
509
-
Debug,
510
-
Clone,
511
-
PartialEq,
512
-
Eq,
513
-
jacquard_derive::IntoStatic
514
-
)]
515
-
#[serde(rename_all = "camelCase")]
516
-
pub struct Entry<'a> {
517
-
#[serde(borrow)]
518
-
pub name: jacquard_common::CowStr<'a>,
519
-
#[serde(borrow)]
520
-
pub node: EntryNode<'a>,
521
-
}
522
-
523
-
pub mod entry_state {
524
-
525
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
526
-
#[allow(unused)]
527
-
use ::core::marker::PhantomData;
528
-
mod sealed {
529
-
pub trait Sealed {}
530
-
}
531
-
/// State trait tracking which required fields have been set
532
-
pub trait State: sealed::Sealed {
533
-
type Name;
534
-
type Node;
535
-
}
536
-
/// Empty state - all required fields are unset
537
-
pub struct Empty(());
538
-
impl sealed::Sealed for Empty {}
539
-
impl State for Empty {
540
-
type Name = Unset;
541
-
type Node = Unset;
542
-
}
543
-
///State transition - sets the `name` field to Set
544
-
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
545
-
impl<S: State> sealed::Sealed for SetName<S> {}
546
-
impl<S: State> State for SetName<S> {
547
-
type Name = Set<members::name>;
548
-
type Node = S::Node;
549
-
}
550
-
///State transition - sets the `node` field to Set
551
-
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
552
-
impl<S: State> sealed::Sealed for SetNode<S> {}
553
-
impl<S: State> State for SetNode<S> {
554
-
type Name = S::Name;
555
-
type Node = Set<members::node>;
556
-
}
557
-
/// Marker types for field names
558
-
#[allow(non_camel_case_types)]
559
-
pub mod members {
560
-
///Marker type for the `name` field
561
-
pub struct name(());
562
-
///Marker type for the `node` field
563
-
pub struct node(());
564
-
}
565
-
}
566
-
567
-
/// Builder for constructing an instance of this type
568
-
pub struct EntryBuilder<'a, S: entry_state::State> {
569
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
570
-
__unsafe_private_named: (
571
-
::core::option::Option<jacquard_common::CowStr<'a>>,
572
-
::core::option::Option<EntryNode<'a>>,
573
-
),
574
-
_phantom: ::core::marker::PhantomData<&'a ()>,
575
-
}
576
-
577
-
impl<'a> Entry<'a> {
578
-
/// Create a new builder for this type
579
-
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
580
-
EntryBuilder::new()
581
-
}
582
-
}
583
-
584
-
impl<'a> EntryBuilder<'a, entry_state::Empty> {
585
-
/// Create a new builder with all fields unset
586
-
pub fn new() -> Self {
587
-
EntryBuilder {
588
-
_phantom_state: ::core::marker::PhantomData,
589
-
__unsafe_private_named: (None, None),
590
-
_phantom: ::core::marker::PhantomData,
591
-
}
592
-
}
593
-
}
594
-
595
-
impl<'a, S> EntryBuilder<'a, S>
596
-
where
597
-
S: entry_state::State,
598
-
S::Name: entry_state::IsUnset,
599
-
{
600
-
/// Set the `name` field (required)
601
-
pub fn name(
602
-
mut self,
603
-
value: impl Into<jacquard_common::CowStr<'a>>,
604
-
) -> EntryBuilder<'a, entry_state::SetName<S>> {
605
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
606
-
EntryBuilder {
607
-
_phantom_state: ::core::marker::PhantomData,
608
-
__unsafe_private_named: self.__unsafe_private_named,
609
-
_phantom: ::core::marker::PhantomData,
610
-
}
611
-
}
612
-
}
613
-
614
-
impl<'a, S> EntryBuilder<'a, S>
615
-
where
616
-
S: entry_state::State,
617
-
S::Node: entry_state::IsUnset,
618
-
{
619
-
/// Set the `node` field (required)
620
-
pub fn node(
621
-
mut self,
622
-
value: impl Into<EntryNode<'a>>,
623
-
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
624
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
625
-
EntryBuilder {
626
-
_phantom_state: ::core::marker::PhantomData,
627
-
__unsafe_private_named: self.__unsafe_private_named,
628
-
_phantom: ::core::marker::PhantomData,
629
-
}
630
-
}
631
-
}
632
-
633
-
impl<'a, S> EntryBuilder<'a, S>
634
-
where
635
-
S: entry_state::State,
636
-
S::Name: entry_state::IsSet,
637
-
S::Node: entry_state::IsSet,
638
-
{
639
-
/// Build the final struct
640
-
pub fn build(self) -> Entry<'a> {
641
-
Entry {
642
-
name: self.__unsafe_private_named.0.unwrap(),
643
-
node: self.__unsafe_private_named.1.unwrap(),
644
-
extra_data: Default::default(),
645
-
}
646
-
}
647
-
/// Build the final struct with custom extra_data
648
-
pub fn build_with_data(
649
-
self,
650
-
extra_data: std::collections::BTreeMap<
651
-
jacquard_common::smol_str::SmolStr,
652
-
jacquard_common::types::value::Data<'a>,
653
-
>,
654
-
) -> Entry<'a> {
655
-
Entry {
656
-
name: self.__unsafe_private_named.0.unwrap(),
657
-
node: self.__unsafe_private_named.1.unwrap(),
658
-
extra_data: Some(extra_data),
659
-
}
660
-
}
661
-
}
662
-
663
-
#[jacquard_derive::open_union]
664
-
#[derive(
665
-
serde::Serialize,
666
-
serde::Deserialize,
667
-
Debug,
668
-
Clone,
669
-
PartialEq,
670
-
Eq,
671
-
jacquard_derive::IntoStatic
672
-
)]
673
-
#[serde(tag = "$type")]
674
-
#[serde(bound(deserialize = "'de: 'a"))]
675
-
pub enum EntryNode<'a> {
676
-
#[serde(rename = "place.wisp.subfs#file")]
677
-
File(Box<crate::place_wisp::subfs::File<'a>>),
678
-
#[serde(rename = "place.wisp.subfs#directory")]
679
-
Directory(Box<crate::place_wisp::subfs::Directory<'a>>),
680
-
#[serde(rename = "place.wisp.subfs#subfs")]
681
-
Subfs(Box<crate::place_wisp::subfs::Subfs<'a>>),
682
-
}
683
-
684
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
685
-
fn nsid() -> &'static str {
686
-
"place.wisp.subfs"
687
-
}
688
-
fn def_name() -> &'static str {
689
-
"entry"
690
-
}
691
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
692
-
lexicon_doc_place_wisp_subfs()
693
-
}
694
-
fn validate(
695
-
&self,
696
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
697
-
{
698
-
let value = &self.name;
699
-
#[allow(unused_comparisons)]
700
-
if <str>::len(value.as_ref()) > 255usize {
701
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
702
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
703
-
"name",
704
-
),
705
-
max: 255usize,
706
-
actual: <str>::len(value.as_ref()),
707
-
});
708
-
}
709
-
}
710
-
Ok(())
711
-
}
712
-
}
713
-
714
-
#[jacquard_derive::lexicon]
715
-
#[derive(
716
-
serde::Serialize,
717
-
serde::Deserialize,
718
-
Debug,
719
-
Clone,
720
-
PartialEq,
721
-
Eq,
722
-
jacquard_derive::IntoStatic
723
-
)]
724
-
#[serde(rename_all = "camelCase")]
725
-
pub struct File<'a> {
726
-
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
727
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
728
-
pub base64: Option<bool>,
729
-
/// Content blob ref
730
-
#[serde(borrow)]
731
-
pub blob: jacquard_common::types::blob::BlobRef<'a>,
732
-
/// Content encoding (e.g., gzip for compressed files)
733
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
734
-
#[serde(borrow)]
735
-
pub encoding: Option<jacquard_common::CowStr<'a>>,
736
-
/// Original MIME type before compression
737
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
738
-
#[serde(borrow)]
739
-
pub mime_type: Option<jacquard_common::CowStr<'a>>,
740
-
#[serde(borrow)]
741
-
pub r#type: jacquard_common::CowStr<'a>,
742
-
}
743
-
744
-
pub mod file_state {
745
-
746
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
747
-
#[allow(unused)]
748
-
use ::core::marker::PhantomData;
749
-
mod sealed {
750
-
pub trait Sealed {}
751
-
}
752
-
/// State trait tracking which required fields have been set
753
-
pub trait State: sealed::Sealed {
754
-
type Type;
755
-
type Blob;
756
-
}
757
-
/// Empty state - all required fields are unset
758
-
pub struct Empty(());
759
-
impl sealed::Sealed for Empty {}
760
-
impl State for Empty {
761
-
type Type = Unset;
762
-
type Blob = Unset;
763
-
}
764
-
///State transition - sets the `type` field to Set
765
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
766
-
impl<S: State> sealed::Sealed for SetType<S> {}
767
-
impl<S: State> State for SetType<S> {
768
-
type Type = Set<members::r#type>;
769
-
type Blob = S::Blob;
770
-
}
771
-
///State transition - sets the `blob` field to Set
772
-
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
773
-
impl<S: State> sealed::Sealed for SetBlob<S> {}
774
-
impl<S: State> State for SetBlob<S> {
775
-
type Type = S::Type;
776
-
type Blob = Set<members::blob>;
777
-
}
778
-
/// Marker types for field names
779
-
#[allow(non_camel_case_types)]
780
-
pub mod members {
781
-
///Marker type for the `type` field
782
-
pub struct r#type(());
783
-
///Marker type for the `blob` field
784
-
pub struct blob(());
785
-
}
786
-
}
787
-
788
-
/// Builder for constructing an instance of this type
789
-
pub struct FileBuilder<'a, S: file_state::State> {
790
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
791
-
__unsafe_private_named: (
792
-
::core::option::Option<bool>,
793
-
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
794
-
::core::option::Option<jacquard_common::CowStr<'a>>,
795
-
::core::option::Option<jacquard_common::CowStr<'a>>,
796
-
::core::option::Option<jacquard_common::CowStr<'a>>,
797
-
),
798
-
_phantom: ::core::marker::PhantomData<&'a ()>,
799
-
}
800
-
801
-
impl<'a> File<'a> {
802
-
/// Create a new builder for this type
803
-
pub fn new() -> FileBuilder<'a, file_state::Empty> {
804
-
FileBuilder::new()
805
-
}
806
-
}
807
-
808
-
impl<'a> FileBuilder<'a, file_state::Empty> {
809
-
/// Create a new builder with all fields unset
810
-
pub fn new() -> Self {
811
-
FileBuilder {
812
-
_phantom_state: ::core::marker::PhantomData,
813
-
__unsafe_private_named: (None, None, None, None, None),
814
-
_phantom: ::core::marker::PhantomData,
815
-
}
816
-
}
817
-
}
818
-
819
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
820
-
/// Set the `base64` field (optional)
821
-
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
822
-
self.__unsafe_private_named.0 = value.into();
823
-
self
824
-
}
825
-
/// Set the `base64` field to an Option value (optional)
826
-
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
827
-
self.__unsafe_private_named.0 = value;
828
-
self
829
-
}
830
-
}
831
-
832
-
impl<'a, S> FileBuilder<'a, S>
833
-
where
834
-
S: file_state::State,
835
-
S::Blob: file_state::IsUnset,
836
-
{
837
-
/// Set the `blob` field (required)
838
-
pub fn blob(
839
-
mut self,
840
-
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
841
-
) -> FileBuilder<'a, file_state::SetBlob<S>> {
842
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
843
-
FileBuilder {
844
-
_phantom_state: ::core::marker::PhantomData,
845
-
__unsafe_private_named: self.__unsafe_private_named,
846
-
_phantom: ::core::marker::PhantomData,
847
-
}
848
-
}
849
-
}
850
-
851
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
852
-
/// Set the `encoding` field (optional)
853
-
pub fn encoding(
854
-
mut self,
855
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
856
-
) -> Self {
857
-
self.__unsafe_private_named.2 = value.into();
858
-
self
859
-
}
860
-
/// Set the `encoding` field to an Option value (optional)
861
-
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
862
-
self.__unsafe_private_named.2 = value;
863
-
self
864
-
}
865
-
}
866
-
867
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
868
-
/// Set the `mimeType` field (optional)
869
-
pub fn mime_type(
870
-
mut self,
871
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
872
-
) -> Self {
873
-
self.__unsafe_private_named.3 = value.into();
874
-
self
875
-
}
876
-
/// Set the `mimeType` field to an Option value (optional)
877
-
pub fn maybe_mime_type(
878
-
mut self,
879
-
value: Option<jacquard_common::CowStr<'a>>,
880
-
) -> Self {
881
-
self.__unsafe_private_named.3 = value;
882
-
self
883
-
}
884
-
}
885
-
886
-
impl<'a, S> FileBuilder<'a, S>
887
-
where
888
-
S: file_state::State,
889
-
S::Type: file_state::IsUnset,
890
-
{
891
-
/// Set the `type` field (required)
892
-
pub fn r#type(
893
-
mut self,
894
-
value: impl Into<jacquard_common::CowStr<'a>>,
895
-
) -> FileBuilder<'a, file_state::SetType<S>> {
896
-
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
897
-
FileBuilder {
898
-
_phantom_state: ::core::marker::PhantomData,
899
-
__unsafe_private_named: self.__unsafe_private_named,
900
-
_phantom: ::core::marker::PhantomData,
901
-
}
902
-
}
903
-
}
904
-
905
-
impl<'a, S> FileBuilder<'a, S>
906
-
where
907
-
S: file_state::State,
908
-
S::Type: file_state::IsSet,
909
-
S::Blob: file_state::IsSet,
910
-
{
911
-
/// Build the final struct
912
-
pub fn build(self) -> File<'a> {
913
-
File {
914
-
base64: self.__unsafe_private_named.0,
915
-
blob: self.__unsafe_private_named.1.unwrap(),
916
-
encoding: self.__unsafe_private_named.2,
917
-
mime_type: self.__unsafe_private_named.3,
918
-
r#type: self.__unsafe_private_named.4.unwrap(),
919
-
extra_data: Default::default(),
920
-
}
921
-
}
922
-
/// Build the final struct with custom extra_data
923
-
pub fn build_with_data(
924
-
self,
925
-
extra_data: std::collections::BTreeMap<
926
-
jacquard_common::smol_str::SmolStr,
927
-
jacquard_common::types::value::Data<'a>,
928
-
>,
929
-
) -> File<'a> {
930
-
File {
931
-
base64: self.__unsafe_private_named.0,
932
-
blob: self.__unsafe_private_named.1.unwrap(),
933
-
encoding: self.__unsafe_private_named.2,
934
-
mime_type: self.__unsafe_private_named.3,
935
-
r#type: self.__unsafe_private_named.4.unwrap(),
936
-
extra_data: Some(extra_data),
937
-
}
938
-
}
939
-
}
940
-
941
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
942
-
fn nsid() -> &'static str {
943
-
"place.wisp.subfs"
944
-
}
945
-
fn def_name() -> &'static str {
946
-
"file"
947
-
}
948
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
949
-
lexicon_doc_place_wisp_subfs()
950
-
}
951
-
fn validate(
952
-
&self,
953
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
954
-
Ok(())
955
-
}
956
-
}
957
-
958
-
/// 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.
959
-
#[jacquard_derive::lexicon]
960
-
#[derive(
961
-
serde::Serialize,
962
-
serde::Deserialize,
963
-
Debug,
964
-
Clone,
965
-
PartialEq,
966
-
Eq,
967
-
jacquard_derive::IntoStatic
968
-
)]
969
-
#[serde(rename_all = "camelCase")]
970
-
pub struct SubfsRecord<'a> {
971
-
pub created_at: jacquard_common::types::string::Datetime,
972
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
973
-
pub file_count: Option<i64>,
974
-
#[serde(borrow)]
975
-
pub root: crate::place_wisp::subfs::Directory<'a>,
976
-
}
977
-
978
-
pub mod subfs_record_state {
979
-
980
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
981
-
#[allow(unused)]
982
-
use ::core::marker::PhantomData;
983
-
mod sealed {
984
-
pub trait Sealed {}
985
-
}
986
-
/// State trait tracking which required fields have been set
987
-
pub trait State: sealed::Sealed {
988
-
type Root;
989
-
type CreatedAt;
990
-
}
991
-
/// Empty state - all required fields are unset
992
-
pub struct Empty(());
993
-
impl sealed::Sealed for Empty {}
994
-
impl State for Empty {
995
-
type Root = Unset;
996
-
type CreatedAt = Unset;
997
-
}
998
-
///State transition - sets the `root` field to Set
999
-
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1000
-
impl<S: State> sealed::Sealed for SetRoot<S> {}
1001
-
impl<S: State> State for SetRoot<S> {
1002
-
type Root = Set<members::root>;
1003
-
type CreatedAt = S::CreatedAt;
1004
-
}
1005
-
///State transition - sets the `created_at` field to Set
1006
-
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1007
-
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1008
-
impl<S: State> State for SetCreatedAt<S> {
1009
-
type Root = S::Root;
1010
-
type CreatedAt = Set<members::created_at>;
1011
-
}
1012
-
/// Marker types for field names
1013
-
#[allow(non_camel_case_types)]
1014
-
pub mod members {
1015
-
///Marker type for the `root` field
1016
-
pub struct root(());
1017
-
///Marker type for the `created_at` field
1018
-
pub struct created_at(());
1019
-
}
1020
-
}
1021
-
1022
-
/// Builder for constructing an instance of this type
1023
-
pub struct SubfsRecordBuilder<'a, S: subfs_record_state::State> {
1024
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1025
-
__unsafe_private_named: (
1026
-
::core::option::Option<jacquard_common::types::string::Datetime>,
1027
-
::core::option::Option<i64>,
1028
-
::core::option::Option<crate::place_wisp::subfs::Directory<'a>>,
1029
-
),
1030
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1031
-
}
1032
-
1033
-
impl<'a> SubfsRecord<'a> {
1034
-
/// Create a new builder for this type
1035
-
pub fn new() -> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1036
-
SubfsRecordBuilder::new()
1037
-
}
1038
-
}
1039
-
1040
-
impl<'a> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1041
-
/// Create a new builder with all fields unset
1042
-
pub fn new() -> Self {
1043
-
SubfsRecordBuilder {
1044
-
_phantom_state: ::core::marker::PhantomData,
1045
-
__unsafe_private_named: (None, None, None),
1046
-
_phantom: ::core::marker::PhantomData,
1047
-
}
1048
-
}
1049
-
}
1050
-
1051
-
impl<'a, S> SubfsRecordBuilder<'a, S>
1052
-
where
1053
-
S: subfs_record_state::State,
1054
-
S::CreatedAt: subfs_record_state::IsUnset,
1055
-
{
1056
-
/// Set the `createdAt` field (required)
1057
-
pub fn created_at(
1058
-
mut self,
1059
-
value: impl Into<jacquard_common::types::string::Datetime>,
1060
-
) -> SubfsRecordBuilder<'a, subfs_record_state::SetCreatedAt<S>> {
1061
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1062
-
SubfsRecordBuilder {
1063
-
_phantom_state: ::core::marker::PhantomData,
1064
-
__unsafe_private_named: self.__unsafe_private_named,
1065
-
_phantom: ::core::marker::PhantomData,
1066
-
}
1067
-
}
1068
-
}
1069
-
1070
-
impl<'a, S: subfs_record_state::State> SubfsRecordBuilder<'a, S> {
1071
-
/// Set the `fileCount` field (optional)
1072
-
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1073
-
self.__unsafe_private_named.1 = value.into();
1074
-
self
1075
-
}
1076
-
/// Set the `fileCount` field to an Option value (optional)
1077
-
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1078
-
self.__unsafe_private_named.1 = value;
1079
-
self
1080
-
}
1081
-
}
1082
-
1083
-
impl<'a, S> SubfsRecordBuilder<'a, S>
1084
-
where
1085
-
S: subfs_record_state::State,
1086
-
S::Root: subfs_record_state::IsUnset,
1087
-
{
1088
-
/// Set the `root` field (required)
1089
-
pub fn root(
1090
-
mut self,
1091
-
value: impl Into<crate::place_wisp::subfs::Directory<'a>>,
1092
-
) -> SubfsRecordBuilder<'a, subfs_record_state::SetRoot<S>> {
1093
-
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1094
-
SubfsRecordBuilder {
1095
-
_phantom_state: ::core::marker::PhantomData,
1096
-
__unsafe_private_named: self.__unsafe_private_named,
1097
-
_phantom: ::core::marker::PhantomData,
1098
-
}
1099
-
}
1100
-
}
1101
-
1102
-
impl<'a, S> SubfsRecordBuilder<'a, S>
1103
-
where
1104
-
S: subfs_record_state::State,
1105
-
S::Root: subfs_record_state::IsSet,
1106
-
S::CreatedAt: subfs_record_state::IsSet,
1107
-
{
1108
-
/// Build the final struct
1109
-
pub fn build(self) -> SubfsRecord<'a> {
1110
-
SubfsRecord {
1111
-
created_at: self.__unsafe_private_named.0.unwrap(),
1112
-
file_count: self.__unsafe_private_named.1,
1113
-
root: self.__unsafe_private_named.2.unwrap(),
1114
-
extra_data: Default::default(),
1115
-
}
1116
-
}
1117
-
/// Build the final struct with custom extra_data
1118
-
pub fn build_with_data(
1119
-
self,
1120
-
extra_data: std::collections::BTreeMap<
1121
-
jacquard_common::smol_str::SmolStr,
1122
-
jacquard_common::types::value::Data<'a>,
1123
-
>,
1124
-
) -> SubfsRecord<'a> {
1125
-
SubfsRecord {
1126
-
created_at: self.__unsafe_private_named.0.unwrap(),
1127
-
file_count: self.__unsafe_private_named.1,
1128
-
root: self.__unsafe_private_named.2.unwrap(),
1129
-
extra_data: Some(extra_data),
1130
-
}
1131
-
}
1132
-
}
1133
-
1134
-
impl<'a> SubfsRecord<'a> {
1135
-
pub fn uri(
1136
-
uri: impl Into<jacquard_common::CowStr<'a>>,
1137
-
) -> Result<
1138
-
jacquard_common::types::uri::RecordUri<'a, SubfsRecordRecord>,
1139
-
jacquard_common::types::uri::UriError,
1140
-
> {
1141
-
jacquard_common::types::uri::RecordUri::try_from_uri(
1142
-
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1143
-
)
1144
-
}
1145
-
}
1146
-
1147
-
/// Typed wrapper for GetRecord response with this collection's record type.
1148
-
#[derive(
1149
-
serde::Serialize,
1150
-
serde::Deserialize,
1151
-
Debug,
1152
-
Clone,
1153
-
PartialEq,
1154
-
Eq,
1155
-
jacquard_derive::IntoStatic
1156
-
)]
1157
-
#[serde(rename_all = "camelCase")]
1158
-
pub struct SubfsRecordGetRecordOutput<'a> {
1159
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1160
-
#[serde(borrow)]
1161
-
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1162
-
#[serde(borrow)]
1163
-
pub uri: jacquard_common::types::string::AtUri<'a>,
1164
-
#[serde(borrow)]
1165
-
pub value: SubfsRecord<'a>,
1166
-
}
1167
-
1168
-
impl From<SubfsRecordGetRecordOutput<'_>> for SubfsRecord<'_> {
1169
-
fn from(output: SubfsRecordGetRecordOutput<'_>) -> Self {
1170
-
use jacquard_common::IntoStatic;
1171
-
output.value.into_static()
1172
-
}
1173
-
}
1174
-
1175
-
impl jacquard_common::types::collection::Collection for SubfsRecord<'_> {
1176
-
const NSID: &'static str = "place.wisp.subfs";
1177
-
type Record = SubfsRecordRecord;
1178
-
}
1179
-
1180
-
/// Marker type for deserializing records from this collection.
1181
-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1182
-
pub struct SubfsRecordRecord;
1183
-
impl jacquard_common::xrpc::XrpcResp for SubfsRecordRecord {
1184
-
const NSID: &'static str = "place.wisp.subfs";
1185
-
const ENCODING: &'static str = "application/json";
1186
-
type Output<'de> = SubfsRecordGetRecordOutput<'de>;
1187
-
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1188
-
}
1189
-
1190
-
impl jacquard_common::types::collection::Collection for SubfsRecordRecord {
1191
-
const NSID: &'static str = "place.wisp.subfs";
1192
-
type Record = SubfsRecordRecord;
1193
-
}
1194
-
1195
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for SubfsRecord<'a> {
1196
-
fn nsid() -> &'static str {
1197
-
"place.wisp.subfs"
1198
-
}
1199
-
fn def_name() -> &'static str {
1200
-
"main"
1201
-
}
1202
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1203
-
lexicon_doc_place_wisp_subfs()
1204
-
}
1205
-
fn validate(
1206
-
&self,
1207
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1208
-
if let Some(ref value) = self.file_count {
1209
-
if *value > 1000i64 {
1210
-
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1211
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1212
-
"file_count",
1213
-
),
1214
-
max: 1000i64,
1215
-
actual: *value,
1216
-
});
1217
-
}
1218
-
}
1219
-
if let Some(ref value) = self.file_count {
1220
-
if *value < 0i64 {
1221
-
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1222
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1223
-
"file_count",
1224
-
),
1225
-
min: 0i64,
1226
-
actual: *value,
1227
-
});
1228
-
}
1229
-
}
1230
-
Ok(())
1231
-
}
1232
-
}
1233
-
1234
-
#[jacquard_derive::lexicon]
1235
-
#[derive(
1236
-
serde::Serialize,
1237
-
serde::Deserialize,
1238
-
Debug,
1239
-
Clone,
1240
-
PartialEq,
1241
-
Eq,
1242
-
jacquard_derive::IntoStatic
1243
-
)]
1244
-
#[serde(rename_all = "camelCase")]
1245
-
pub struct Subfs<'a> {
1246
-
/// 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.
1247
-
#[serde(borrow)]
1248
-
pub subject: jacquard_common::types::string::AtUri<'a>,
1249
-
#[serde(borrow)]
1250
-
pub r#type: jacquard_common::CowStr<'a>,
1251
-
}
1252
-
1253
-
pub mod subfs_state {
1254
-
1255
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1256
-
#[allow(unused)]
1257
-
use ::core::marker::PhantomData;
1258
-
mod sealed {
1259
-
pub trait Sealed {}
1260
-
}
1261
-
/// State trait tracking which required fields have been set
1262
-
pub trait State: sealed::Sealed {
1263
-
type Type;
1264
-
type Subject;
1265
-
}
1266
-
/// Empty state - all required fields are unset
1267
-
pub struct Empty(());
1268
-
impl sealed::Sealed for Empty {}
1269
-
impl State for Empty {
1270
-
type Type = Unset;
1271
-
type Subject = Unset;
1272
-
}
1273
-
///State transition - sets the `type` field to Set
1274
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1275
-
impl<S: State> sealed::Sealed for SetType<S> {}
1276
-
impl<S: State> State for SetType<S> {
1277
-
type Type = Set<members::r#type>;
1278
-
type Subject = S::Subject;
1279
-
}
1280
-
///State transition - sets the `subject` field to Set
1281
-
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1282
-
impl<S: State> sealed::Sealed for SetSubject<S> {}
1283
-
impl<S: State> State for SetSubject<S> {
1284
-
type Type = S::Type;
1285
-
type Subject = Set<members::subject>;
1286
-
}
1287
-
/// Marker types for field names
1288
-
#[allow(non_camel_case_types)]
1289
-
pub mod members {
1290
-
///Marker type for the `type` field
1291
-
pub struct r#type(());
1292
-
///Marker type for the `subject` field
1293
-
pub struct subject(());
1294
-
}
1295
-
}
1296
-
1297
-
/// Builder for constructing an instance of this type
1298
-
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1299
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1300
-
__unsafe_private_named: (
1301
-
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1302
-
::core::option::Option<jacquard_common::CowStr<'a>>,
1303
-
),
1304
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1305
-
}
1306
-
1307
-
impl<'a> Subfs<'a> {
1308
-
/// Create a new builder for this type
1309
-
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1310
-
SubfsBuilder::new()
1311
-
}
1312
-
}
1313
-
1314
-
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1315
-
/// Create a new builder with all fields unset
1316
-
pub fn new() -> Self {
1317
-
SubfsBuilder {
1318
-
_phantom_state: ::core::marker::PhantomData,
1319
-
__unsafe_private_named: (None, None),
1320
-
_phantom: ::core::marker::PhantomData,
1321
-
}
1322
-
}
1323
-
}
1324
-
1325
-
impl<'a, S> SubfsBuilder<'a, S>
1326
-
where
1327
-
S: subfs_state::State,
1328
-
S::Subject: subfs_state::IsUnset,
1329
-
{
1330
-
/// Set the `subject` field (required)
1331
-
pub fn subject(
1332
-
mut self,
1333
-
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1334
-
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1335
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1336
-
SubfsBuilder {
1337
-
_phantom_state: ::core::marker::PhantomData,
1338
-
__unsafe_private_named: self.__unsafe_private_named,
1339
-
_phantom: ::core::marker::PhantomData,
1340
-
}
1341
-
}
1342
-
}
1343
-
1344
-
impl<'a, S> SubfsBuilder<'a, S>
1345
-
where
1346
-
S: subfs_state::State,
1347
-
S::Type: subfs_state::IsUnset,
1348
-
{
1349
-
/// Set the `type` field (required)
1350
-
pub fn r#type(
1351
-
mut self,
1352
-
value: impl Into<jacquard_common::CowStr<'a>>,
1353
-
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1354
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1355
-
SubfsBuilder {
1356
-
_phantom_state: ::core::marker::PhantomData,
1357
-
__unsafe_private_named: self.__unsafe_private_named,
1358
-
_phantom: ::core::marker::PhantomData,
1359
-
}
1360
-
}
1361
-
}
1362
-
1363
-
impl<'a, S> SubfsBuilder<'a, S>
1364
-
where
1365
-
S: subfs_state::State,
1366
-
S::Type: subfs_state::IsSet,
1367
-
S::Subject: subfs_state::IsSet,
1368
-
{
1369
-
/// Build the final struct
1370
-
pub fn build(self) -> Subfs<'a> {
1371
-
Subfs {
1372
-
subject: self.__unsafe_private_named.0.unwrap(),
1373
-
r#type: self.__unsafe_private_named.1.unwrap(),
1374
-
extra_data: Default::default(),
1375
-
}
1376
-
}
1377
-
/// Build the final struct with custom extra_data
1378
-
pub fn build_with_data(
1379
-
self,
1380
-
extra_data: std::collections::BTreeMap<
1381
-
jacquard_common::smol_str::SmolStr,
1382
-
jacquard_common::types::value::Data<'a>,
1383
-
>,
1384
-
) -> Subfs<'a> {
1385
-
Subfs {
1386
-
subject: self.__unsafe_private_named.0.unwrap(),
1387
-
r#type: self.__unsafe_private_named.1.unwrap(),
1388
-
extra_data: Some(extra_data),
1389
-
}
1390
-
}
1391
-
}
1392
-
1393
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1394
-
fn nsid() -> &'static str {
1395
-
"place.wisp.subfs"
1396
-
}
1397
-
fn def_name() -> &'static str {
1398
-
"subfs"
1399
-
}
1400
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1401
-
lexicon_doc_place_wisp_subfs()
1402
-
}
1403
-
fn validate(
1404
-
&self,
1405
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1406
-
Ok(())
1407
-
}
1408
-
}
-8
cli/src/place_wisp.rs
-8
cli/src/place_wisp.rs
+12
-12
cli/src/pull.rs
+12
-12
cli/src/pull.rs
···
1
1
use crate::blob_map;
2
2
use crate::download;
3
3
use crate::metadata::SiteMetadata;
4
-
use crate::place_wisp::fs::*;
4
+
use wisp_lexicons::place_wisp::fs::*;
5
5
use crate::subfs_utils;
6
6
use jacquard::CowStr;
7
7
use jacquard::prelude::IdentityResolver;
···
410
410
) -> miette::Result<Directory<'static>> {
411
411
use jacquard_common::IntoStatic;
412
412
use jacquard_common::types::value::from_data;
413
-
use crate::place_wisp::subfs::SubfsRecord;
413
+
use wisp_lexicons::place_wisp::subfs::SubfsRecord;
414
414
415
-
let mut all_subfs_map: HashMap<String, crate::place_wisp::subfs::Directory> = HashMap::new();
415
+
let mut all_subfs_map: HashMap<String, wisp_lexicons::place_wisp::subfs::Directory> = HashMap::new();
416
416
let mut to_fetch = subfs_utils::extract_subfs_uris(directory, String::new());
417
417
418
418
if to_fetch.is_empty() {
···
516
516
517
517
/// Extract subfs URIs from a subfs::Directory (helper for pull)
518
518
fn extract_subfs_uris_from_subfs_dir(
519
-
directory: &crate::place_wisp::subfs::Directory,
519
+
directory: &wisp_lexicons::place_wisp::subfs::Directory,
520
520
current_path: String,
521
521
) -> Vec<(String, String)> {
522
522
let mut uris = Vec::new();
···
529
529
};
530
530
531
531
match &entry.node {
532
-
crate::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
532
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
533
533
uris.push((subfs_node.subject.to_string(), full_path.clone()));
534
534
}
535
-
crate::place_wisp::subfs::EntryNode::Directory(subdir) => {
535
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => {
536
536
let nested = extract_subfs_uris_from_subfs_dir(subdir, full_path);
537
537
uris.extend(nested);
538
538
}
···
546
546
/// Recursively replace subfs nodes with their actual content
547
547
fn replace_subfs_with_content(
548
548
directory: Directory,
549
-
subfs_map: &HashMap<String, crate::place_wisp::subfs::Directory>,
549
+
subfs_map: &HashMap<String, wisp_lexicons::place_wisp::subfs::Directory>,
550
550
current_path: String,
551
551
) -> Directory<'static> {
552
552
use jacquard_common::IntoStatic;
···
628
628
}
629
629
630
630
/// Convert a subfs entry to a fs entry (they have the same structure but different types)
631
-
fn convert_subfs_entry_to_fs(subfs_entry: crate::place_wisp::subfs::Entry<'static>) -> Entry<'static> {
631
+
fn convert_subfs_entry_to_fs(subfs_entry: wisp_lexicons::place_wisp::subfs::Entry<'static>) -> Entry<'static> {
632
632
use jacquard_common::IntoStatic;
633
633
634
634
let node = match subfs_entry.node {
635
-
crate::place_wisp::subfs::EntryNode::File(file) => {
635
+
wisp_lexicons::place_wisp::subfs::EntryNode::File(file) => {
636
636
EntryNode::File(Box::new(
637
637
File::new()
638
638
.r#type(file.r#type.into_static())
···
643
643
.build()
644
644
))
645
645
}
646
-
crate::place_wisp::subfs::EntryNode::Directory(dir) => {
646
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(dir) => {
647
647
let converted_entries: Vec<Entry<'static>> = dir
648
648
.entries
649
649
.into_iter()
···
657
657
.build()
658
658
))
659
659
}
660
-
crate::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
660
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
661
661
// Nested subfs should have been expanded already - if we get here, it means expansion failed
662
662
// Treat it like a directory reference that should have been expanded
663
663
eprintln!(" โ ๏ธ Warning: unexpanded nested subfs at path, treating as empty directory");
···
668
668
.build()
669
669
))
670
670
}
671
-
crate::place_wisp::subfs::EntryNode::Unknown(unknown) => {
671
+
wisp_lexicons::place_wisp::subfs::EntryNode::Unknown(unknown) => {
672
672
EntryNode::Unknown(unknown)
673
673
}
674
674
};
+1
-1
cli/src/serve.rs
+1
-1
cli/src/serve.rs
+14
-14
cli/src/subfs_utils.rs
+14
-14
cli/src/subfs_utils.rs
···
6
6
use miette::IntoDiagnostic;
7
7
use std::collections::HashMap;
8
8
9
-
use crate::place_wisp::fs::{Directory as FsDirectory, EntryNode as FsEntryNode};
10
-
use crate::place_wisp::subfs::SubfsRecord;
9
+
use wisp_lexicons::place_wisp::fs::{Directory as FsDirectory, EntryNode as FsEntryNode};
10
+
use wisp_lexicons::place_wisp::subfs::SubfsRecord;
11
11
12
12
/// Extract all subfs URIs from a directory tree with their mount paths
13
13
pub fn extract_subfs_uris(directory: &FsDirectory, current_path: String) -> Vec<(String, String)> {
···
145
145
146
146
/// Extract subfs URIs from a subfs::Directory
147
147
fn extract_subfs_uris_from_subfs_dir(
148
-
directory: &crate::place_wisp::subfs::Directory,
148
+
directory: &wisp_lexicons::place_wisp::subfs::Directory,
149
149
current_path: String,
150
150
) -> Vec<(String, String)> {
151
151
let mut uris = Vec::new();
152
152
153
153
for entry in &directory.entries {
154
154
match &entry.node {
155
-
crate::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
155
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
156
156
// Check if this is a chunk entry (chunk0, chunk1, etc.)
157
157
// Chunks should be flat-merged, so use the parent's path
158
158
let mount_path = if entry.name.starts_with("chunk") &&
···
171
171
172
172
uris.push((subfs_node.subject.to_string(), mount_path));
173
173
}
174
-
crate::place_wisp::subfs::EntryNode::Directory(subdir) => {
174
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => {
175
175
let full_path = if current_path.is_empty() {
176
176
entry.name.to_string()
177
177
} else {
···
204
204
for (mount_path, subfs_record) in all_subfs {
205
205
// Check if this record only contains chunk subfs references (no files)
206
206
let only_has_chunks = subfs_record.root.entries.iter().all(|e| {
207
-
matches!(&e.node, crate::place_wisp::subfs::EntryNode::Subfs(_)) &&
207
+
matches!(&e.node, wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_)) &&
208
208
e.name.starts_with("chunk") &&
209
209
e.name.chars().skip(5).all(|c| c.is_ascii_digit())
210
210
});
···
232
232
/// Extract blobs from a subfs directory (works with subfs::Directory)
233
233
/// Returns a map of file paths to their blob refs and CIDs
234
234
fn extract_subfs_blobs(
235
-
directory: &crate::place_wisp::subfs::Directory,
235
+
directory: &wisp_lexicons::place_wisp::subfs::Directory,
236
236
current_path: String,
237
237
) -> HashMap<String, (BlobRef<'static>, String)> {
238
238
let mut blob_map = HashMap::new();
···
245
245
};
246
246
247
247
match &entry.node {
248
-
crate::place_wisp::subfs::EntryNode::File(file_node) => {
248
+
wisp_lexicons::place_wisp::subfs::EntryNode::File(file_node) => {
249
249
let blob_ref = &file_node.blob;
250
250
let cid_string = blob_ref.blob().r#ref.to_string();
251
251
blob_map.insert(
···
253
253
(blob_ref.clone().into_static(), cid_string)
254
254
);
255
255
}
256
-
crate::place_wisp::subfs::EntryNode::Directory(subdir) => {
256
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => {
257
257
let sub_map = extract_subfs_blobs(subdir, full_path);
258
258
blob_map.extend(sub_map);
259
259
}
260
-
crate::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
260
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
261
261
// Nested subfs - these should be resolved recursively in the main flow
262
262
// For now, we skip them (they'll be fetched separately)
263
263
eprintln!(" โ ๏ธ Found nested subfs at {}, skipping (should be fetched separately)", full_path);
264
264
}
265
-
crate::place_wisp::subfs::EntryNode::Unknown(_) => {
265
+
wisp_lexicons::place_wisp::subfs::EntryNode::Unknown(_) => {
266
266
// Skip unknown nodes
267
267
}
268
268
}
···
352
352
flat: bool,
353
353
) -> miette::Result<FsDirectory<'static>> {
354
354
use jacquard_common::CowStr;
355
-
use crate::place_wisp::fs::{Entry, Subfs};
355
+
use wisp_lexicons::place_wisp::fs::{Entry, Subfs};
356
356
357
357
let path_parts: Vec<&str> = target_path.split('/').collect();
358
358
···
430
430
431
431
// Construct AT-URI and convert to RecordUri
432
432
let at_uri = AtUri::new(uri).into_diagnostic()?;
433
-
let record_uri: RecordUri<'_, crate::place_wisp::subfs::SubfsRecordRecord> = RecordUri::try_from_uri(at_uri).into_diagnostic()?;
433
+
let record_uri: RecordUri<'_, wisp_lexicons::place_wisp::subfs::SubfsRecordRecord> = RecordUri::try_from_uri(at_uri).into_diagnostic()?;
434
434
435
435
let rkey = record_uri.rkey()
436
436
.ok_or_else(|| miette::miette!("Invalid subfs URI: missing rkey"))?
···
489
489
}
490
490
491
491
/// Estimate the JSON size of a single entry
492
-
fn estimate_entry_size(entry: &crate::place_wisp::fs::Entry) -> usize {
492
+
fn estimate_entry_size(entry: &wisp_lexicons::place_wisp::fs::Entry) -> usize {
493
493
match serde_json::to_string(entry) {
494
494
Ok(json) => json.len(),
495
495
Err(_) => 500, // Conservative estimate if serialization fails
+21
docker-compose.yml
+21
docker-compose.yml
···
1
+
services:
2
+
postgres:
3
+
image: postgres:16-alpine
4
+
container_name: wisp-postgres
5
+
restart: unless-stopped
6
+
environment:
7
+
POSTGRES_USER: postgres
8
+
POSTGRES_PASSWORD: postgres
9
+
POSTGRES_DB: wisp
10
+
ports:
11
+
- "5432:5432"
12
+
volumes:
13
+
- postgres_data:/var/lib/postgresql/data
14
+
healthcheck:
15
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
16
+
interval: 5s
17
+
timeout: 5s
18
+
retries: 5
19
+
20
+
volumes:
21
+
postgres_data:
+3
-1
docs/astro.config.mjs
+3
-1
docs/astro.config.mjs
···
7
7
integrations: [
8
8
starlight({
9
9
title: 'Wisp.place Docs',
10
-
social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/tangled-org/wisp.place' }],
10
+
components: {
11
+
SocialIcons: './src/components/SocialIcons.astro',
12
+
},
11
13
sidebar: [
12
14
{
13
15
label: 'Getting Started',
+9
docs/src/assets/tangled-icon.svg
+9
docs/src/assets/tangled-icon.svg
···
1
+
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1" id="svg1" width="25" height="25" viewBox="0 0 25 25" sodipodi:docname="tangled_dolly_silhouette.png">
2
+
<defs id="defs1"/>
3
+
<sodipodi:namedview id="namedview1" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="true" inkscape:deskcolor="#d1d1d1">
4
+
<inkscape:page x="0" y="0" width="25" height="25" id="page2" margin="0" bleed="0"/>
5
+
</sodipodi:namedview>
6
+
<g inkscape:groupmode="layer" inkscape:label="Image" id="g1">
7
+
<path style="fill:#000000;stroke-width:1.12248" d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z" id="path1"/>
8
+
</g>
9
+
</svg>
+26
docs/src/components/SocialIcons.astro
+26
docs/src/components/SocialIcons.astro
···
1
+
---
2
+
// Custom social icons component to use the Tangled icon
3
+
---
4
+
5
+
<div class="sl-flex">
6
+
<a
7
+
href="https://tangled.org/nekomimi.pet/wisp.place-monorepo"
8
+
rel="me"
9
+
class="sl-flex"
10
+
aria-label="Tangled"
11
+
>
12
+
<svg
13
+
xmlns="http://www.w3.org/2000/svg"
14
+
viewBox="0 0 25 25"
15
+
width="16"
16
+
height="16"
17
+
aria-hidden="true"
18
+
focusable="false"
19
+
>
20
+
<path
21
+
style="fill:currentColor;stroke-width:1.12248"
22
+
d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z"
23
+
></path>
24
+
</svg>
25
+
</a>
26
+
</div>
+6
-11
docs/src/content/docs/cli.md
+6
-11
docs/src/content/docs/cli.md
···
71
71
72
72
engine: 'nixery'
73
73
74
-
clone:
75
-
skip: false
76
-
depth: 1
77
-
submodules: false
78
-
79
74
dependencies:
80
75
nixpkgs:
81
76
- nodejs
···
141
136
# Pull a site to a specific directory
142
137
wisp-cli pull your-handle.bsky.social \
143
138
--site my-site \
144
-
--output ./my-site
139
+
--path ./my-site
145
140
146
141
# Pull to current directory
147
142
wisp-cli pull your-handle.bsky.social \
···
238
233
### Pull Command
239
234
240
235
```bash
241
-
wisp-cli pull [OPTIONS] <INPUT>
236
+
wisp-cli pull [OPTIONS] --site <SITE> <INPUT>
242
237
243
238
Arguments:
244
239
<INPUT> Handle or DID
245
240
246
241
Options:
247
242
-s, --site <SITE> Site name to download
248
-
-o, --output <OUTPUT> Output directory [default: .]
243
+
-p, --path <PATH> Output directory [default: .]
249
244
-h, --help Print help
250
245
```
251
246
252
247
### Serve Command
253
248
254
249
```bash
255
-
wisp-cli serve [OPTIONS] <INPUT>
250
+
wisp-cli serve [OPTIONS] --site <SITE> <INPUT>
256
251
257
252
Arguments:
258
253
<INPUT> Handle or DID
259
254
260
255
Options:
261
256
-s, --site <SITE> Site name to serve
262
-
-o, --output <OUTPUT> Site files directory [default: .]
263
-
-p, --port <PORT> Port to serve on [default: 8080]
257
+
-p, --path <PATH> Site files directory [default: .]
258
+
-P, --port <PORT> Port to serve on [default: 8080]
264
259
--spa Enable SPA mode (serve index.html for all routes)
265
260
--directory Enable directory listing mode for paths without index files
266
261
-h, --help Print help
-318
flake.lock
-318
flake.lock
···
1
-
{
2
-
"nodes": {
3
-
"crane": {
4
-
"flake": false,
5
-
"locked": {
6
-
"lastModified": 1758758545,
7
-
"narHash": "sha256-NU5WaEdfwF6i8faJ2Yh+jcK9vVFrofLcwlD/mP65JrI=",
8
-
"owner": "ipetkov",
9
-
"repo": "crane",
10
-
"rev": "95d528a5f54eaba0d12102249ce42f4d01f4e364",
11
-
"type": "github"
12
-
},
13
-
"original": {
14
-
"owner": "ipetkov",
15
-
"ref": "v0.21.1",
16
-
"repo": "crane",
17
-
"type": "github"
18
-
}
19
-
},
20
-
"dream2nix": {
21
-
"inputs": {
22
-
"nixpkgs": [
23
-
"nci",
24
-
"nixpkgs"
25
-
],
26
-
"purescript-overlay": "purescript-overlay",
27
-
"pyproject-nix": "pyproject-nix"
28
-
},
29
-
"locked": {
30
-
"lastModified": 1754978539,
31
-
"narHash": "sha256-nrDovydywSKRbWim9Ynmgj8SBm8LK3DI2WuhIqzOHYI=",
32
-
"owner": "nix-community",
33
-
"repo": "dream2nix",
34
-
"rev": "fbec3263cb4895ac86ee9506cdc4e6919a1a2214",
35
-
"type": "github"
36
-
},
37
-
"original": {
38
-
"owner": "nix-community",
39
-
"repo": "dream2nix",
40
-
"type": "github"
41
-
}
42
-
},
43
-
"fenix": {
44
-
"inputs": {
45
-
"nixpkgs": [
46
-
"nixpkgs"
47
-
],
48
-
"rust-analyzer-src": "rust-analyzer-src"
49
-
},
50
-
"locked": {
51
-
"lastModified": 1762584108,
52
-
"narHash": "sha256-wZUW7dlXMXaRdvNbaADqhF8gg9bAfFiMV+iyFQiDv+Y=",
53
-
"owner": "nix-community",
54
-
"repo": "fenix",
55
-
"rev": "32f3ad3b6c690061173e1ac16708874975ec6056",
56
-
"type": "github"
57
-
},
58
-
"original": {
59
-
"owner": "nix-community",
60
-
"repo": "fenix",
61
-
"type": "github"
62
-
}
63
-
},
64
-
"flake-compat": {
65
-
"flake": false,
66
-
"locked": {
67
-
"lastModified": 1696426674,
68
-
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
69
-
"owner": "edolstra",
70
-
"repo": "flake-compat",
71
-
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
72
-
"type": "github"
73
-
},
74
-
"original": {
75
-
"owner": "edolstra",
76
-
"repo": "flake-compat",
77
-
"type": "github"
78
-
}
79
-
},
80
-
"mk-naked-shell": {
81
-
"flake": false,
82
-
"locked": {
83
-
"lastModified": 1681286841,
84
-
"narHash": "sha256-3XlJrwlR0nBiREnuogoa5i1b4+w/XPe0z8bbrJASw0g=",
85
-
"owner": "90-008",
86
-
"repo": "mk-naked-shell",
87
-
"rev": "7612f828dd6f22b7fb332cc69440e839d7ffe6bd",
88
-
"type": "github"
89
-
},
90
-
"original": {
91
-
"owner": "90-008",
92
-
"repo": "mk-naked-shell",
93
-
"type": "github"
94
-
}
95
-
},
96
-
"nci": {
97
-
"inputs": {
98
-
"crane": "crane",
99
-
"dream2nix": "dream2nix",
100
-
"mk-naked-shell": "mk-naked-shell",
101
-
"nixpkgs": [
102
-
"nixpkgs"
103
-
],
104
-
"parts": "parts",
105
-
"rust-overlay": "rust-overlay",
106
-
"treefmt": "treefmt"
107
-
},
108
-
"locked": {
109
-
"lastModified": 1762582646,
110
-
"narHash": "sha256-MMzE4xccG+8qbLhdaZoeFDUKWUOn3B4lhp5dZmgukmM=",
111
-
"owner": "90-008",
112
-
"repo": "nix-cargo-integration",
113
-
"rev": "0993c449377049fa8868a664e8290ac6658e0b9a",
114
-
"type": "github"
115
-
},
116
-
"original": {
117
-
"owner": "90-008",
118
-
"repo": "nix-cargo-integration",
119
-
"type": "github"
120
-
}
121
-
},
122
-
"nixpkgs": {
123
-
"locked": {
124
-
"lastModified": 1762361079,
125
-
"narHash": "sha256-lz718rr1BDpZBYk7+G8cE6wee3PiBUpn8aomG/vLLiY=",
126
-
"owner": "nixos",
127
-
"repo": "nixpkgs",
128
-
"rev": "ffcdcf99d65c61956d882df249a9be53e5902ea5",
129
-
"type": "github"
130
-
},
131
-
"original": {
132
-
"owner": "nixos",
133
-
"ref": "nixpkgs-unstable",
134
-
"repo": "nixpkgs",
135
-
"type": "github"
136
-
}
137
-
},
138
-
"parts": {
139
-
"inputs": {
140
-
"nixpkgs-lib": [
141
-
"nci",
142
-
"nixpkgs"
143
-
]
144
-
},
145
-
"locked": {
146
-
"lastModified": 1762440070,
147
-
"narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=",
148
-
"owner": "hercules-ci",
149
-
"repo": "flake-parts",
150
-
"rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8",
151
-
"type": "github"
152
-
},
153
-
"original": {
154
-
"owner": "hercules-ci",
155
-
"repo": "flake-parts",
156
-
"type": "github"
157
-
}
158
-
},
159
-
"parts_2": {
160
-
"inputs": {
161
-
"nixpkgs-lib": [
162
-
"nixpkgs"
163
-
]
164
-
},
165
-
"locked": {
166
-
"lastModified": 1762440070,
167
-
"narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=",
168
-
"owner": "hercules-ci",
169
-
"repo": "flake-parts",
170
-
"rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8",
171
-
"type": "github"
172
-
},
173
-
"original": {
174
-
"owner": "hercules-ci",
175
-
"repo": "flake-parts",
176
-
"type": "github"
177
-
}
178
-
},
179
-
"purescript-overlay": {
180
-
"inputs": {
181
-
"flake-compat": "flake-compat",
182
-
"nixpkgs": [
183
-
"nci",
184
-
"dream2nix",
185
-
"nixpkgs"
186
-
],
187
-
"slimlock": "slimlock"
188
-
},
189
-
"locked": {
190
-
"lastModified": 1728546539,
191
-
"narHash": "sha256-Sws7w0tlnjD+Bjck1nv29NjC5DbL6nH5auL9Ex9Iz2A=",
192
-
"owner": "thomashoneyman",
193
-
"repo": "purescript-overlay",
194
-
"rev": "4ad4c15d07bd899d7346b331f377606631eb0ee4",
195
-
"type": "github"
196
-
},
197
-
"original": {
198
-
"owner": "thomashoneyman",
199
-
"repo": "purescript-overlay",
200
-
"type": "github"
201
-
}
202
-
},
203
-
"pyproject-nix": {
204
-
"inputs": {
205
-
"nixpkgs": [
206
-
"nci",
207
-
"dream2nix",
208
-
"nixpkgs"
209
-
]
210
-
},
211
-
"locked": {
212
-
"lastModified": 1752481895,
213
-
"narHash": "sha256-luVj97hIMpCbwhx3hWiRwjP2YvljWy8FM+4W9njDhLA=",
214
-
"owner": "pyproject-nix",
215
-
"repo": "pyproject.nix",
216
-
"rev": "16ee295c25107a94e59a7fc7f2e5322851781162",
217
-
"type": "github"
218
-
},
219
-
"original": {
220
-
"owner": "pyproject-nix",
221
-
"repo": "pyproject.nix",
222
-
"type": "github"
223
-
}
224
-
},
225
-
"root": {
226
-
"inputs": {
227
-
"fenix": "fenix",
228
-
"nci": "nci",
229
-
"nixpkgs": "nixpkgs",
230
-
"parts": "parts_2"
231
-
}
232
-
},
233
-
"rust-analyzer-src": {
234
-
"flake": false,
235
-
"locked": {
236
-
"lastModified": 1762438844,
237
-
"narHash": "sha256-ApIKJf6CcMsV2nYBXhGF95BmZMO/QXPhgfSnkA/rVUo=",
238
-
"owner": "rust-lang",
239
-
"repo": "rust-analyzer",
240
-
"rev": "4bf516ee5a960c1e2eee9fedd9b1c9e976a19c86",
241
-
"type": "github"
242
-
},
243
-
"original": {
244
-
"owner": "rust-lang",
245
-
"ref": "nightly",
246
-
"repo": "rust-analyzer",
247
-
"type": "github"
248
-
}
249
-
},
250
-
"rust-overlay": {
251
-
"inputs": {
252
-
"nixpkgs": [
253
-
"nci",
254
-
"nixpkgs"
255
-
]
256
-
},
257
-
"locked": {
258
-
"lastModified": 1762569282,
259
-
"narHash": "sha256-vINZAJpXQTZd5cfh06Rcw7hesH7sGSvi+Tn+HUieJn8=",
260
-
"owner": "oxalica",
261
-
"repo": "rust-overlay",
262
-
"rev": "a35a6144b976f70827c2fe2f5c89d16d8f9179d8",
263
-
"type": "github"
264
-
},
265
-
"original": {
266
-
"owner": "oxalica",
267
-
"repo": "rust-overlay",
268
-
"type": "github"
269
-
}
270
-
},
271
-
"slimlock": {
272
-
"inputs": {
273
-
"nixpkgs": [
274
-
"nci",
275
-
"dream2nix",
276
-
"purescript-overlay",
277
-
"nixpkgs"
278
-
]
279
-
},
280
-
"locked": {
281
-
"lastModified": 1688756706,
282
-
"narHash": "sha256-xzkkMv3neJJJ89zo3o2ojp7nFeaZc2G0fYwNXNJRFlo=",
283
-
"owner": "thomashoneyman",
284
-
"repo": "slimlock",
285
-
"rev": "cf72723f59e2340d24881fd7bf61cb113b4c407c",
286
-
"type": "github"
287
-
},
288
-
"original": {
289
-
"owner": "thomashoneyman",
290
-
"repo": "slimlock",
291
-
"type": "github"
292
-
}
293
-
},
294
-
"treefmt": {
295
-
"inputs": {
296
-
"nixpkgs": [
297
-
"nci",
298
-
"nixpkgs"
299
-
]
300
-
},
301
-
"locked": {
302
-
"lastModified": 1762410071,
303
-
"narHash": "sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g+mjR/p5TEg=",
304
-
"owner": "numtide",
305
-
"repo": "treefmt-nix",
306
-
"rev": "97a30861b13c3731a84e09405414398fbf3e109f",
307
-
"type": "github"
308
-
},
309
-
"original": {
310
-
"owner": "numtide",
311
-
"repo": "treefmt-nix",
312
-
"type": "github"
313
-
}
314
-
}
315
-
},
316
-
"root": "root",
317
-
"version": 7
318
-
}
-59
flake.nix
-59
flake.nix
···
1
-
{
2
-
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
3
-
inputs.nci.url = "github:90-008/nix-cargo-integration";
4
-
inputs.nci.inputs.nixpkgs.follows = "nixpkgs";
5
-
inputs.parts.url = "github:hercules-ci/flake-parts";
6
-
inputs.parts.inputs.nixpkgs-lib.follows = "nixpkgs";
7
-
inputs.fenix = {
8
-
url = "github:nix-community/fenix";
9
-
inputs.nixpkgs.follows = "nixpkgs";
10
-
};
11
-
12
-
outputs = inputs @ {
13
-
parts,
14
-
nci,
15
-
...
16
-
}:
17
-
parts.lib.mkFlake {inherit inputs;} {
18
-
systems = ["x86_64-linux" "aarch64-darwin"];
19
-
imports = [
20
-
nci.flakeModule
21
-
./crates.nix
22
-
];
23
-
perSystem = {
24
-
pkgs,
25
-
config,
26
-
...
27
-
}: let
28
-
crateOutputs = config.nci.outputs."wisp-cli";
29
-
mkRenamedPackage = name: pkg: isWindows: pkgs.runCommand name {} ''
30
-
mkdir -p $out/bin
31
-
if [ -f ${pkg}/bin/wisp-cli.exe ]; then
32
-
cp ${pkg}/bin/wisp-cli.exe $out/bin/${name}
33
-
elif [ -f ${pkg}/bin/wisp-cli ]; then
34
-
cp ${pkg}/bin/wisp-cli $out/bin/${name}
35
-
else
36
-
echo "Error: Could not find wisp-cli binary in ${pkg}/bin/"
37
-
ls -la ${pkg}/bin/ || true
38
-
exit 1
39
-
fi
40
-
'';
41
-
in {
42
-
devShells.default = crateOutputs.devShell;
43
-
packages.default = crateOutputs.packages.release;
44
-
packages.wisp-cli-x86_64-linux = mkRenamedPackage "wisp-cli-x86_64-linux" crateOutputs.packages.release false;
45
-
packages.wisp-cli-aarch64-linux = mkRenamedPackage "wisp-cli-aarch64-linux" crateOutputs.allTargets."aarch64-unknown-linux-gnu".packages.release false;
46
-
packages.wisp-cli-x86_64-windows = mkRenamedPackage "wisp-cli-x86_64-windows.exe" crateOutputs.allTargets."x86_64-pc-windows-gnu".packages.release true;
47
-
packages.wisp-cli-aarch64-darwin = mkRenamedPackage "wisp-cli-aarch64-darwin" crateOutputs.allTargets."aarch64-apple-darwin".packages.release false;
48
-
packages.all = pkgs.symlinkJoin {
49
-
name = "wisp-cli-all";
50
-
paths = [
51
-
config.packages.wisp-cli-x86_64-linux
52
-
config.packages.wisp-cli-aarch64-linux
53
-
config.packages.wisp-cli-x86_64-windows
54
-
config.packages.wisp-cli-aarch64-darwin
55
-
];
56
-
};
57
-
};
58
-
};
59
-
}
+59
lexicons/fs.json
+59
lexicons/fs.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "place.wisp.fs",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "Virtual filesystem manifest for a Wisp site",
8
+
"record": {
9
+
"type": "object",
10
+
"required": ["site", "root", "createdAt"],
11
+
"properties": {
12
+
"site": { "type": "string" },
13
+
"root": { "type": "ref", "ref": "#directory" },
14
+
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
15
+
"createdAt": { "type": "string", "format": "datetime" }
16
+
}
17
+
}
18
+
},
19
+
"file": {
20
+
"type": "object",
21
+
"required": ["type", "blob"],
22
+
"properties": {
23
+
"type": { "type": "string", "const": "file" },
24
+
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
25
+
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
26
+
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
27
+
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" } }
28
+
},
29
+
"directory": {
30
+
"type": "object",
31
+
"required": ["type", "entries"],
32
+
"properties": {
33
+
"type": { "type": "string", "const": "directory" },
34
+
"entries": {
35
+
"type": "array",
36
+
"maxLength": 500,
37
+
"items": { "type": "ref", "ref": "#entry" }
38
+
}
39
+
}
40
+
},
41
+
"entry": {
42
+
"type": "object",
43
+
"required": ["name", "node"],
44
+
"properties": {
45
+
"name": { "type": "string", "maxLength": 255 },
46
+
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
+
}
48
+
},
49
+
"subfs": {
50
+
"type": "object",
51
+
"required": ["type", "subject"],
52
+
"properties": {
53
+
"type": { "type": "string", "const": "subfs" },
54
+
"subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to a place.wisp.subfs record containing this subtree." },
55
+
"flat": { "type": "boolean", "description": "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." }
56
+
}
57
+
}
58
+
}
59
+
}
+76
lexicons/settings.json
+76
lexicons/settings.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "place.wisp.settings",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "Configuration settings for a static site hosted on wisp.place",
8
+
"key": "any",
9
+
"record": {
10
+
"type": "object",
11
+
"properties": {
12
+
"directoryListing": {
13
+
"type": "boolean",
14
+
"description": "Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.",
15
+
"default": false
16
+
},
17
+
"spaMode": {
18
+
"type": "string",
19
+
"description": "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.",
20
+
"maxLength": 500
21
+
},
22
+
"custom404": {
23
+
"type": "string",
24
+
"description": "Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
25
+
"maxLength": 500
26
+
},
27
+
"indexFiles": {
28
+
"type": "array",
29
+
"description": "Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
30
+
"items": {
31
+
"type": "string",
32
+
"maxLength": 255
33
+
},
34
+
"maxLength": 10
35
+
},
36
+
"cleanUrls": {
37
+
"type": "boolean",
38
+
"description": "Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.",
39
+
"default": false
40
+
},
41
+
"headers": {
42
+
"type": "array",
43
+
"description": "Custom HTTP headers to set on responses",
44
+
"items": {
45
+
"type": "ref",
46
+
"ref": "#customHeader"
47
+
},
48
+
"maxLength": 50
49
+
}
50
+
}
51
+
}
52
+
},
53
+
"customHeader": {
54
+
"type": "object",
55
+
"description": "Custom HTTP header configuration",
56
+
"required": ["name", "value"],
57
+
"properties": {
58
+
"name": {
59
+
"type": "string",
60
+
"description": "HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
61
+
"maxLength": 100
62
+
},
63
+
"value": {
64
+
"type": "string",
65
+
"description": "HTTP header value",
66
+
"maxLength": 1000
67
+
},
68
+
"path": {
69
+
"type": "string",
70
+
"description": "Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
71
+
"maxLength": 500
72
+
}
73
+
}
74
+
}
75
+
}
76
+
}
+59
lexicons/subfs.json
+59
lexicons/subfs.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "place.wisp.subfs",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "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.",
8
+
"record": {
9
+
"type": "object",
10
+
"required": ["root", "createdAt"],
11
+
"properties": {
12
+
"root": { "type": "ref", "ref": "#directory" },
13
+
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
14
+
"createdAt": { "type": "string", "format": "datetime" }
15
+
}
16
+
}
17
+
},
18
+
"file": {
19
+
"type": "object",
20
+
"required": ["type", "blob"],
21
+
"properties": {
22
+
"type": { "type": "string", "const": "file" },
23
+
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
24
+
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
25
+
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
26
+
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" }
27
+
}
28
+
},
29
+
"directory": {
30
+
"type": "object",
31
+
"required": ["type", "entries"],
32
+
"properties": {
33
+
"type": { "type": "string", "const": "directory" },
34
+
"entries": {
35
+
"type": "array",
36
+
"maxLength": 500,
37
+
"items": { "type": "ref", "ref": "#entry" }
38
+
}
39
+
}
40
+
},
41
+
"entry": {
42
+
"type": "object",
43
+
"required": ["name", "node"],
44
+
"properties": {
45
+
"name": { "type": "string", "maxLength": 255 },
46
+
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
+
}
48
+
},
49
+
"subfs": {
50
+
"type": "object",
51
+
"required": ["type", "subject"],
52
+
"properties": {
53
+
"type": { "type": "string", "const": "subfs" },
54
+
"subject": { "type": "string", "format": "at-uri", "description": "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." }
55
+
}
56
+
}
57
+
}
58
+
}
59
+
+2
-1
package.json
+2
-1
package.json
···
24
24
"check": "cd apps/main-app && npm run check && cd ../hosting-service && npm run check",
25
25
"screenshot": "bun run apps/main-app/scripts/screenshot-sites.ts",
26
26
"hosting:dev": "cd apps/hosting-service && npm run dev",
27
-
"hosting:start": "cd apps/hosting-service && npm run start"
27
+
"hosting:start": "cd apps/hosting-service && npm run start",
28
+
"codegen": "./scripts/codegen.sh"
28
29
},
29
30
"trustedDependencies": [
30
31
"@parcel/watcher",
-59
packages/@wisp/lexicons/lexicons/fs.json
-59
packages/@wisp/lexicons/lexicons/fs.json
···
1
-
{
2
-
"lexicon": 1,
3
-
"id": "place.wisp.fs",
4
-
"defs": {
5
-
"main": {
6
-
"type": "record",
7
-
"description": "Virtual filesystem manifest for a Wisp site",
8
-
"record": {
9
-
"type": "object",
10
-
"required": ["site", "root", "createdAt"],
11
-
"properties": {
12
-
"site": { "type": "string" },
13
-
"root": { "type": "ref", "ref": "#directory" },
14
-
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
15
-
"createdAt": { "type": "string", "format": "datetime" }
16
-
}
17
-
}
18
-
},
19
-
"file": {
20
-
"type": "object",
21
-
"required": ["type", "blob"],
22
-
"properties": {
23
-
"type": { "type": "string", "const": "file" },
24
-
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
25
-
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
26
-
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
27
-
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" } }
28
-
},
29
-
"directory": {
30
-
"type": "object",
31
-
"required": ["type", "entries"],
32
-
"properties": {
33
-
"type": { "type": "string", "const": "directory" },
34
-
"entries": {
35
-
"type": "array",
36
-
"maxLength": 500,
37
-
"items": { "type": "ref", "ref": "#entry" }
38
-
}
39
-
}
40
-
},
41
-
"entry": {
42
-
"type": "object",
43
-
"required": ["name", "node"],
44
-
"properties": {
45
-
"name": { "type": "string", "maxLength": 255 },
46
-
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
-
}
48
-
},
49
-
"subfs": {
50
-
"type": "object",
51
-
"required": ["type", "subject"],
52
-
"properties": {
53
-
"type": { "type": "string", "const": "subfs" },
54
-
"subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to a place.wisp.subfs record containing this subtree." },
55
-
"flat": { "type": "boolean", "description": "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." }
56
-
}
57
-
}
58
-
}
59
-
}
-76
packages/@wisp/lexicons/lexicons/settings.json
-76
packages/@wisp/lexicons/lexicons/settings.json
···
1
-
{
2
-
"lexicon": 1,
3
-
"id": "place.wisp.settings",
4
-
"defs": {
5
-
"main": {
6
-
"type": "record",
7
-
"description": "Configuration settings for a static site hosted on wisp.place",
8
-
"key": "any",
9
-
"record": {
10
-
"type": "object",
11
-
"properties": {
12
-
"directoryListing": {
13
-
"type": "boolean",
14
-
"description": "Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.",
15
-
"default": false
16
-
},
17
-
"spaMode": {
18
-
"type": "string",
19
-
"description": "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.",
20
-
"maxLength": 500
21
-
},
22
-
"custom404": {
23
-
"type": "string",
24
-
"description": "Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
25
-
"maxLength": 500
26
-
},
27
-
"indexFiles": {
28
-
"type": "array",
29
-
"description": "Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
30
-
"items": {
31
-
"type": "string",
32
-
"maxLength": 255
33
-
},
34
-
"maxLength": 10
35
-
},
36
-
"cleanUrls": {
37
-
"type": "boolean",
38
-
"description": "Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.",
39
-
"default": false
40
-
},
41
-
"headers": {
42
-
"type": "array",
43
-
"description": "Custom HTTP headers to set on responses",
44
-
"items": {
45
-
"type": "ref",
46
-
"ref": "#customHeader"
47
-
},
48
-
"maxLength": 50
49
-
}
50
-
}
51
-
}
52
-
},
53
-
"customHeader": {
54
-
"type": "object",
55
-
"description": "Custom HTTP header configuration",
56
-
"required": ["name", "value"],
57
-
"properties": {
58
-
"name": {
59
-
"type": "string",
60
-
"description": "HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
61
-
"maxLength": 100
62
-
},
63
-
"value": {
64
-
"type": "string",
65
-
"description": "HTTP header value",
66
-
"maxLength": 1000
67
-
},
68
-
"path": {
69
-
"type": "string",
70
-
"description": "Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
71
-
"maxLength": 500
72
-
}
73
-
}
74
-
}
75
-
}
76
-
}
-59
packages/@wisp/lexicons/lexicons/subfs.json
-59
packages/@wisp/lexicons/lexicons/subfs.json
···
1
-
{
2
-
"lexicon": 1,
3
-
"id": "place.wisp.subfs",
4
-
"defs": {
5
-
"main": {
6
-
"type": "record",
7
-
"description": "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.",
8
-
"record": {
9
-
"type": "object",
10
-
"required": ["root", "createdAt"],
11
-
"properties": {
12
-
"root": { "type": "ref", "ref": "#directory" },
13
-
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
14
-
"createdAt": { "type": "string", "format": "datetime" }
15
-
}
16
-
}
17
-
},
18
-
"file": {
19
-
"type": "object",
20
-
"required": ["type", "blob"],
21
-
"properties": {
22
-
"type": { "type": "string", "const": "file" },
23
-
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
24
-
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
25
-
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
26
-
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" }
27
-
}
28
-
},
29
-
"directory": {
30
-
"type": "object",
31
-
"required": ["type", "entries"],
32
-
"properties": {
33
-
"type": { "type": "string", "const": "directory" },
34
-
"entries": {
35
-
"type": "array",
36
-
"maxLength": 500,
37
-
"items": { "type": "ref", "ref": "#entry" }
38
-
}
39
-
}
40
-
},
41
-
"entry": {
42
-
"type": "object",
43
-
"required": ["name", "node"],
44
-
"properties": {
45
-
"name": { "type": "string", "maxLength": 255 },
46
-
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
-
}
48
-
},
49
-
"subfs": {
50
-
"type": "object",
51
-
"required": ["type", "subject"],
52
-
"properties": {
53
-
"type": { "type": "string", "const": "subfs" },
54
-
"subject": { "type": "string", "format": "at-uri", "description": "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." }
55
-
}
56
-
}
57
-
}
58
-
}
59
-
+1
-1
packages/@wisp/lexicons/package.json
+1
-1
packages/@wisp/lexicons/package.json
+1
-1
packages/@wisp/lexicons/src/index.ts
+1
-1
packages/@wisp/lexicons/src/index.ts
···
9
9
type MethodConfigOrHandler,
10
10
createServer as createXrpcServer,
11
11
} from '@atproto/xrpc-server'
12
-
import { schemas } from './lexicons'
12
+
import { schemas } from './lexicons.js'
13
13
14
14
export function createServer(options?: XrpcOptions): Server {
15
15
return new Server(options)
+1
-1
packages/@wisp/lexicons/src/lexicons.ts
+1
-1
packages/@wisp/lexicons/src/lexicons.ts
+1
-1
packages/@wisp/observability/README.md
+1
-1
packages/@wisp/observability/README.md
+2
-2
packages/@wisp/observability/src/exporters.ts
+2
-2
packages/@wisp/observability/src/exporters.ts
···
3
3
* Integrates with Grafana Loki for logs and Prometheus/OTLP for metrics
4
4
*/
5
5
6
-
import { LogEntry, ErrorEntry, MetricEntry } from './core'
7
-
import { metrics, MeterProvider } from '@opentelemetry/api'
6
+
import type { LogEntry, ErrorEntry, MetricEntry } from './core'
7
+
import { metrics, type MeterProvider } from '@opentelemetry/api'
8
8
import { MeterProvider as SdkMeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
9
9
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
10
10
import { Resource } from '@opentelemetry/resources'
+28
scripts/codegen.sh
+28
scripts/codegen.sh
···
1
+
#!/bin/bash
2
+
set -e
3
+
4
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
6
+
7
+
# Parse arguments
8
+
AUTO_ACCEPT=""
9
+
if [[ "$1" == "-y" || "$1" == "--yes" ]]; then
10
+
AUTO_ACCEPT="yes |"
11
+
fi
12
+
13
+
echo "=== Generating TypeScript lexicons ==="
14
+
cd "$ROOT_DIR/packages/@wisp/lexicons"
15
+
eval "$AUTO_ACCEPT npm run codegen"
16
+
17
+
echo "=== Generating Rust lexicons ==="
18
+
echo "Installing jacquard-lexgen..."
19
+
cargo install jacquard-lexgen --version 0.9.5 2>/dev/null || true
20
+
echo "Running jacquard-codegen..."
21
+
echo " Input: $ROOT_DIR/lexicons"
22
+
echo " Output: $ROOT_DIR/cli/crates/lexicons/src"
23
+
jacquard-codegen -i "$ROOT_DIR/lexicons" -o "$ROOT_DIR/cli/crates/lexicons/src"
24
+
25
+
# Add extern crate alloc for the macro to work
26
+
sed -i '' '1s/^/extern crate alloc;\n\n/' "$ROOT_DIR/cli/crates/lexicons/src/lib.rs"
27
+
28
+
echo "=== Done ==="