Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place

Compare changes

Choose any two refs to compare.

+1
.gitignore
··· 1 # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 .env 3 # dependencies
··· 1 + .research/ 2 # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 3 .env 4 # dependencies
+2
.tangled/workflows/deploy-wisp.yml
··· 49 - name: Build docs 50 command: | 51 cd docs 52 bun run build 53 - name: Deploy to Wisp.place 54 command: |
··· 49 - name: Build docs 50 command: | 51 cd docs 52 + export PATH="$HOME/.nix-profile/bin:$PATH" 53 + bun install 54 bun run build 55 - name: Deploy to Wisp.place 56 command: |
+2 -1
.tangled/workflows/test.yml
··· 7 dependencies: 8 nixpkgs: 9 - git 10 github:NixOS/nixpkgs/nixpkgs-unstable: 11 - bun 12 ··· 16 export PATH="$HOME/.nix-profile/bin:$PATH" 17 18 # have to regenerate otherwise it wont install necessary dependencies to run 19 - rm -rf bun.lock package-lock.json 20 bun install 21 22 - name: run all tests
··· 7 dependencies: 8 nixpkgs: 9 - git 10 + - findutils 11 github:NixOS/nixpkgs/nixpkgs-unstable: 12 - bun 13 ··· 17 export PATH="$HOME/.nix-profile/bin:$PATH" 18 19 # have to regenerate otherwise it wont install necessary dependencies to run 20 + find . -type f \( -name "bun.lock" -o -name "package-lock.json" \) -delete 21 bun install 22 23 - name: run all tests
+9 -8
apps/hosting-service/package.json
··· 10 "backfill": "tsx src/index.ts --backfill" 11 }, 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 "@atproto/api": "^0.17.4", 21 "@atproto/identity": "^0.4.9", 22 "@atproto/lexicon": "^0.5.2", 23 "@atproto/sync": "^0.1.36", 24 "@atproto/xrpc": "^0.7.5", 25 "@hono/node-server": "^1.19.6", 26 "hono": "^4.10.4", 27 "mime-types": "^2.1.35", 28 "multiformats": "^13.4.1", 29 - "postgres": "^3.4.5" 30 }, 31 "devDependencies": { 32 "@types/bun": "^1.3.1",
··· 10 "backfill": "tsx src/index.ts --backfill" 11 }, 12 "dependencies": { 13 "@atproto/api": "^0.17.4", 14 "@atproto/identity": "^0.4.9", 15 "@atproto/lexicon": "^0.5.2", 16 "@atproto/sync": "^0.1.36", 17 "@atproto/xrpc": "^0.7.5", 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 "hono": "^4.10.4", 27 "mime-types": "^2.1.35", 28 "multiformats": "^13.4.1", 29 + "postgres": "^3.4.5", 30 + "tiered-storage": "1.0.3" 31 }, 32 "devDependencies": { 33 "@types/bun": "^1.3.1",
+31 -3
apps/hosting-service/src/index.ts
··· 5 import { mkdirSync, existsSync } from 'fs'; 6 import { backfillCache } from './lib/backfill'; 7 import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode, closeDatabase } from './lib/db'; 8 9 // Initialize Grafana exporters if configured 10 initializeGrafanaExporters({ ··· 50 51 firehose.start(); 52 53 // Run backfill if requested 54 if (backfillOnStartup) { 55 console.log('๐Ÿ”„ Backfill requested, starting cache backfill...'); ··· 78 port: PORT, 79 }); 80 81 console.log(` 82 - Wisp Hosting Service 83 84 Server: http://localhost:${PORT} 85 Health: http://localhost:${PORT}/health 86 - Cache: ${CACHE_DIR} 87 - Firehose: Connected to Firehose 88 Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'} 89 Backfill: ${backfillOnStartup ? `ENABLED (concurrency: ${BACKFILL_CONCURRENCY || 10})` : 'DISABLED'} 90 `); 91 92 // Graceful shutdown
··· 5 import { mkdirSync, existsSync } from 'fs'; 6 import { backfillCache } from './lib/backfill'; 7 import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode, closeDatabase } from './lib/db'; 8 + import { storage, getStorageConfig } from './lib/storage'; 9 10 // Initialize Grafana exporters if configured 11 initializeGrafanaExporters({ ··· 51 52 firehose.start(); 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 + 69 // Run backfill if requested 70 if (backfillOnStartup) { 71 console.log('๐Ÿ”„ Backfill requested, starting cache backfill...'); ··· 94 port: PORT, 95 }); 96 97 + // Get storage configuration for display 98 + const storageConfig = getStorageConfig(); 99 + 100 console.log(` 101 + Wisp Hosting Service with Tiered Storage 102 103 Server: http://localhost:${PORT} 104 Health: http://localhost:${PORT}/health 105 Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'} 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... 118 `); 119 120 // Graceful shutdown
+1 -1
apps/hosting-service/src/lib/backfill.ts
··· 69 const processSite = async () => { 70 try { 71 // Check if already cached 72 - if (skipExisting && isCached(site.did, site.rkey)) { 73 stats.skipped++; 74 processed++; 75 logger.debug(`Skipping already cached site`, { did: site.did, rkey: site.rkey });
··· 69 const processSite = async () => { 70 try { 71 // Check if already cached 72 + if (skipExisting && await isCached(site.did, site.rkey)) { 73 stats.skipped++; 74 processed++; 75 logger.debug(`Skipping already cached site`, { did: site.did, rkey: site.rkey });
+35 -43
apps/hosting-service/src/lib/cache.ts
··· 1 - // In-memory LRU cache for file contents and metadata 2 3 interface CacheEntry<T> { 4 value: T; 5 size: number; ··· 96 return true; 97 } 98 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 size(): number { 116 return this.cache.size; 117 } ··· 127 return { ...this.stats }; 128 } 129 130 - // Get cache hit rate 131 getHitRate(): number { 132 const total = this.stats.hits + this.stats.misses; 133 return total === 0 ? 0 : (this.stats.hits / total) * 100; 134 } 135 } 136 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 150 export const rewrittenHtmlCache = new LRUCache<Buffer>(50 * 1024 * 1024, 200); // 50MB for rewritten HTML 151 152 - // Helper to generate cache keys 153 export function getCacheKey(did: string, rkey: string, filePath: string, suffix?: string): string { 154 const base = `${did}:${rkey}:${filePath}`; 155 return suffix ? `${base}:${suffix}` : base; 156 } 157 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); 163 164 - console.log(`[Cache] Invalidated site ${did}:${rkey} - ${fileCount} files, ${metaCount} metadata, ${htmlCount} HTML`); 165 } 166 167 // Track sites currently being cached (to prevent serving stale cache during updates) ··· 183 } 184 185 // Get overall cache statistics 186 - export function getCacheStats() { 187 return { 188 - files: fileCache.getStats(), 189 - fileHitRate: fileCache.getHitRate(), 190 - metadata: metadataCache.getStats(), 191 - metadataHitRate: metadataCache.getHitRate(), 192 rewrittenHtml: rewrittenHtmlCache.getStats(), 193 rewrittenHtmlHitRate: rewrittenHtmlCache.getHitRate(), 194 sitesBeingCached: sitesBeingCached.size,
··· 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 + */ 7 8 + import { storage } from './storage'; 9 + 10 + // In-memory LRU cache for rewritten HTML (for path rewriting in subdomain routes) 11 interface CacheEntry<T> { 12 value: T; 13 size: number; ··· 104 return true; 105 } 106 107 size(): number { 108 return this.cache.size; 109 } ··· 119 return { ...this.stats }; 120 } 121 122 getHitRate(): number { 123 const total = this.stats.hits + this.stats.misses; 124 return total === 0 ? 0 : (this.stats.hits / total) * 100; 125 } 126 } 127 128 + // Rewritten HTML cache: stores HTML after path rewriting for subdomain routes 129 export const rewrittenHtmlCache = new LRUCache<Buffer>(50 * 1024 * 1024, 200); // 50MB for rewritten HTML 130 131 + // Helper to generate cache keys for rewritten HTML 132 export function getCacheKey(did: string, rkey: string, filePath: string, suffix?: string): string { 133 const base = `${did}:${rkey}:${filePath}`; 134 return suffix ? `${base}:${suffix}` : base; 135 } 136 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); 145 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`); 158 } 159 160 // Track sites currently being cached (to prevent serving stale cache during updates) ··· 176 } 177 178 // Get overall cache statistics 179 + export async function getCacheStats() { 180 + const tieredStats = await storage.getStats(); 181 + 182 return { 183 + tieredStorage: tieredStats, 184 rewrittenHtml: rewrittenHtmlCache.getStats(), 185 rewrittenHtmlHitRate: rewrittenHtmlCache.getHitRate(), 186 sitesBeingCached: sitesBeingCached.size,
+64 -76
apps/hosting-service/src/lib/file-serving.ts
··· 7 import { lookup } from 'mime-types'; 8 import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings'; 9 import { shouldCompressMimeType } from '@wisp/atproto-utils/compression'; 10 - import { fileCache, metadataCache, rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache'; 11 import { getCachedFilePath, getCachedSettings } from './utils'; 12 import { loadRedirectRules, matchRedirectRule, parseCookies, parseQueryString } from './redirects'; 13 import { rewriteHtmlPaths, isHtmlContent } from './html-rewriter'; 14 import { generate404Page, generateDirectoryListing, siteUpdatingResponse } from './page-generators'; 15 import { getIndexFiles, applyCustomHeaders, fileExists } from './request-utils'; 16 import { getRedirectRulesFromCache, setRedirectRulesInCache } from './site-cache'; 17 18 /** 19 * Helper to serve files from cache (for custom domains and subdomains) ··· 176 177 // Not a directory, try to serve as a file 178 const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html'; 179 - const cacheKey = getCacheKey(did, rkey, fileRequestPath); 180 - const cachedFile = getCachedFilePath(did, rkey, fileRequestPath); 181 182 - // Check in-memory cache first 183 - let content = fileCache.get(cacheKey); 184 - let meta = metadataCache.get(cacheKey); 185 186 - if (!content && await fileExists(cachedFile)) { 187 - // Read from disk and cache 188 - content = await readFile(cachedFile); 189 - fileCache.set(cacheKey, content, content.length); 190 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 // Build headers with caching 201 - const headers: Record<string, string> = {}; 202 203 - if (meta && meta.encoding === 'gzip' && meta.mimeType) { 204 const shouldServeCompressed = shouldCompressMimeType(meta.mimeType); 205 206 if (!shouldServeCompressed) { ··· 233 } 234 235 // Non-compressed files 236 - const mimeType = lookup(cachedFile) || 'application/octet-stream'; 237 headers['Content-Type'] = mimeType; 238 headers['Cache-Control'] = mimeType.startsWith('text/html') 239 ? 'public, max-age=300' ··· 246 if (!fileRequestPath.includes('.')) { 247 for (const indexFileName of indexFiles) { 248 const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName; 249 - const indexCacheKey = getCacheKey(did, rkey, indexPath); 250 - const indexFile = getCachedFilePath(did, rkey, indexPath); 251 252 - let indexContent = fileCache.get(indexCacheKey); 253 - let indexMeta = metadataCache.get(indexCacheKey); 254 255 - if (!indexContent && await fileExists(indexFile)) { 256 - indexContent = await readFile(indexFile); 257 - fileCache.set(indexCacheKey, indexContent, indexContent.length); 258 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 const headers: Record<string, string> = { 269 'Content-Type': 'text/html; charset=utf-8', 270 'Cache-Control': 'public, max-age=300', 271 }; 272 273 - if (indexMeta && indexMeta.encoding === 'gzip') { 274 headers['Content-Encoding'] = 'gzip'; 275 } 276 ··· 556 557 // Not a directory, try to serve as a file 558 const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html'; 559 - const cacheKey = getCacheKey(did, rkey, fileRequestPath); 560 - const cachedFile = getCachedFilePath(did, rkey, fileRequestPath); 561 562 // Check for rewritten HTML in cache first (if it's HTML) 563 const mimeTypeGuess = lookup(fileRequestPath) || 'application/octet-stream'; ··· 565 const rewrittenKey = getCacheKey(did, rkey, fileRequestPath, `rewritten:${basePath}`); 566 const rewrittenContent = rewrittenHtmlCache.get(rewrittenKey); 567 if (rewrittenContent) { 568 const headers: Record<string, string> = { 569 'Content-Type': 'text/html; charset=utf-8', 570 'Content-Encoding': 'gzip', 571 'Cache-Control': 'public, max-age=300', 572 }; 573 applyCustomHeaders(headers, fileRequestPath, settings); 574 return new Response(rewrittenContent, { headers }); 575 } 576 } 577 578 - // Check in-memory file cache 579 - let content = fileCache.get(cacheKey); 580 - let meta = metadataCache.get(cacheKey); 581 582 - if (!content && await fileExists(cachedFile)) { 583 - // Read from disk and cache 584 - content = await readFile(cachedFile); 585 - fileCache.set(cacheKey, content, content.length); 586 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'; 598 599 // Check if this is HTML content that needs rewriting 600 if (isHtmlContent(fileRequestPath, mimeType)) { 601 let htmlContent: string; 602 if (isGzipped) { 603 // Verify content is actually gzipped ··· 612 } else { 613 htmlContent = content.toString('utf-8'); 614 } 615 const rewritten = rewriteHtmlPaths(htmlContent, basePath, fileRequestPath); 616 617 // Recompress and cache the rewritten HTML 618 const { gzipSync } = await import('zlib'); 619 const recompressed = gzipSync(Buffer.from(rewritten, 'utf-8')); ··· 625 'Content-Type': 'text/html; charset=utf-8', 626 'Content-Encoding': 'gzip', 627 'Cache-Control': 'public, max-age=300', 628 }; 629 applyCustomHeaders(htmlHeaders, fileRequestPath, settings); 630 return new Response(recompressed, { headers: htmlHeaders }); ··· 634 const headers: Record<string, string> = { 635 'Content-Type': mimeType, 636 'Cache-Control': 'public, max-age=31536000, immutable', 637 }; 638 639 if (isGzipped) { ··· 663 if (!fileRequestPath.includes('.')) { 664 for (const indexFileName of indexFiles) { 665 const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName; 666 - const indexCacheKey = getCacheKey(did, rkey, indexPath); 667 - const indexFile = getCachedFilePath(did, rkey, indexPath); 668 669 // Check for rewritten index file in cache 670 const rewrittenKey = getCacheKey(did, rkey, indexPath, `rewritten:${basePath}`); ··· 674 'Content-Type': 'text/html; charset=utf-8', 675 'Content-Encoding': 'gzip', 676 'Cache-Control': 'public, max-age=300', 677 }; 678 applyCustomHeaders(headers, indexPath, settings); 679 return new Response(rewrittenContent, { headers }); 680 } 681 682 - let indexContent = fileCache.get(indexCacheKey); 683 - let indexMeta = metadataCache.get(indexCacheKey); 684 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) { 698 const isGzipped = indexMeta?.encoding === 'gzip'; 699 700 let htmlContent: string; ··· 722 'Content-Type': 'text/html; charset=utf-8', 723 'Content-Encoding': 'gzip', 724 'Cache-Control': 'public, max-age=300', 725 }; 726 applyCustomHeaders(headers, indexPath, settings); 727 return new Response(recompressed, { headers });
··· 7 import { lookup } from 'mime-types'; 8 import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings'; 9 import { shouldCompressMimeType } from '@wisp/atproto-utils/compression'; 10 + import { rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache'; 11 import { getCachedFilePath, getCachedSettings } from './utils'; 12 import { loadRedirectRules, matchRedirectRule, parseCookies, parseQueryString } from './redirects'; 13 import { rewriteHtmlPaths, isHtmlContent } from './html-rewriter'; 14 import { generate404Page, generateDirectoryListing, siteUpdatingResponse } from './page-generators'; 15 import { getIndexFiles, applyCustomHeaders, fileExists } from './request-utils'; 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 + } 26 27 /** 28 * Helper to serve files from cache (for custom domains and subdomains) ··· 185 186 // Not a directory, try to serve as a file 187 const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html'; 188 189 + // Retrieve from tiered storage 190 + const result = await getFileWithMetadata(did, rkey, fileRequestPath); 191 192 + if (result) { 193 + const content = Buffer.from(result.data); 194 + const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 195 196 // Build headers with caching 197 + const headers: Record<string, string> = { 198 + 'X-Cache-Tier': result.source, 199 + }; 200 201 + if (meta?.encoding === 'gzip' && meta.mimeType) { 202 const shouldServeCompressed = shouldCompressMimeType(meta.mimeType); 203 204 if (!shouldServeCompressed) { ··· 231 } 232 233 // Non-compressed files 234 + const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream'; 235 headers['Content-Type'] = mimeType; 236 headers['Cache-Control'] = mimeType.startsWith('text/html') 237 ? 'public, max-age=300' ··· 244 if (!fileRequestPath.includes('.')) { 245 for (const indexFileName of indexFiles) { 246 const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName; 247 248 + const indexResult = await getFileWithMetadata(did, rkey, indexPath); 249 250 + if (indexResult) { 251 + const indexContent = Buffer.from(indexResult.data); 252 + const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 253 254 const headers: Record<string, string> = { 255 'Content-Type': 'text/html; charset=utf-8', 256 'Cache-Control': 'public, max-age=300', 257 + 'X-Cache-Tier': indexResult.source, 258 }; 259 260 + if (indexMeta?.encoding === 'gzip') { 261 headers['Content-Encoding'] = 'gzip'; 262 } 263 ··· 543 544 // Not a directory, try to serve as a file 545 const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html'; 546 547 // Check for rewritten HTML in cache first (if it's HTML) 548 const mimeTypeGuess = lookup(fileRequestPath) || 'application/octet-stream'; ··· 550 const rewrittenKey = getCacheKey(did, rkey, fileRequestPath, `rewritten:${basePath}`); 551 const rewrittenContent = rewrittenHtmlCache.get(rewrittenKey); 552 if (rewrittenContent) { 553 + console.log(`[HTML Rewrite] Serving from rewritten cache: ${rewrittenKey}`); 554 const headers: Record<string, string> = { 555 'Content-Type': 'text/html; charset=utf-8', 556 'Content-Encoding': 'gzip', 557 'Cache-Control': 'public, max-age=300', 558 + 'X-Cache-Tier': 'local', // Rewritten HTML is stored locally 559 }; 560 applyCustomHeaders(headers, fileRequestPath, settings); 561 return new Response(rewrittenContent, { headers }); 562 } 563 } 564 565 + // Retrieve from tiered storage 566 + const result = await getFileWithMetadata(did, rkey, fileRequestPath); 567 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'; 573 574 + console.log(`[File Serve] Serving ${fileRequestPath}, mimeType: ${mimeType}, isHTML: ${isHtmlContent(fileRequestPath, mimeType)}, basePath: ${basePath}`); 575 576 // Check if this is HTML content that needs rewriting 577 if (isHtmlContent(fileRequestPath, mimeType)) { 578 + console.log(`[HTML Rewrite] Processing ${fileRequestPath}, basePath: ${basePath}, mimeType: ${mimeType}, isGzipped: ${isGzipped}`); 579 let htmlContent: string; 580 if (isGzipped) { 581 // Verify content is actually gzipped ··· 590 } else { 591 htmlContent = content.toString('utf-8'); 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 + 606 const rewritten = rewriteHtmlPaths(htmlContent, basePath, fileRequestPath); 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 + 614 // Recompress and cache the rewritten HTML 615 const { gzipSync } = await import('zlib'); 616 const recompressed = gzipSync(Buffer.from(rewritten, 'utf-8')); ··· 622 'Content-Type': 'text/html; charset=utf-8', 623 'Content-Encoding': 'gzip', 624 'Cache-Control': 'public, max-age=300', 625 + 'X-Cache-Tier': result.source, 626 }; 627 applyCustomHeaders(htmlHeaders, fileRequestPath, settings); 628 return new Response(recompressed, { headers: htmlHeaders }); ··· 632 const headers: Record<string, string> = { 633 'Content-Type': mimeType, 634 'Cache-Control': 'public, max-age=31536000, immutable', 635 + 'X-Cache-Tier': result.source, 636 }; 637 638 if (isGzipped) { ··· 662 if (!fileRequestPath.includes('.')) { 663 for (const indexFileName of indexFiles) { 664 const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName; 665 666 // Check for rewritten index file in cache 667 const rewrittenKey = getCacheKey(did, rkey, indexPath, `rewritten:${basePath}`); ··· 671 'Content-Type': 'text/html; charset=utf-8', 672 'Content-Encoding': 'gzip', 673 'Cache-Control': 'public, max-age=300', 674 + 'X-Cache-Tier': 'local', // Rewritten HTML is stored locally 675 }; 676 applyCustomHeaders(headers, indexPath, settings); 677 return new Response(rewrittenContent, { headers }); 678 } 679 680 + const indexResult = await getFileWithMetadata(did, rkey, indexPath); 681 682 + if (indexResult) { 683 + const indexContent = Buffer.from(indexResult.data); 684 + const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 685 const isGzipped = indexMeta?.encoding === 'gzip'; 686 687 let htmlContent: string; ··· 709 'Content-Type': 'text/html; charset=utf-8', 710 'Content-Encoding': 'gzip', 711 'Cache-Control': 'public, max-age=300', 712 + 'X-Cache-Tier': indexResult.source, 713 }; 714 applyCustomHeaders(headers, indexPath, settings); 715 return new Response(recompressed, { headers });
+46 -35
apps/hosting-service/src/lib/firehose.ts
··· 1 - import { existsSync, rmSync } from 'fs' 2 import { 3 getPdsForDid, 4 downloadAndCacheSite, ··· 13 import { invalidateSiteCache, markSiteAsBeingCached, unmarkSiteAsBeingCached } from './cache' 14 import { clearRedirectRulesCache } from './site-cache' 15 16 - const CACHE_DIR = './cache/sites' 17 18 export class FirehoseWorker { 19 private firehose: Firehose | null = null 20 private idResolver: IdResolver 21 private isShuttingDown = false 22 private lastEventTime = Date.now() 23 private cacheCleanupInterval: NodeJS.Timeout | null = null 24 25 constructor( 26 private logger?: (msg: string, data?: Record<string, unknown>) => void ··· 47 48 this.log('IdResolver cache cleared') 49 }, 60 * 60 * 1000) // Every hour 50 } 51 52 start() { ··· 61 if (this.cacheCleanupInterval) { 62 clearInterval(this.cacheCleanupInterval) 63 this.cacheCleanupInterval = null 64 } 65 66 if (this.firehose) { ··· 80 filterCollections: ['place.wisp.fs', 'place.wisp.settings'], 81 handleEvent: async (evt: any) => { 82 this.lastEventTime = Date.now() 83 84 // Watch for write events 85 if (evt.event === 'create' || evt.event === 'update') { ··· 189 } 190 }) 191 192 - this.firehose.start() 193 - this.log('Firehose started') 194 } 195 196 private async handleCreateOrUpdate( ··· 250 } 251 252 // Invalidate in-memory caches before updating 253 - invalidateSiteCache(did, site) 254 255 // Mark site as being cached to prevent serving stale content during update 256 markSiteAsBeingCached(did, site) ··· 340 }) 341 } 342 343 - // Invalidate in-memory caches 344 - invalidateSiteCache(did, site) 345 - 346 - // Delete disk cache 347 - this.deleteCache(did, site) 348 349 this.log('Successfully processed delete', { did, site }) 350 } ··· 353 this.log('Processing settings change', { did, rkey }) 354 355 // Invalidate in-memory caches (includes metadata which stores settings) 356 - invalidateSiteCache(did, rkey) 357 358 // Check if site is already cached 359 const cacheDir = `${CACHE_DIR}/${did}/${rkey}` ··· 413 } 414 415 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 } 441 442 getHealth() {
··· 1 + import { existsSync } from 'fs' 2 import { 3 getPdsForDid, 4 downloadAndCacheSite, ··· 13 import { invalidateSiteCache, markSiteAsBeingCached, unmarkSiteAsBeingCached } from './cache' 14 import { clearRedirectRulesCache } from './site-cache' 15 16 + const CACHE_DIR = process.env.CACHE_DIR || './cache/sites' 17 18 export class FirehoseWorker { 19 private firehose: Firehose | null = null 20 private idResolver: IdResolver 21 private isShuttingDown = false 22 private lastEventTime = Date.now() 23 + private eventCount = 0 24 private cacheCleanupInterval: NodeJS.Timeout | null = null 25 + private healthCheckInterval: NodeJS.Timeout | null = null 26 27 constructor( 28 private logger?: (msg: string, data?: Record<string, unknown>) => void ··· 49 50 this.log('IdResolver cache cleared') 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 70 } 71 72 start() { ··· 81 if (this.cacheCleanupInterval) { 82 clearInterval(this.cacheCleanupInterval) 83 this.cacheCleanupInterval = null 84 + } 85 + 86 + if (this.healthCheckInterval) { 87 + clearInterval(this.healthCheckInterval) 88 + this.healthCheckInterval = null 89 } 90 91 if (this.firehose) { ··· 105 filterCollections: ['place.wisp.fs', 'place.wisp.settings'], 106 handleEvent: async (evt: any) => { 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 + } 116 117 // Watch for write events 118 if (evt.event === 'create' || evt.event === 'update') { ··· 222 } 223 }) 224 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') 232 } 233 234 private async handleCreateOrUpdate( ··· 288 } 289 290 // Invalidate in-memory caches before updating 291 + await invalidateSiteCache(did, site) 292 293 // Mark site as being cached to prevent serving stale content during update 294 markSiteAsBeingCached(did, site) ··· 378 }) 379 } 380 381 + // Invalidate all caches (tiered storage invalidation is handled by invalidateSiteCache) 382 + await invalidateSiteCache(did, site) 383 384 this.log('Successfully processed delete', { did, site }) 385 } ··· 388 this.log('Processing settings change', { did, rkey }) 389 390 // Invalidate in-memory caches (includes metadata which stores settings) 391 + await invalidateSiteCache(did, rkey) 392 393 // Check if site is already cached 394 const cacheDir = `${CACHE_DIR}/${did}/${rkey}` ··· 448 } 449 450 this.log('Successfully processed settings change', { did, rkey }) 451 } 452 453 getHealth() {
+16
apps/hosting-service/src/lib/html-rewriter.ts
··· 189 `\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}'([^']*)'`, 190 'gi' 191 ) 192 193 rewritten = rewritten.replace(doubleQuoteRegex, (match, value) => { 194 const rewrittenValue = rewritePath( ··· 206 documentPath 207 ) 208 return `${attr}='${rewrittenValue}'` 209 }) 210 } 211 }
··· 189 `\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}'([^']*)'`, 190 'gi' 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 + ) 199 200 rewritten = rewritten.replace(doubleQuoteRegex, (match, value) => { 201 const rewrittenValue = rewritePath( ··· 213 documentPath 214 ) 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}` 225 }) 226 } 227 }
+1 -1
apps/hosting-service/src/lib/site-cache.ts
··· 42 * Returns true if site is successfully cached, false otherwise 43 */ 44 export async function ensureSiteCached(did: string, rkey: string): Promise<boolean> { 45 - if (isCached(did, rkey)) { 46 return true; 47 } 48
··· 42 * Returns true if site is successfully cached, false otherwise 43 */ 44 export async function ensureSiteCached(did: string, rkey: string): Promise<boolean> { 45 + if (await isCached(did, rkey)) { 46 return true; 47 } 48
+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
··· 4 import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings'; 5 import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs'; 6 import { writeFile, readFile, rename } from 'fs/promises'; 7 import { safeFetchJson, safeFetchBlob } from '@wisp/safe-fetch'; 8 import { CID } from 'multiformats'; 9 import { extractBlobCid } from '@wisp/atproto-utils'; 10 import { sanitizePath, collectFileCidsFromEntries, countFilesInDirectory } from '@wisp/fs-utils'; 11 import { shouldCompressMimeType } from '@wisp/atproto-utils/compression'; 12 import { MAX_BLOB_SIZE, MAX_FILE_COUNT, MAX_SITE_SIZE } from '@wisp/constants'; 13 14 // Re-export shared utilities for local usage and tests 15 export { extractBlobCid, sanitizePath }; ··· 395 const existingMetadata = await getCacheMetadata(did, rkey); 396 const existingFileCids = existingMetadata?.fileCids || {}; 397 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); 407 408 - // Fetch site settings (optional) 409 - const settings = await fetchSiteSettings(did, rkey); 410 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); 414 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 - } 448 } 449 450 ··· 454 entries: Entry[], 455 pdsEndpoint: string, 456 pathPrefix: string, 457 - dirSuffix: string = '', 458 - existingFileCids: Record<string, string> = {}, 459 - existingCacheDir?: string 460 ): Promise<void> { 461 - // Collect file tasks, separating unchanged files from new/changed files 462 const downloadTasks: Array<() => Promise<void>> = []; 463 - const copyTasks: Array<() => Promise<void>> = []; 464 465 function collectFileTasks( 466 entries: Entry[], ··· 477 const cid = extractBlobCid(fileNode.blob); 478 479 // 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 - )); 489 } else { 490 // File new or changed - download it 491 downloadTasks.push(() => cacheFileBlob( ··· 496 pdsEndpoint, 497 fileNode.encoding, 498 fileNode.mimeType, 499 - fileNode.base64, 500 - dirSuffix 501 )); 502 } 503 } ··· 506 507 collectFileTasks(entries, pathPrefix); 508 509 - console.log(`[Incremental Update] Files to copy: ${copyTasks.length}, Files to download: ${downloadTasks.length}`); 510 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 522 const downloadLimit = 20; 523 let successCount = 0; 524 let failureCount = 0; ··· 547 } 548 } 549 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 async function cacheFileBlob( 588 did: string, 589 site: string, ··· 592 pdsEndpoint: string, 593 encoding?: 'gzip', 594 mimeType?: string, 595 - base64?: boolean, 596 - dirSuffix: string = '' 597 ): Promise<void> { 598 const cid = extractBlobCid(blobRef); 599 if (!cid) { ··· 616 content = Buffer.from(base64String, 'base64'); 617 } 618 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 // Use the shared function to determine if this should remain compressed 627 const shouldStayCompressed = shouldCompressMimeType(mimeType); 628 ··· 640 } 641 } 642 643 - await writeFile(cacheFile, content); 644 645 - // Store metadata only if file is still compressed 646 if (encoding === 'gzip' && mimeType) { 647 - const metaFile = `${cacheFile}.meta`; 648 - await writeFile(metaFile, JSON.stringify({ encoding, mimeType })); 649 console.log('Cached file', filePath, content.length, 'bytes (gzipped,', mimeType + ')'); 650 } else { 651 console.log('Cached file', filePath, content.length, 'bytes'); ··· 658 return `${CACHE_DIR}/${did}/${site}/${sanitizedPath}`; 659 } 660 661 - export function isCached(did: string, site: string): boolean { 662 - return existsSync(`${CACHE_DIR}/${did}/${site}`); 663 } 664 665 - async function saveCacheMetadata(did: string, rkey: string, recordCid: string, dirSuffix: string = '', fileCids?: Record<string, string>, settings?: WispSettings | null): Promise<void> { 666 const metadata: CacheMetadata = { 667 recordCid, 668 cachedAt: Date.now(), ··· 672 settings: settings || undefined 673 }; 674 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)); 683 } 684 685 async function getCacheMetadata(did: string, rkey: string): Promise<CacheMetadata | null> { 686 try { 687 - const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`; 688 - if (!existsSync(metadataPath)) return null; 689 690 - const content = await readFile(metadataPath, 'utf-8'); 691 - return JSON.parse(content) as CacheMetadata; 692 } catch (err) { 693 console.error('Failed to read cache metadata', err); 694 return null; ··· 722 } 723 724 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 try { 733 - // Read existing metadata 734 - const content = await readFile(metadataPath, 'utf-8'); 735 - const metadata = JSON.parse(content) as CacheMetadata; 736 737 // Update settings field 738 // Store null explicitly to cache "no settings" state and avoid repeated fetches 739 metadata.settings = settings ?? null; 740 741 - // Write back to disk 742 - await writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf-8'); 743 console.log('Updated metadata settings', { did, rkey, hasSettings: !!settings }); 744 } catch (err) { 745 console.error('Failed to update metadata settings', err);
··· 4 import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings'; 5 import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs'; 6 import { writeFile, readFile, rename } from 'fs/promises'; 7 + import { Readable } from 'stream'; 8 import { safeFetchJson, safeFetchBlob } from '@wisp/safe-fetch'; 9 import { CID } from 'multiformats'; 10 import { extractBlobCid } from '@wisp/atproto-utils'; 11 import { sanitizePath, collectFileCidsFromEntries, countFilesInDirectory } from '@wisp/fs-utils'; 12 import { shouldCompressMimeType } from '@wisp/atproto-utils/compression'; 13 import { MAX_BLOB_SIZE, MAX_FILE_COUNT, MAX_SITE_SIZE } from '@wisp/constants'; 14 + import { storage } from './storage'; 15 16 // Re-export shared utilities for local usage and tests 17 export { extractBlobCid, sanitizePath }; ··· 397 const existingMetadata = await getCacheMetadata(did, rkey); 398 const existingFileCids = existingMetadata?.fileCids || {}; 399 400 + // Collect file CIDs from the new record (using expanded root) 401 + const newFileCids: Record<string, string> = {}; 402 + collectFileCidsFromEntries(expandedRoot.entries, '', newFileCids); 403 404 + // Fetch site settings (optional) 405 + const settings = await fetchSiteSettings(did, rkey); 406 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); 410 411 + console.log('Successfully cached site', did, rkey); 412 } 413 414 ··· 418 entries: Entry[], 419 pdsEndpoint: string, 420 pathPrefix: string, 421 + existingFileCids: Record<string, string> = {} 422 ): Promise<void> { 423 + // Collect file download tasks (skip unchanged files) 424 const downloadTasks: Array<() => Promise<void>> = []; 425 426 function collectFileTasks( 427 entries: Entry[], ··· 438 const cid = extractBlobCid(fileNode.blob); 439 440 // Check if file is unchanged (same CID as existing cache) 441 + if (cid && existingFileCids[currentPath] === cid) { 442 + // File unchanged - skip download (already in tiered storage) 443 + console.log(`Skipping unchanged file: ${currentPath}`); 444 } else { 445 // File new or changed - download it 446 downloadTasks.push(() => cacheFileBlob( ··· 451 pdsEndpoint, 452 fileNode.encoding, 453 fileNode.mimeType, 454 + fileNode.base64 455 )); 456 } 457 } ··· 460 461 collectFileTasks(entries, pathPrefix); 462 463 + console.log(`[Incremental Update] Files to download: ${downloadTasks.length}`); 464 465 + // Download new/changed files concurrently 466 const downloadLimit = 20; 467 let successCount = 0; 468 let failureCount = 0; ··· 491 } 492 } 493 494 async function cacheFileBlob( 495 did: string, 496 site: string, ··· 499 pdsEndpoint: string, 500 encoding?: 'gzip', 501 mimeType?: string, 502 + base64?: boolean 503 ): Promise<void> { 504 const cid = extractBlobCid(blobRef); 505 if (!cid) { ··· 522 content = Buffer.from(base64String, 'base64'); 523 } 524 525 // Use the shared function to determine if this should remain compressed 526 const shouldStayCompressed = shouldCompressMimeType(mimeType); 527 ··· 539 } 540 } 541 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 + }); 556 557 + // Log completion 558 if (encoding === 'gzip' && mimeType) { 559 console.log('Cached file', filePath, content.length, 'bytes (gzipped,', mimeType + ')'); 560 } else { 561 console.log('Cached file', filePath, content.length, 'bytes'); ··· 568 return `${CACHE_DIR}/${did}/${site}/${sanitizedPath}`; 569 } 570 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); 580 } 581 582 + async function saveCacheMetadata(did: string, rkey: string, recordCid: string, fileCids?: Record<string, string>, settings?: WispSettings | null): Promise<void> { 583 const metadata: CacheMetadata = { 584 recordCid, 585 cachedAt: Date.now(), ··· 589 settings: settings || undefined 590 }; 591 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); 596 } 597 598 async function getCacheMetadata(did: string, rkey: string): Promise<CacheMetadata | null> { 599 try { 600 + // Retrieve metadata from tiered storage 601 + const metadataKey = `${did}/${rkey}/.metadata.json`; 602 + const data = await storage.get(metadataKey); 603 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; 609 } catch (err) { 610 console.error('Failed to read cache metadata', err); 611 return null; ··· 639 } 640 641 export async function updateCacheMetadataSettings(did: string, rkey: string, settings: WispSettings | null): Promise<void> { 642 try { 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 + } 650 651 // Update settings field 652 // Store null explicitly to cache "no settings" state and avoid repeated fetches 653 metadata.settings = settings ?? null; 654 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); 660 console.log('Updated metadata settings', { did, rkey, hasSettings: !!settings }); 661 } catch (err) { 662 console.error('Failed to update metadata settings', err);
+4 -1
apps/hosting-service/src/server.ts
··· 80 return c.text('Invalid identifier', 400); 81 } 82 83 // Check if site is currently being cached - return updating response early 84 if (isSiteBeingCached(did, site)) { 85 return siteUpdatingResponse(); ··· 93 94 // Serve with HTML path rewriting to handle absolute paths 95 const basePath = `/${identifier}/${site}/`; 96 const headers = extractHeaders(c.req.raw.headers); 97 return serveFromCacheWithRewrite(did, site, filePath, basePath, c.req.url, headers); 98 } ··· 227 228 app.get('/__internal__/observability/cache', async (c) => { 229 const { getCacheStats } = await import('./lib/cache'); 230 - const stats = getCacheStats(); 231 return c.json({ cache: stats }); 232 }); 233
··· 80 return c.text('Invalid identifier', 400); 81 } 82 83 + console.log(`[Server] sites.wisp.place request: identifier=${identifier}, site=${site}, filePath=${filePath}`); 84 + 85 // Check if site is currently being cached - return updating response early 86 if (isSiteBeingCached(did, site)) { 87 return siteUpdatingResponse(); ··· 95 96 // Serve with HTML path rewriting to handle absolute paths 97 const basePath = `/${identifier}/${site}/`; 98 + console.log(`[Server] Serving with basePath: ${basePath}`); 99 const headers = extractHeaders(c.req.raw.headers); 100 return serveFromCacheWithRewrite(did, site, filePath, basePath, c.req.url, headers); 101 } ··· 230 231 app.get('/__internal__/observability/cache', async (c) => { 232 const { getCacheStats } = await import('./lib/cache'); 233 + const stats = await getCacheStats(); 234 return c.json({ cache: stats }); 235 }); 236
+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
··· 36 "mime-types": "^2.1.35", 37 "multiformats": "^13.4.1", 38 "postgres": "^3.4.5", 39 }, 40 "devDependencies": { 41 "@types/bun": "^1.3.1", ··· 262 263 "@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 "@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="], 266 267 "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], ··· 544 545 "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], 546 547 "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], 548 549 "@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 "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], 644 645 "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=="], 646 647 "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], 648 649 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 650 651 - "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], 652 653 "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 ··· 750 751 "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], 752 753 "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], 754 755 "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 961 "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 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=="], 964 965 "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], 966 ··· 1004 1005 "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], 1006 1007 "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 1009 "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], 1010 1011 "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 1012 1013 "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], 1014 ··· 1024 1025 "thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="], 1026 1027 "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 1028 1029 "tlds": ["tlds@1.261.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA=="], ··· 1063 "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 1065 "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=="], 1066 1067 "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], 1068 ··· 1118 1119 "@atproto/sync/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1120 1121 "@ipld/dag-cbor/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1122 1123 "@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="], ··· 1274 1275 "@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 1277 "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], 1278 1279 "iron-session/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], ··· 1282 1283 "node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 1284 1285 "require-in-the-middle/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 1286 1287 "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 "send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 1292 1293 "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=="], 1294 1295 "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], 1296 ··· 1302 1303 "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 1305 - "wisp-hosting-service/@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="], 1306 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=="], 1308 1309 "@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 ··· 1342 1343 "@wisp/main-app/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1344 1345 "require-in-the-middle/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 1346 1347 "serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], ··· 1351 "serve-static/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 1352 1353 "serve-static/send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 1354 1355 "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA=="], 1356 ··· 1406 1407 "wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1408 1409 - "wisp-hosting-service/@types/bun/bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="], 1410 } 1411 }
··· 36 "mime-types": "^2.1.35", 37 "multiformats": "^13.4.1", 38 "postgres": "^3.4.5", 39 + "tiered-storage": "1.0.3", 40 }, 41 "devDependencies": { 42 "@types/bun": "^1.3.1", ··· 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=="], 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 + 350 "@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="], 351 352 "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], ··· 629 630 "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], 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 + 734 "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], 735 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=="], ··· 830 "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], 831 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=="], 835 836 "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], 837 838 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 839 840 + "buffer": ["buffer@5.6.0", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw=="], 841 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=="], 843 ··· 939 940 "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], 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 + 944 "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], 945 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=="], ··· 1151 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=="], 1153 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=="], 1155 1156 "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], 1157 ··· 1195 1196 "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], 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 + 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=="], 1201 1202 "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], 1203 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=="], 1207 1208 "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], 1209 ··· 1219 1220 "thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="], 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 + 1226 "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 1227 1228 "tlds": ["tlds@1.261.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA=="], ··· 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=="], 1263 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=="], 1267 1268 "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], 1269 ··· 1319 1320 "@atproto/sync/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 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 + 1328 "@ipld/dag-cbor/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1329 1330 "@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="], ··· 1481 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=="], 1483 1484 + "@wisp/observability/bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], 1485 + 1486 "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], 1487 1488 "iron-session/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], ··· 1491 1492 "node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 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 + 1496 "require-in-the-middle/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 1497 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=="], ··· 1502 "send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 1503 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=="], 1507 1508 "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], 1509 ··· 1515 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=="], 1517 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=="], 1519 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=="], 1525 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=="], 1527 ··· 1559 1560 "@wisp/main-app/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 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 + 1564 "require-in-the-middle/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 1565 1566 "serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], ··· 1570 "serve-static/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 1571 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=="], 1575 1576 "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA=="], 1577 ··· 1627 1628 "wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1629 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=="], 1635 } 1636 }
+277 -516
cli/Cargo.lock
··· 3 version = 4 4 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 name = "addr2line" 26 version = "0.25.1" 27 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 71 dependencies = [ 72 "alloc-no-stdlib", 73 ] 74 75 [[package]] 76 name = "android_system_properties" ··· 139 140 [[package]] 141 name = "async-compression" 142 - version = "0.4.34" 143 source = "registry+https://github.com/rust-lang/crates.io-index" 144 - checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473" 145 dependencies = [ 146 "compression-codecs", 147 "compression-core", ··· 158 dependencies = [ 159 "proc-macro2", 160 "quote", 161 - "syn 2.0.111", 162 ] 163 164 [[package]] ··· 184 185 [[package]] 186 name = "axum" 187 - version = "0.8.7" 188 source = "registry+https://github.com/rust-lang/crates.io-index" 189 - checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" 190 dependencies = [ 191 "axum-core", 192 "bytes", ··· 217 218 [[package]] 219 name = "axum-core" 220 - version = "0.5.5" 221 source = "registry+https://github.com/rust-lang/crates.io-index" 222 - checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" 223 dependencies = [ 224 "bytes", 225 "futures-core", ··· 246 "miniz_oxide", 247 "object", 248 "rustc-demangle", 249 - "windows-link 0.2.1", 250 ] 251 252 [[package]] ··· 294 295 [[package]] 296 name = "base64ct" 297 - version = "1.8.0" 298 source = "registry+https://github.com/rust-lang/crates.io-index" 299 - checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" 300 301 [[package]] 302 name = "bitflags" ··· 335 "proc-macro2", 336 "quote", 337 "rustversion", 338 - "syn 2.0.111", 339 ] 340 341 [[package]] 342 name = "borsh" 343 - version = "1.5.7" 344 source = "registry+https://github.com/rust-lang/crates.io-index" 345 - checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" 346 dependencies = [ 347 "cfg_aliases", 348 ] ··· 376 dependencies = [ 377 "memchr", 378 "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 ] 404 405 [[package]] ··· 414 415 [[package]] 416 name = "bumpalo" 417 - version = "3.19.0" 418 source = "registry+https://github.com/rust-lang/crates.io-index" 419 - checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" 420 421 [[package]] 422 name = "byteorder" ··· 444 445 [[package]] 446 name = "cc" 447 - version = "1.2.47" 448 source = "registry+https://github.com/rust-lang/crates.io-index" 449 - checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" 450 dependencies = [ 451 "find-msvc-tools", 452 "shlex", 453 ] 454 455 [[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 name = "cesu8" 466 version = "1.1.0" 467 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 490 "num-traits", 491 "serde", 492 "wasm-bindgen", 493 - "windows-link 0.2.1", 494 ] 495 496 [[package]] ··· 542 543 [[package]] 544 name = "clap" 545 - version = "4.5.53" 546 source = "registry+https://github.com/rust-lang/crates.io-index" 547 - checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" 548 dependencies = [ 549 "clap_builder", 550 "clap_derive", ··· 552 553 [[package]] 554 name = "clap_builder" 555 - version = "4.5.53" 556 source = "registry+https://github.com/rust-lang/crates.io-index" 557 - checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" 558 dependencies = [ 559 "anstream", 560 "anstyle", ··· 571 "heck 0.5.0", 572 "proc-macro2", 573 "quote", 574 - "syn 2.0.111", 575 ] 576 577 [[package]] ··· 607 608 [[package]] 609 name = "compression-codecs" 610 - version = "0.4.33" 611 source = "registry+https://github.com/rust-lang/crates.io-index" 612 - checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad" 613 dependencies = [ 614 "compression-core", 615 "flate2", ··· 799 "proc-macro2", 800 "quote", 801 "strsim", 802 - "syn 2.0.111", 803 ] 804 805 [[package]] ··· 810 dependencies = [ 811 "darling_core", 812 "quote", 813 - "syn 2.0.111", 814 ] 815 816 [[package]] ··· 850 checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" 851 dependencies = [ 852 "data-encoding", 853 - "syn 2.0.111", 854 ] 855 856 [[package]] ··· 881 checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" 882 dependencies = [ 883 "powerfmt", 884 - "serde_core", 885 ] 886 887 [[package]] ··· 901 dependencies = [ 902 "proc-macro2", 903 "quote", 904 - "syn 2.0.111", 905 "unicode-xid", 906 ] 907 ··· 952 dependencies = [ 953 "proc-macro2", 954 "quote", 955 - "syn 2.0.111", 956 ] 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 964 [[package]] 965 name = "ecdsa" ··· 1031 "heck 0.5.0", 1032 "proc-macro2", 1033 "quote", 1034 - "syn 2.0.111", 1035 ] 1036 1037 [[package]] ··· 1080 1081 [[package]] 1082 name = "find-msvc-tools" 1083 - version = "0.1.5" 1084 source = "registry+https://github.com/rust-lang/crates.io-index" 1085 - checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 1086 1087 [[package]] 1088 name = "flate2" ··· 1099 version = "1.0.7" 1100 source = "registry+https://github.com/rust-lang/crates.io-index" 1101 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 1102 1103 [[package]] 1104 name = "form_urlencoded" ··· 1201 dependencies = [ 1202 "proc-macro2", 1203 "quote", 1204 - "syn 2.0.111", 1205 ] 1206 1207 [[package]] ··· 1236 1237 [[package]] 1238 name = "generator" 1239 - version = "0.8.7" 1240 source = "registry+https://github.com/rust-lang/crates.io-index" 1241 - checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" 1242 dependencies = [ 1243 "cc", 1244 "cfg-if", 1245 "libc", 1246 "log", 1247 "rustversion", 1248 - "windows", 1249 ] 1250 1251 [[package]] ··· 1355 1356 [[package]] 1357 name = "h2" 1358 - version = "0.4.12" 1359 source = "registry+https://github.com/rust-lang/crates.io-index" 1360 - checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" 1361 dependencies = [ 1362 "atomic-waker", 1363 "bytes", ··· 1365 "futures-core", 1366 "futures-sink", 1367 "http", 1368 - "indexmap 2.12.1", 1369 "slab", 1370 "tokio", 1371 "tokio-util", ··· 1394 1395 [[package]] 1396 name = "hashbrown" 1397 - version = "0.12.3" 1398 source = "registry+https://github.com/rust-lang/crates.io-index" 1399 - checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 1400 1401 [[package]] 1402 name = "hashbrown" 1403 - version = "0.14.5" 1404 source = "registry+https://github.com/rust-lang/crates.io-index" 1405 - checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 1406 1407 [[package]] 1408 name = "hashbrown" ··· 1449 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1450 1451 [[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 name = "hickory-proto" 1459 version = "0.24.4" 1460 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1519 "markup5ever", 1520 "proc-macro2", 1521 "quote", 1522 - "syn 2.0.111", 1523 ] 1524 1525 [[package]] ··· 1615 1616 [[package]] 1617 name = "hyper-util" 1618 - version = "0.1.18" 1619 source = "registry+https://github.com/rust-lang/crates.io-index" 1620 - checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" 1621 dependencies = [ 1622 "base64 0.22.1", 1623 "bytes", ··· 1651 "js-sys", 1652 "log", 1653 "wasm-bindgen", 1654 - "windows-core 0.62.2", 1655 ] 1656 1657 [[package]] ··· 1711 1712 [[package]] 1713 name = "icu_properties" 1714 - version = "2.1.1" 1715 source = "registry+https://github.com/rust-lang/crates.io-index" 1716 - checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" 1717 dependencies = [ 1718 "icu_collections", 1719 "icu_locale_core", ··· 1725 1726 [[package]] 1727 name = "icu_properties_data" 1728 - version = "2.1.1" 1729 source = "registry+https://github.com/rust-lang/crates.io-index" 1730 - checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" 1731 1732 [[package]] 1733 name = "icu_provider" ··· 1789 1790 [[package]] 1791 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 version = "2.12.1" 1804 source = "registry+https://github.com/rust-lang/crates.io-index" 1805 checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 1806 dependencies = [ 1807 "equivalent", 1808 "hashbrown 0.16.1", 1809 - "serde", 1810 - "serde_core", 1811 ] 1812 1813 [[package]] ··· 1821 "portable-atomic", 1822 "unicode-width 0.2.2", 1823 "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 ] 1834 1835 [[package]] ··· 1872 1873 [[package]] 1874 name = "iri-string" 1875 - version = "0.7.9" 1876 source = "registry+https://github.com/rust-lang/crates.io-index" 1877 - checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" 1878 dependencies = [ 1879 "memchr", 1880 "serde", ··· 1894 1895 [[package]] 1896 name = "itoa" 1897 - version = "1.0.15" 1898 source = "registry+https://github.com/rust-lang/crates.io-index" 1899 - checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 1900 1901 [[package]] 1902 name = "jacquard" 1903 - version = "0.9.4" 1904 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 1905 dependencies = [ 1906 "bytes", 1907 "getrandom 0.2.16", ··· 1917 "regex", 1918 "regex-lite", 1919 "reqwest", 1920 - "ring", 1921 "serde", 1922 "serde_html_form", 1923 "serde_json", ··· 1931 1932 [[package]] 1933 name = "jacquard-api" 1934 - version = "0.9.2" 1935 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 1936 dependencies = [ 1937 "bon", 1938 "bytes", ··· 1950 1951 [[package]] 1952 name = "jacquard-common" 1953 - version = "0.9.2" 1954 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 1955 dependencies = [ 1956 "base64 0.22.1", 1957 "bon", 1958 "bytes", 1959 "chrono", 1960 "ciborium", 1961 "cid", 1962 "futures", 1963 "getrandom 0.2.16", 1964 "getrandom 0.3.4", 1965 "http", 1966 "ipld-core", 1967 "k256", 1968 - "langtag", 1969 "miette", 1970 "multibase", 1971 "multihash", 1972 "n0-future 0.1.3", 1973 "ouroboros", 1974 "p256", 1975 "postcard", 1976 "rand 0.9.2", 1977 "regex", 1978 "regex-lite", 1979 "reqwest", 1980 - "ring", 1981 "serde", 1982 "serde_bytes", 1983 "serde_html_form", ··· 1985 "serde_json", 1986 "signature", 1987 "smol_str", 1988 "thiserror 2.0.17", 1989 "tokio", 1990 "tokio-tungstenite-wasm", ··· 1995 1996 [[package]] 1997 name = "jacquard-derive" 1998 - version = "0.9.4" 1999 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 2000 dependencies = [ 2001 "heck 0.5.0", 2002 "jacquard-lexicon", 2003 "proc-macro2", 2004 "quote", 2005 - "syn 2.0.111", 2006 ] 2007 2008 [[package]] 2009 name = "jacquard-identity" 2010 - version = "0.9.2" 2011 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 2012 dependencies = [ 2013 "bon", 2014 "bytes", ··· 2018 "jacquard-common", 2019 "jacquard-lexicon", 2020 "miette", 2021 - "mini-moka", 2022 "n0-future 0.1.3", 2023 "percent-encoding", 2024 "reqwest", 2025 - "ring", 2026 "serde", 2027 "serde_html_form", 2028 "serde_json", ··· 2035 2036 [[package]] 2037 name = "jacquard-lexicon" 2038 - version = "0.9.2" 2039 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 2040 dependencies = [ 2041 "cid", 2042 "dashmap", ··· 2054 "serde_repr", 2055 "serde_with", 2056 "sha2", 2057 - "syn 2.0.111", 2058 "thiserror 2.0.17", 2059 "unicode-segmentation", 2060 ] 2061 2062 [[package]] 2063 name = "jacquard-oauth" 2064 - version = "0.9.2" 2065 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 2066 dependencies = [ 2067 "base64 0.22.1", 2068 "bytes", ··· 2077 "miette", 2078 "p256", 2079 "rand 0.8.5", 2080 - "ring", 2081 "rouille", 2082 "serde", 2083 "serde_html_form", ··· 2151 2152 [[package]] 2153 name = "js-sys" 2154 - version = "0.3.82" 2155 source = "registry+https://github.com/rust-lang/crates.io-index" 2156 - checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" 2157 dependencies = [ 2158 "once_cell", 2159 "wasm-bindgen", ··· 2172 ] 2173 2174 [[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 name = "lazy_static" 2187 version = "1.5.0" 2188 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2193 2194 [[package]] 2195 name = "libc" 2196 - version = "0.2.177" 2197 source = "registry+https://github.com/rust-lang/crates.io-index" 2198 - checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 2199 2200 [[package]] 2201 name = "libm" ··· 2205 2206 [[package]] 2207 name = "libredox" 2208 - version = "0.1.10" 2209 source = "registry+https://github.com/rust-lang/crates.io-index" 2210 - checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" 2211 dependencies = [ 2212 "bitflags", 2213 "libc", 2214 - "redox_syscall", 2215 ] 2216 2217 [[package]] ··· 2243 2244 [[package]] 2245 name = "log" 2246 - version = "0.4.28" 2247 source = "registry+https://github.com/rust-lang/crates.io-index" 2248 - checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 2249 2250 [[package]] 2251 name = "loom" ··· 2282 checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 2283 2284 [[package]] 2285 name = "markup5ever" 2286 version = "0.12.1" 2287 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2366 dependencies = [ 2367 "proc-macro2", 2368 "quote", 2369 - "syn 2.0.111", 2370 ] 2371 2372 [[package]] ··· 2386 ] 2387 2388 [[package]] 2389 - name = "mini-moka" 2390 version = "0.10.99" 2391 - source = "git+https://tangled.org/nekomimi.pet/jacquard#69a1552424ffa439ea1022aa8e3f311ed77ab4df" 2392 dependencies = [ 2393 "crossbeam-channel", 2394 "crossbeam-utils", ··· 2400 ] 2401 2402 [[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 name = "miniz_oxide" 2410 version = "0.8.9" 2411 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2417 2418 [[package]] 2419 name = "mio" 2420 - version = "1.1.0" 2421 source = "registry+https://github.com/rust-lang/crates.io-index" 2422 - checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" 2423 dependencies = [ 2424 "libc", 2425 "wasi", ··· 2468 ] 2469 2470 [[package]] 2471 name = "n0-future" 2472 version = "0.1.3" 2473 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2520 version = "1.0.6" 2521 source = "registry+https://github.com/rust-lang/crates.io-index" 2522 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 2534 [[package]] 2535 name = "nu-ansi-term" ··· 2665 2666 [[package]] 2667 name = "openssl-probe" 2668 - version = "0.1.6" 2669 source = "registry+https://github.com/rust-lang/crates.io-index" 2670 - checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 2671 2672 [[package]] 2673 name = "option-ext" ··· 2696 "proc-macro2", 2697 "proc-macro2-diagnostics", 2698 "quote", 2699 - "syn 2.0.111", 2700 ] 2701 2702 [[package]] ··· 2706 checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" 2707 2708 [[package]] 2709 name = "p256" 2710 version = "0.13.2" 2711 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2751 dependencies = [ 2752 "cfg-if", 2753 "libc", 2754 - "redox_syscall", 2755 "smallvec", 2756 - "windows-link 0.2.1", 2757 ] 2758 2759 [[package]] ··· 2826 dependencies = [ 2827 "proc-macro2", 2828 "quote", 2829 - "syn 2.0.111", 2830 ] 2831 2832 [[package]] ··· 2864 2865 [[package]] 2866 name = "portable-atomic" 2867 - version = "1.11.1" 2868 source = "registry+https://github.com/rust-lang/crates.io-index" 2869 - checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" 2870 2871 [[package]] 2872 name = "postcard" ··· 2918 checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 2919 dependencies = [ 2920 "proc-macro2", 2921 - "syn 2.0.111", 2922 ] 2923 2924 [[package]] ··· 2931 ] 2932 2933 [[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 name = "proc-macro2" 2959 - version = "1.0.103" 2960 source = "registry+https://github.com/rust-lang/crates.io-index" 2961 - checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 2962 dependencies = [ 2963 "unicode-ident", 2964 ] ··· 2971 dependencies = [ 2972 "proc-macro2", 2973 "quote", 2974 - "syn 2.0.111", 2975 "version_check", 2976 "yansi", 2977 ] ··· 3039 3040 [[package]] 3041 name = "quote" 3042 - version = "1.0.42" 3043 source = "registry+https://github.com/rust-lang/crates.io-index" 3044 - checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 3045 dependencies = [ 3046 "proc-macro2", 3047 ] ··· 3112 ] 3113 3114 [[package]] 3115 - name = "range-traits" 3116 - version = "0.3.2" 3117 source = "registry+https://github.com/rust-lang/crates.io-index" 3118 - checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab" 3119 3120 [[package]] 3121 name = "redox_syscall" 3122 - version = "0.5.18" 3123 source = "registry+https://github.com/rust-lang/crates.io-index" 3124 - checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 3125 dependencies = [ 3126 "bitflags", 3127 ] ··· 3138 ] 3139 3140 [[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 name = "regex" 3162 version = "1.12.2" 3163 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3194 3195 [[package]] 3196 name = "reqwest" 3197 - version = "0.12.24" 3198 source = "registry+https://github.com/rust-lang/crates.io-index" 3199 - checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" 3200 dependencies = [ 3201 - "async-compression", 3202 "base64 0.22.1", 3203 "bytes", 3204 "encoding_rs", ··· 3293 3294 [[package]] 3295 name = "rsa" 3296 - version = "0.9.9" 3297 source = "registry+https://github.com/rust-lang/crates.io-index" 3298 - checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" 3299 dependencies = [ 3300 "const-oid", 3301 "digest", ··· 3334 3335 [[package]] 3336 name = "rustix" 3337 - version = "1.1.2" 3338 source = "registry+https://github.com/rust-lang/crates.io-index" 3339 - checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 3340 dependencies = [ 3341 "bitflags", 3342 "errno", ··· 3347 3348 [[package]] 3349 name = "rustls" 3350 - version = "0.23.35" 3351 source = "registry+https://github.com/rust-lang/crates.io-index" 3352 - checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" 3353 dependencies = [ 3354 "once_cell", 3355 "ring", ··· 3361 3362 [[package]] 3363 name = "rustls-native-certs" 3364 - version = "0.8.2" 3365 source = "registry+https://github.com/rust-lang/crates.io-index" 3366 - checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" 3367 dependencies = [ 3368 "openssl-probe", 3369 "rustls-pki-types", ··· 3373 3374 [[package]] 3375 name = "rustls-pki-types" 3376 - version = "1.13.0" 3377 source = "registry+https://github.com/rust-lang/crates.io-index" 3378 - checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" 3379 dependencies = [ 3380 "web-time", 3381 "zeroize", ··· 3400 3401 [[package]] 3402 name = "ryu" 3403 - version = "1.0.20" 3404 source = "registry+https://github.com/rust-lang/crates.io-index" 3405 - checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 3406 3407 [[package]] 3408 name = "safemem" ··· 3429 ] 3430 3431 [[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 name = "scoped-tls" 3457 version = "1.0.1" 3458 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3550 dependencies = [ 3551 "proc-macro2", 3552 "quote", 3553 - "syn 2.0.111", 3554 ] 3555 3556 [[package]] 3557 name = "serde_html_form" 3558 - version = "0.2.8" 3559 source = "registry+https://github.com/rust-lang/crates.io-index" 3560 - checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" 3561 dependencies = [ 3562 "form_urlencoded", 3563 - "indexmap 2.12.1", 3564 "itoa", 3565 - "ryu", 3566 "serde_core", 3567 ] 3568 ··· 3580 3581 [[package]] 3582 name = "serde_json" 3583 - version = "1.0.145" 3584 source = "registry+https://github.com/rust-lang/crates.io-index" 3585 - checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 3586 dependencies = [ 3587 "itoa", 3588 "memchr", 3589 - "ryu", 3590 "serde", 3591 "serde_core", 3592 ] 3593 3594 [[package]] ··· 3610 dependencies = [ 3611 "proc-macro2", 3612 "quote", 3613 - "syn 2.0.111", 3614 ] 3615 3616 [[package]] ··· 3627 3628 [[package]] 3629 name = "serde_with" 3630 - version = "3.16.0" 3631 source = "registry+https://github.com/rust-lang/crates.io-index" 3632 - checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" 3633 dependencies = [ 3634 "base64 0.22.1", 3635 "chrono", 3636 "hex", 3637 - "indexmap 1.9.3", 3638 - "indexmap 2.12.1", 3639 - "schemars 0.9.0", 3640 - "schemars 1.1.0", 3641 "serde_core", 3642 "serde_json", 3643 "serde_with_macros", ··· 3646 3647 [[package]] 3648 name = "serde_with_macros" 3649 - version = "3.16.0" 3650 source = "registry+https://github.com/rust-lang/crates.io-index" 3651 - checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" 3652 dependencies = [ 3653 "darling", 3654 "proc-macro2", 3655 "quote", 3656 - "syn 2.0.111", 3657 ] 3658 3659 [[package]] ··· 3710 3711 [[package]] 3712 name = "signal-hook-registry" 3713 - version = "1.4.7" 3714 source = "registry+https://github.com/rust-lang/crates.io-index" 3715 - checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" 3716 dependencies = [ 3717 "libc", 3718 ] 3719 ··· 3729 3730 [[package]] 3731 name = "simd-adler32" 3732 - version = "0.3.7" 3733 source = "registry+https://github.com/rust-lang/crates.io-index" 3734 - checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 3735 3736 [[package]] 3737 name = "siphasher" ··· 3813 checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 3814 3815 [[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 name = "static_assertions" 3837 version = "1.1.0" 3838 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3886 3887 [[package]] 3888 name = "supports-hyperlinks" 3889 - version = "3.1.0" 3890 source = "registry+https://github.com/rust-lang/crates.io-index" 3891 - checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" 3892 3893 [[package]] 3894 name = "supports-unicode" ··· 3909 3910 [[package]] 3911 name = "syn" 3912 - version = "2.0.111" 3913 source = "registry+https://github.com/rust-lang/crates.io-index" 3914 - checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" 3915 dependencies = [ 3916 "proc-macro2", 3917 "quote", ··· 3935 dependencies = [ 3936 "proc-macro2", 3937 "quote", 3938 - "syn 2.0.111", 3939 ] 3940 3941 [[package]] ··· 3967 3968 [[package]] 3969 name = "tempfile" 3970 - version = "3.23.0" 3971 source = "registry+https://github.com/rust-lang/crates.io-index" 3972 - checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" 3973 dependencies = [ 3974 "fastrand", 3975 "getrandom 0.3.4", ··· 4035 dependencies = [ 4036 "proc-macro2", 4037 "quote", 4038 - "syn 2.0.111", 4039 ] 4040 4041 [[package]] ··· 4046 dependencies = [ 4047 "proc-macro2", 4048 "quote", 4049 - "syn 2.0.111", 4050 ] 4051 4052 [[package]] ··· 4074 checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" 4075 dependencies = [ 4076 "deranged", 4077 - "itoa", 4078 "libc", 4079 "num-conv", 4080 "num_threads", 4081 "powerfmt", 4082 "serde", 4083 "time-core", 4084 - "time-macros", 4085 ] 4086 4087 [[package]] ··· 4091 checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" 4092 4093 [[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 name = "tiny_http" 4105 version = "0.12.0" 4106 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4139 4140 [[package]] 4141 name = "tokio" 4142 - version = "1.48.0" 4143 source = "registry+https://github.com/rust-lang/crates.io-index" 4144 - checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" 4145 dependencies = [ 4146 "bytes", 4147 "libc", ··· 4162 dependencies = [ 4163 "proc-macro2", 4164 "quote", 4165 - "syn 2.0.111", 4166 ] 4167 4168 [[package]] ··· 4212 4213 [[package]] 4214 name = "tokio-util" 4215 - version = "0.7.17" 4216 source = "registry+https://github.com/rust-lang/crates.io-index" 4217 - checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" 4218 dependencies = [ 4219 "bytes", 4220 "futures-core", ··· 4242 4243 [[package]] 4244 name = "tower-http" 4245 - version = "0.6.7" 4246 source = "registry+https://github.com/rust-lang/crates.io-index" 4247 - checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" 4248 dependencies = [ 4249 "async-compression", 4250 "bitflags", ··· 4283 4284 [[package]] 4285 name = "tracing" 4286 - version = "0.1.41" 4287 source = "registry+https://github.com/rust-lang/crates.io-index" 4288 - checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 4289 dependencies = [ 4290 "log", 4291 "pin-project-lite", ··· 4295 4296 [[package]] 4297 name = "tracing-attributes" 4298 - version = "0.1.30" 4299 source = "registry+https://github.com/rust-lang/crates.io-index" 4300 - checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 4301 dependencies = [ 4302 "proc-macro2", 4303 "quote", 4304 - "syn 2.0.111", 4305 ] 4306 4307 [[package]] 4308 name = "tracing-core" 4309 - version = "0.1.34" 4310 source = "registry+https://github.com/rust-lang/crates.io-index" 4311 - checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 4312 dependencies = [ 4313 "once_cell", 4314 "valuable", ··· 4327 4328 [[package]] 4329 name = "tracing-subscriber" 4330 - version = "0.3.20" 4331 source = "registry+https://github.com/rust-lang/crates.io-index" 4332 - checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" 4333 dependencies = [ 4334 "matchers", 4335 "nu-ansi-term", ··· 4351 dependencies = [ 4352 "proc-macro2", 4353 "quote", 4354 - "syn 2.0.111", 4355 ] 4356 4357 [[package]] ··· 4403 4404 [[package]] 4405 name = "unicase" 4406 - version = "2.8.1" 4407 source = "registry+https://github.com/rust-lang/crates.io-index" 4408 - checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 4409 4410 [[package]] 4411 name = "unicode-ident" ··· 4457 4458 [[package]] 4459 name = "url" 4460 - version = "2.5.7" 4461 source = "registry+https://github.com/rust-lang/crates.io-index" 4462 - checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 4463 dependencies = [ 4464 "form_urlencoded", 4465 "idna", 4466 "percent-encoding", 4467 "serde", 4468 ] 4469 4470 [[package]] ··· 4539 4540 [[package]] 4541 name = "wasm-bindgen" 4542 - version = "0.2.105" 4543 source = "registry+https://github.com/rust-lang/crates.io-index" 4544 - checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" 4545 dependencies = [ 4546 "cfg-if", 4547 "once_cell", ··· 4552 4553 [[package]] 4554 name = "wasm-bindgen-futures" 4555 - version = "0.4.55" 4556 source = "registry+https://github.com/rust-lang/crates.io-index" 4557 - checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" 4558 dependencies = [ 4559 "cfg-if", 4560 "js-sys", ··· 4565 4566 [[package]] 4567 name = "wasm-bindgen-macro" 4568 - version = "0.2.105" 4569 source = "registry+https://github.com/rust-lang/crates.io-index" 4570 - checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" 4571 dependencies = [ 4572 "quote", 4573 "wasm-bindgen-macro-support", ··· 4575 4576 [[package]] 4577 name = "wasm-bindgen-macro-support" 4578 - version = "0.2.105" 4579 source = "registry+https://github.com/rust-lang/crates.io-index" 4580 - checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" 4581 dependencies = [ 4582 "bumpalo", 4583 "proc-macro2", 4584 "quote", 4585 - "syn 2.0.111", 4586 "wasm-bindgen-shared", 4587 ] 4588 4589 [[package]] 4590 name = "wasm-bindgen-shared" 4591 - version = "0.2.105" 4592 source = "registry+https://github.com/rust-lang/crates.io-index" 4593 - checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" 4594 dependencies = [ 4595 "unicode-ident", 4596 ] ··· 4610 4611 [[package]] 4612 name = "web-sys" 4613 - version = "0.3.82" 4614 source = "registry+https://github.com/rust-lang/crates.io-index" 4615 - checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" 4616 dependencies = [ 4617 "js-sys", 4618 "wasm-bindgen", ··· 4658 4659 [[package]] 4660 name = "webpki-roots" 4661 - version = "1.0.4" 4662 source = "registry+https://github.com/rust-lang/crates.io-index" 4663 - checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" 4664 dependencies = [ 4665 "rustls-pki-types", 4666 ] ··· 4681 ] 4682 4683 [[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 name = "windows-core" 4720 version = "0.62.2" 4721 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4723 dependencies = [ 4724 "windows-implement", 4725 "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", 4740 ] 4741 4742 [[package]] ··· 4747 dependencies = [ 4748 "proc-macro2", 4749 "quote", 4750 - "syn 2.0.111", 4751 ] 4752 4753 [[package]] ··· 4758 dependencies = [ 4759 "proc-macro2", 4760 "quote", 4761 - "syn 2.0.111", 4762 ] 4763 4764 [[package]] 4765 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 version = "0.2.1" 4773 source = "registry+https://github.com/rust-lang/crates.io-index" 4774 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 4775 4776 [[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 name = "windows-registry" 4788 version = "0.6.1" 4789 source = "registry+https://github.com/rust-lang/crates.io-index" 4790 checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 4791 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", 4804 ] 4805 4806 [[package]] ··· 4809 source = "registry+https://github.com/rust-lang/crates.io-index" 4810 checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 4811 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", 4822 ] 4823 4824 [[package]] ··· 4827 source = "registry+https://github.com/rust-lang/crates.io-index" 4828 checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 4829 dependencies = [ 4830 - "windows-link 0.2.1", 4831 ] 4832 4833 [[package]] ··· 4881 source = "registry+https://github.com/rust-lang/crates.io-index" 4882 checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 4883 dependencies = [ 4884 - "windows-link 0.2.1", 4885 ] 4886 4887 [[package]] ··· 4936 source = "registry+https://github.com/rust-lang/crates.io-index" 4937 checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 4938 dependencies = [ 4939 - "windows-link 0.2.1", 4940 "windows_aarch64_gnullvm 0.53.1", 4941 "windows_aarch64_msvc 0.53.1", 4942 "windows_i686_gnu 0.53.1", ··· 4945 "windows_x86_64_gnu 0.53.1", 4946 "windows_x86_64_gnullvm 0.53.1", 4947 "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 ] 4958 4959 [[package]] ··· 5184 "tower-http", 5185 "url", 5186 "walkdir", 5187 ] 5188 5189 [[package]] ··· 5234 dependencies = [ 5235 "proc-macro2", 5236 "quote", 5237 - "syn 2.0.111", 5238 "synstructure", 5239 ] 5240 5241 [[package]] 5242 name = "zerocopy" 5243 - version = "0.8.30" 5244 source = "registry+https://github.com/rust-lang/crates.io-index" 5245 - checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" 5246 dependencies = [ 5247 "zerocopy-derive", 5248 ] 5249 5250 [[package]] 5251 name = "zerocopy-derive" 5252 - version = "0.8.30" 5253 source = "registry+https://github.com/rust-lang/crates.io-index" 5254 - checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" 5255 dependencies = [ 5256 "proc-macro2", 5257 "quote", 5258 - "syn 2.0.111", 5259 ] 5260 5261 [[package]] ··· 5275 dependencies = [ 5276 "proc-macro2", 5277 "quote", 5278 - "syn 2.0.111", 5279 "synstructure", 5280 ] 5281 ··· 5318 dependencies = [ 5319 "proc-macro2", 5320 "quote", 5321 - "syn 2.0.111", 5322 ]
··· 3 version = 4 4 5 [[package]] 6 name = "addr2line" 7 version = "0.25.1" 8 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 52 dependencies = [ 53 "alloc-no-stdlib", 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" 61 62 [[package]] 63 name = "android_system_properties" ··· 126 127 [[package]] 128 name = "async-compression" 129 + version = "0.4.36" 130 source = "registry+https://github.com/rust-lang/crates.io-index" 131 + checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" 132 dependencies = [ 133 "compression-codecs", 134 "compression-core", ··· 145 dependencies = [ 146 "proc-macro2", 147 "quote", 148 + "syn 2.0.113", 149 ] 150 151 [[package]] ··· 171 172 [[package]] 173 name = "axum" 174 + version = "0.8.8" 175 source = "registry+https://github.com/rust-lang/crates.io-index" 176 + checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" 177 dependencies = [ 178 "axum-core", 179 "bytes", ··· 204 205 [[package]] 206 name = "axum-core" 207 + version = "0.5.6" 208 source = "registry+https://github.com/rust-lang/crates.io-index" 209 + checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" 210 dependencies = [ 211 "bytes", 212 "futures-core", ··· 233 "miniz_oxide", 234 "object", 235 "rustc-demangle", 236 + "windows-link", 237 ] 238 239 [[package]] ··· 281 282 [[package]] 283 name = "base64ct" 284 + version = "1.8.2" 285 source = "registry+https://github.com/rust-lang/crates.io-index" 286 + checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" 287 288 [[package]] 289 name = "bitflags" ··· 322 "proc-macro2", 323 "quote", 324 "rustversion", 325 + "syn 2.0.113", 326 ] 327 328 [[package]] 329 name = "borsh" 330 + version = "1.6.0" 331 source = "registry+https://github.com/rust-lang/crates.io-index" 332 + checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 333 dependencies = [ 334 "cfg_aliases", 335 ] ··· 363 dependencies = [ 364 "memchr", 365 "serde", 366 ] 367 368 [[package]] ··· 377 378 [[package]] 379 name = "bumpalo" 380 + version = "3.19.1" 381 source = "registry+https://github.com/rust-lang/crates.io-index" 382 + checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" 383 384 [[package]] 385 name = "byteorder" ··· 407 408 [[package]] 409 name = "cc" 410 + version = "1.2.51" 411 source = "registry+https://github.com/rust-lang/crates.io-index" 412 + checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" 413 dependencies = [ 414 "find-msvc-tools", 415 "shlex", 416 ] 417 418 [[package]] 419 name = "cesu8" 420 version = "1.1.0" 421 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 444 "num-traits", 445 "serde", 446 "wasm-bindgen", 447 + "windows-link", 448 ] 449 450 [[package]] ··· 496 497 [[package]] 498 name = "clap" 499 + version = "4.5.54" 500 source = "registry+https://github.com/rust-lang/crates.io-index" 501 + checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" 502 dependencies = [ 503 "clap_builder", 504 "clap_derive", ··· 506 507 [[package]] 508 name = "clap_builder" 509 + version = "4.5.54" 510 source = "registry+https://github.com/rust-lang/crates.io-index" 511 + checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" 512 dependencies = [ 513 "anstream", 514 "anstyle", ··· 525 "heck 0.5.0", 526 "proc-macro2", 527 "quote", 528 + "syn 2.0.113", 529 ] 530 531 [[package]] ··· 561 562 [[package]] 563 name = "compression-codecs" 564 + version = "0.4.35" 565 source = "registry+https://github.com/rust-lang/crates.io-index" 566 + checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" 567 dependencies = [ 568 "compression-core", 569 "flate2", ··· 753 "proc-macro2", 754 "quote", 755 "strsim", 756 + "syn 2.0.113", 757 ] 758 759 [[package]] ··· 764 dependencies = [ 765 "darling_core", 766 "quote", 767 + "syn 2.0.113", 768 ] 769 770 [[package]] ··· 804 checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" 805 dependencies = [ 806 "data-encoding", 807 + "syn 2.0.113", 808 ] 809 810 [[package]] ··· 835 checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" 836 dependencies = [ 837 "powerfmt", 838 ] 839 840 [[package]] ··· 854 dependencies = [ 855 "proc-macro2", 856 "quote", 857 + "syn 2.0.113", 858 "unicode-xid", 859 ] 860 ··· 905 dependencies = [ 906 "proc-macro2", 907 "quote", 908 + "syn 2.0.113", 909 ] 910 911 [[package]] 912 name = "ecdsa" ··· 978 "heck 0.5.0", 979 "proc-macro2", 980 "quote", 981 + "syn 2.0.113", 982 ] 983 984 [[package]] ··· 1027 1028 [[package]] 1029 name = "find-msvc-tools" 1030 + version = "0.1.6" 1031 source = "registry+https://github.com/rust-lang/crates.io-index" 1032 + checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" 1033 1034 [[package]] 1035 name = "flate2" ··· 1046 version = "1.0.7" 1047 source = "registry+https://github.com/rust-lang/crates.io-index" 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" 1055 1056 [[package]] 1057 name = "form_urlencoded" ··· 1154 dependencies = [ 1155 "proc-macro2", 1156 "quote", 1157 + "syn 2.0.113", 1158 ] 1159 1160 [[package]] ··· 1189 1190 [[package]] 1191 name = "generator" 1192 + version = "0.8.8" 1193 source = "registry+https://github.com/rust-lang/crates.io-index" 1194 + checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" 1195 dependencies = [ 1196 "cc", 1197 "cfg-if", 1198 "libc", 1199 "log", 1200 "rustversion", 1201 + "windows-link", 1202 + "windows-result", 1203 ] 1204 1205 [[package]] ··· 1309 1310 [[package]] 1311 name = "h2" 1312 + version = "0.4.13" 1313 source = "registry+https://github.com/rust-lang/crates.io-index" 1314 + checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" 1315 dependencies = [ 1316 "atomic-waker", 1317 "bytes", ··· 1319 "futures-core", 1320 "futures-sink", 1321 "http", 1322 + "indexmap", 1323 "slab", 1324 "tokio", 1325 "tokio-util", ··· 1348 1349 [[package]] 1350 name = "hashbrown" 1351 + version = "0.14.5" 1352 source = "registry+https://github.com/rust-lang/crates.io-index" 1353 + checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 1354 1355 [[package]] 1356 name = "hashbrown" 1357 + version = "0.15.5" 1358 source = "registry+https://github.com/rust-lang/crates.io-index" 1359 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 1360 + dependencies = [ 1361 + "allocator-api2", 1362 + "equivalent", 1363 + "foldhash", 1364 + ] 1365 1366 [[package]] 1367 name = "hashbrown" ··· 1408 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1409 1410 [[package]] 1411 name = "hickory-proto" 1412 version = "0.24.4" 1413 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1472 "markup5ever", 1473 "proc-macro2", 1474 "quote", 1475 + "syn 2.0.113", 1476 ] 1477 1478 [[package]] ··· 1568 1569 [[package]] 1570 name = "hyper-util" 1571 + version = "0.1.19" 1572 source = "registry+https://github.com/rust-lang/crates.io-index" 1573 + checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" 1574 dependencies = [ 1575 "base64 0.22.1", 1576 "bytes", ··· 1604 "js-sys", 1605 "log", 1606 "wasm-bindgen", 1607 + "windows-core", 1608 ] 1609 1610 [[package]] ··· 1664 1665 [[package]] 1666 name = "icu_properties" 1667 + version = "2.1.2" 1668 source = "registry+https://github.com/rust-lang/crates.io-index" 1669 + checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 1670 dependencies = [ 1671 "icu_collections", 1672 "icu_locale_core", ··· 1678 1679 [[package]] 1680 name = "icu_properties_data" 1681 + version = "2.1.2" 1682 source = "registry+https://github.com/rust-lang/crates.io-index" 1683 + checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 1684 1685 [[package]] 1686 name = "icu_provider" ··· 1742 1743 [[package]] 1744 name = "indexmap" 1745 version = "2.12.1" 1746 source = "registry+https://github.com/rust-lang/crates.io-index" 1747 checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 1748 dependencies = [ 1749 "equivalent", 1750 "hashbrown 0.16.1", 1751 ] 1752 1753 [[package]] ··· 1761 "portable-atomic", 1762 "unicode-width 0.2.2", 1763 "web-time", 1764 ] 1765 1766 [[package]] ··· 1803 1804 [[package]] 1805 name = "iri-string" 1806 + version = "0.7.10" 1807 source = "registry+https://github.com/rust-lang/crates.io-index" 1808 + checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" 1809 dependencies = [ 1810 "memchr", 1811 "serde", ··· 1825 1826 [[package]] 1827 name = "itoa" 1828 + version = "1.0.17" 1829 source = "registry+https://github.com/rust-lang/crates.io-index" 1830 + checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 1831 1832 [[package]] 1833 name = "jacquard" 1834 + version = "0.9.5" 1835 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1836 dependencies = [ 1837 "bytes", 1838 "getrandom 0.2.16", ··· 1848 "regex", 1849 "regex-lite", 1850 "reqwest", 1851 "serde", 1852 "serde_html_form", 1853 "serde_json", ··· 1861 1862 [[package]] 1863 name = "jacquard-api" 1864 + version = "0.9.5" 1865 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1866 dependencies = [ 1867 "bon", 1868 "bytes", ··· 1880 1881 [[package]] 1882 name = "jacquard-common" 1883 + version = "0.9.5" 1884 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1885 dependencies = [ 1886 "base64 0.22.1", 1887 "bon", 1888 "bytes", 1889 "chrono", 1890 "ciborium", 1891 + "ciborium-io", 1892 "cid", 1893 "futures", 1894 "getrandom 0.2.16", 1895 "getrandom 0.3.4", 1896 + "hashbrown 0.15.5", 1897 "http", 1898 "ipld-core", 1899 "k256", 1900 + "maitake-sync", 1901 "miette", 1902 "multibase", 1903 "multihash", 1904 "n0-future 0.1.3", 1905 "ouroboros", 1906 + "oxilangtag", 1907 "p256", 1908 "postcard", 1909 "rand 0.9.2", 1910 "regex", 1911 + "regex-automata", 1912 "regex-lite", 1913 "reqwest", 1914 "serde", 1915 "serde_bytes", 1916 "serde_html_form", ··· 1918 "serde_json", 1919 "signature", 1920 "smol_str", 1921 + "spin 0.10.0", 1922 "thiserror 2.0.17", 1923 "tokio", 1924 "tokio-tungstenite-wasm", ··· 1929 1930 [[package]] 1931 name = "jacquard-derive" 1932 + version = "0.9.5" 1933 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1934 dependencies = [ 1935 "heck 0.5.0", 1936 "jacquard-lexicon", 1937 "proc-macro2", 1938 "quote", 1939 + "syn 2.0.113", 1940 ] 1941 1942 [[package]] 1943 name = "jacquard-identity" 1944 + version = "0.9.5" 1945 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1946 dependencies = [ 1947 "bon", 1948 "bytes", ··· 1952 "jacquard-common", 1953 "jacquard-lexicon", 1954 "miette", 1955 + "mini-moka-wasm", 1956 "n0-future 0.1.3", 1957 "percent-encoding", 1958 "reqwest", 1959 "serde", 1960 "serde_html_form", 1961 "serde_json", ··· 1968 1969 [[package]] 1970 name = "jacquard-lexicon" 1971 + version = "0.9.5" 1972 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1973 dependencies = [ 1974 "cid", 1975 "dashmap", ··· 1987 "serde_repr", 1988 "serde_with", 1989 "sha2", 1990 + "syn 2.0.113", 1991 "thiserror 2.0.17", 1992 "unicode-segmentation", 1993 ] 1994 1995 [[package]] 1996 name = "jacquard-oauth" 1997 + version = "0.9.6" 1998 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 1999 dependencies = [ 2000 "base64 0.22.1", 2001 "bytes", ··· 2010 "miette", 2011 "p256", 2012 "rand 0.8.5", 2013 "rouille", 2014 "serde", 2015 "serde_html_form", ··· 2083 2084 [[package]] 2085 name = "js-sys" 2086 + version = "0.3.83" 2087 source = "registry+https://github.com/rust-lang/crates.io-index" 2088 + checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" 2089 dependencies = [ 2090 "once_cell", 2091 "wasm-bindgen", ··· 2104 ] 2105 2106 [[package]] 2107 name = "lazy_static" 2108 version = "1.5.0" 2109 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2114 2115 [[package]] 2116 name = "libc" 2117 + version = "0.2.179" 2118 source = "registry+https://github.com/rust-lang/crates.io-index" 2119 + checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" 2120 2121 [[package]] 2122 name = "libm" ··· 2126 2127 [[package]] 2128 name = "libredox" 2129 + version = "0.1.12" 2130 source = "registry+https://github.com/rust-lang/crates.io-index" 2131 + checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" 2132 dependencies = [ 2133 "bitflags", 2134 "libc", 2135 + "redox_syscall 0.7.0", 2136 ] 2137 2138 [[package]] ··· 2164 2165 [[package]] 2166 name = "log" 2167 + version = "0.4.29" 2168 source = "registry+https://github.com/rust-lang/crates.io-index" 2169 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 2170 2171 [[package]] 2172 name = "loom" ··· 2203 checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 2204 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]] 2219 name = "markup5ever" 2220 version = "0.12.1" 2221 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2300 dependencies = [ 2301 "proc-macro2", 2302 "quote", 2303 + "syn 2.0.113", 2304 ] 2305 2306 [[package]] ··· 2320 ] 2321 2322 [[package]] 2323 + name = "mini-moka-wasm" 2324 version = "0.10.99" 2325 + source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b" 2326 dependencies = [ 2327 "crossbeam-channel", 2328 "crossbeam-utils", ··· 2334 ] 2335 2336 [[package]] 2337 name = "miniz_oxide" 2338 version = "0.8.9" 2339 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2345 2346 [[package]] 2347 name = "mio" 2348 + version = "1.1.1" 2349 source = "registry+https://github.com/rust-lang/crates.io-index" 2350 + checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" 2351 dependencies = [ 2352 "libc", 2353 "wasi", ··· 2396 ] 2397 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]] 2405 name = "n0-future" 2406 version = "0.1.3" 2407 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2454 version = "1.0.6" 2455 source = "registry+https://github.com/rust-lang/crates.io-index" 2456 checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 2457 2458 [[package]] 2459 name = "nu-ansi-term" ··· 2589 2590 [[package]] 2591 name = "openssl-probe" 2592 + version = "0.2.0" 2593 source = "registry+https://github.com/rust-lang/crates.io-index" 2594 + checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" 2595 2596 [[package]] 2597 name = "option-ext" ··· 2620 "proc-macro2", 2621 "proc-macro2-diagnostics", 2622 "quote", 2623 + "syn 2.0.113", 2624 ] 2625 2626 [[package]] ··· 2630 checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" 2631 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]] 2642 name = "p256" 2643 version = "0.13.2" 2644 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2684 dependencies = [ 2685 "cfg-if", 2686 "libc", 2687 + "redox_syscall 0.5.18", 2688 "smallvec", 2689 + "windows-link", 2690 ] 2691 2692 [[package]] ··· 2759 dependencies = [ 2760 "proc-macro2", 2761 "quote", 2762 + "syn 2.0.113", 2763 ] 2764 2765 [[package]] ··· 2797 2798 [[package]] 2799 name = "portable-atomic" 2800 + version = "1.13.0" 2801 source = "registry+https://github.com/rust-lang/crates.io-index" 2802 + checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" 2803 2804 [[package]] 2805 name = "postcard" ··· 2851 checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 2852 dependencies = [ 2853 "proc-macro2", 2854 + "syn 2.0.113", 2855 ] 2856 2857 [[package]] ··· 2864 ] 2865 2866 [[package]] 2867 name = "proc-macro2" 2868 + version = "1.0.105" 2869 source = "registry+https://github.com/rust-lang/crates.io-index" 2870 + checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" 2871 dependencies = [ 2872 "unicode-ident", 2873 ] ··· 2880 dependencies = [ 2881 "proc-macro2", 2882 "quote", 2883 + "syn 2.0.113", 2884 "version_check", 2885 "yansi", 2886 ] ··· 2948 2949 [[package]] 2950 name = "quote" 2951 + version = "1.0.43" 2952 source = "registry+https://github.com/rust-lang/crates.io-index" 2953 + checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" 2954 dependencies = [ 2955 "proc-macro2", 2956 ] ··· 3021 ] 3022 3023 [[package]] 3024 + name = "redox_syscall" 3025 + version = "0.5.18" 3026 source = "registry+https://github.com/rust-lang/crates.io-index" 3027 + checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 3028 + dependencies = [ 3029 + "bitflags", 3030 + ] 3031 3032 [[package]] 3033 name = "redox_syscall" 3034 + version = "0.7.0" 3035 source = "registry+https://github.com/rust-lang/crates.io-index" 3036 + checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" 3037 dependencies = [ 3038 "bitflags", 3039 ] ··· 3050 ] 3051 3052 [[package]] 3053 name = "regex" 3054 version = "1.12.2" 3055 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3086 3087 [[package]] 3088 name = "reqwest" 3089 + version = "0.12.28" 3090 source = "registry+https://github.com/rust-lang/crates.io-index" 3091 + checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" 3092 dependencies = [ 3093 "base64 0.22.1", 3094 "bytes", 3095 "encoding_rs", ··· 3184 3185 [[package]] 3186 name = "rsa" 3187 + version = "0.9.10" 3188 source = "registry+https://github.com/rust-lang/crates.io-index" 3189 + checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" 3190 dependencies = [ 3191 "const-oid", 3192 "digest", ··· 3225 3226 [[package]] 3227 name = "rustix" 3228 + version = "1.1.3" 3229 source = "registry+https://github.com/rust-lang/crates.io-index" 3230 + checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" 3231 dependencies = [ 3232 "bitflags", 3233 "errno", ··· 3238 3239 [[package]] 3240 name = "rustls" 3241 + version = "0.23.36" 3242 source = "registry+https://github.com/rust-lang/crates.io-index" 3243 + checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" 3244 dependencies = [ 3245 "once_cell", 3246 "ring", ··· 3252 3253 [[package]] 3254 name = "rustls-native-certs" 3255 + version = "0.8.3" 3256 source = "registry+https://github.com/rust-lang/crates.io-index" 3257 + checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" 3258 dependencies = [ 3259 "openssl-probe", 3260 "rustls-pki-types", ··· 3264 3265 [[package]] 3266 name = "rustls-pki-types" 3267 + version = "1.13.2" 3268 source = "registry+https://github.com/rust-lang/crates.io-index" 3269 + checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" 3270 dependencies = [ 3271 "web-time", 3272 "zeroize", ··· 3291 3292 [[package]] 3293 name = "ryu" 3294 + version = "1.0.22" 3295 source = "registry+https://github.com/rust-lang/crates.io-index" 3296 + checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" 3297 3298 [[package]] 3299 name = "safemem" ··· 3320 ] 3321 3322 [[package]] 3323 name = "scoped-tls" 3324 version = "1.0.1" 3325 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3417 dependencies = [ 3418 "proc-macro2", 3419 "quote", 3420 + "syn 2.0.113", 3421 ] 3422 3423 [[package]] 3424 name = "serde_html_form" 3425 + version = "0.3.2" 3426 source = "registry+https://github.com/rust-lang/crates.io-index" 3427 + checksum = "2acf96b1d9364968fce46ebb548f1c0e1d7eceae27bdff73865d42e6c7369d94" 3428 dependencies = [ 3429 "form_urlencoded", 3430 + "indexmap", 3431 "itoa", 3432 "serde_core", 3433 ] 3434 ··· 3446 3447 [[package]] 3448 name = "serde_json" 3449 + version = "1.0.149" 3450 source = "registry+https://github.com/rust-lang/crates.io-index" 3451 + checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" 3452 dependencies = [ 3453 "itoa", 3454 "memchr", 3455 "serde", 3456 "serde_core", 3457 + "zmij", 3458 ] 3459 3460 [[package]] ··· 3476 dependencies = [ 3477 "proc-macro2", 3478 "quote", 3479 + "syn 2.0.113", 3480 ] 3481 3482 [[package]] ··· 3493 3494 [[package]] 3495 name = "serde_with" 3496 + version = "3.16.1" 3497 source = "registry+https://github.com/rust-lang/crates.io-index" 3498 + checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" 3499 dependencies = [ 3500 "base64 0.22.1", 3501 "chrono", 3502 "hex", 3503 "serde_core", 3504 "serde_json", 3505 "serde_with_macros", ··· 3508 3509 [[package]] 3510 name = "serde_with_macros" 3511 + version = "3.16.1" 3512 source = "registry+https://github.com/rust-lang/crates.io-index" 3513 + checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" 3514 dependencies = [ 3515 "darling", 3516 "proc-macro2", 3517 "quote", 3518 + "syn 2.0.113", 3519 ] 3520 3521 [[package]] ··· 3572 3573 [[package]] 3574 name = "signal-hook-registry" 3575 + version = "1.4.8" 3576 source = "registry+https://github.com/rust-lang/crates.io-index" 3577 + checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" 3578 dependencies = [ 3579 + "errno", 3580 "libc", 3581 ] 3582 ··· 3592 3593 [[package]] 3594 name = "simd-adler32" 3595 + version = "0.3.8" 3596 source = "registry+https://github.com/rust-lang/crates.io-index" 3597 + checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" 3598 3599 [[package]] 3600 name = "siphasher" ··· 3676 checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 3677 3678 [[package]] 3679 name = "static_assertions" 3680 version = "1.1.0" 3681 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3729 3730 [[package]] 3731 name = "supports-hyperlinks" 3732 + version = "3.2.0" 3733 source = "registry+https://github.com/rust-lang/crates.io-index" 3734 + checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" 3735 3736 [[package]] 3737 name = "supports-unicode" ··· 3752 3753 [[package]] 3754 name = "syn" 3755 + version = "2.0.113" 3756 source = "registry+https://github.com/rust-lang/crates.io-index" 3757 + checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4" 3758 dependencies = [ 3759 "proc-macro2", 3760 "quote", ··· 3778 dependencies = [ 3779 "proc-macro2", 3780 "quote", 3781 + "syn 2.0.113", 3782 ] 3783 3784 [[package]] ··· 3810 3811 [[package]] 3812 name = "tempfile" 3813 + version = "3.24.0" 3814 source = "registry+https://github.com/rust-lang/crates.io-index" 3815 + checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" 3816 dependencies = [ 3817 "fastrand", 3818 "getrandom 0.3.4", ··· 3878 dependencies = [ 3879 "proc-macro2", 3880 "quote", 3881 + "syn 2.0.113", 3882 ] 3883 3884 [[package]] ··· 3889 dependencies = [ 3890 "proc-macro2", 3891 "quote", 3892 + "syn 2.0.113", 3893 ] 3894 3895 [[package]] ··· 3917 checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" 3918 dependencies = [ 3919 "deranged", 3920 "libc", 3921 "num-conv", 3922 "num_threads", 3923 "powerfmt", 3924 "serde", 3925 "time-core", 3926 ] 3927 3928 [[package]] ··· 3932 checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" 3933 3934 [[package]] 3935 name = "tiny_http" 3936 version = "0.12.0" 3937 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3970 3971 [[package]] 3972 name = "tokio" 3973 + version = "1.49.0" 3974 source = "registry+https://github.com/rust-lang/crates.io-index" 3975 + checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" 3976 dependencies = [ 3977 "bytes", 3978 "libc", ··· 3993 dependencies = [ 3994 "proc-macro2", 3995 "quote", 3996 + "syn 2.0.113", 3997 ] 3998 3999 [[package]] ··· 4043 4044 [[package]] 4045 name = "tokio-util" 4046 + version = "0.7.18" 4047 source = "registry+https://github.com/rust-lang/crates.io-index" 4048 + checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" 4049 dependencies = [ 4050 "bytes", 4051 "futures-core", ··· 4073 4074 [[package]] 4075 name = "tower-http" 4076 + version = "0.6.8" 4077 source = "registry+https://github.com/rust-lang/crates.io-index" 4078 + checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" 4079 dependencies = [ 4080 "async-compression", 4081 "bitflags", ··· 4114 4115 [[package]] 4116 name = "tracing" 4117 + version = "0.1.44" 4118 source = "registry+https://github.com/rust-lang/crates.io-index" 4119 + checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 4120 dependencies = [ 4121 "log", 4122 "pin-project-lite", ··· 4126 4127 [[package]] 4128 name = "tracing-attributes" 4129 + version = "0.1.31" 4130 source = "registry+https://github.com/rust-lang/crates.io-index" 4131 + checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" 4132 dependencies = [ 4133 "proc-macro2", 4134 "quote", 4135 + "syn 2.0.113", 4136 ] 4137 4138 [[package]] 4139 name = "tracing-core" 4140 + version = "0.1.36" 4141 source = "registry+https://github.com/rust-lang/crates.io-index" 4142 + checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" 4143 dependencies = [ 4144 "once_cell", 4145 "valuable", ··· 4158 4159 [[package]] 4160 name = "tracing-subscriber" 4161 + version = "0.3.22" 4162 source = "registry+https://github.com/rust-lang/crates.io-index" 4163 + checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" 4164 dependencies = [ 4165 "matchers", 4166 "nu-ansi-term", ··· 4182 dependencies = [ 4183 "proc-macro2", 4184 "quote", 4185 + "syn 2.0.113", 4186 ] 4187 4188 [[package]] ··· 4234 4235 [[package]] 4236 name = "unicase" 4237 + version = "2.9.0" 4238 source = "registry+https://github.com/rust-lang/crates.io-index" 4239 + checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" 4240 4241 [[package]] 4242 name = "unicode-ident" ··· 4288 4289 [[package]] 4290 name = "url" 4291 + version = "2.5.8" 4292 source = "registry+https://github.com/rust-lang/crates.io-index" 4293 + checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" 4294 dependencies = [ 4295 "form_urlencoded", 4296 "idna", 4297 "percent-encoding", 4298 "serde", 4299 + "serde_derive", 4300 ] 4301 4302 [[package]] ··· 4371 4372 [[package]] 4373 name = "wasm-bindgen" 4374 + version = "0.2.106" 4375 source = "registry+https://github.com/rust-lang/crates.io-index" 4376 + checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 4377 dependencies = [ 4378 "cfg-if", 4379 "once_cell", ··· 4384 4385 [[package]] 4386 name = "wasm-bindgen-futures" 4387 + version = "0.4.56" 4388 source = "registry+https://github.com/rust-lang/crates.io-index" 4389 + checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" 4390 dependencies = [ 4391 "cfg-if", 4392 "js-sys", ··· 4397 4398 [[package]] 4399 name = "wasm-bindgen-macro" 4400 + version = "0.2.106" 4401 source = "registry+https://github.com/rust-lang/crates.io-index" 4402 + checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" 4403 dependencies = [ 4404 "quote", 4405 "wasm-bindgen-macro-support", ··· 4407 4408 [[package]] 4409 name = "wasm-bindgen-macro-support" 4410 + version = "0.2.106" 4411 source = "registry+https://github.com/rust-lang/crates.io-index" 4412 + checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" 4413 dependencies = [ 4414 "bumpalo", 4415 "proc-macro2", 4416 "quote", 4417 + "syn 2.0.113", 4418 "wasm-bindgen-shared", 4419 ] 4420 4421 [[package]] 4422 name = "wasm-bindgen-shared" 4423 + version = "0.2.106" 4424 source = "registry+https://github.com/rust-lang/crates.io-index" 4425 + checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" 4426 dependencies = [ 4427 "unicode-ident", 4428 ] ··· 4442 4443 [[package]] 4444 name = "web-sys" 4445 + version = "0.3.83" 4446 source = "registry+https://github.com/rust-lang/crates.io-index" 4447 + checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" 4448 dependencies = [ 4449 "js-sys", 4450 "wasm-bindgen", ··· 4490 4491 [[package]] 4492 name = "webpki-roots" 4493 + version = "1.0.5" 4494 source = "registry+https://github.com/rust-lang/crates.io-index" 4495 + checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" 4496 dependencies = [ 4497 "rustls-pki-types", 4498 ] ··· 4513 ] 4514 4515 [[package]] 4516 name = "windows-core" 4517 version = "0.62.2" 4518 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4520 dependencies = [ 4521 "windows-implement", 4522 "windows-interface", 4523 + "windows-link", 4524 + "windows-result", 4525 + "windows-strings", 4526 ] 4527 4528 [[package]] ··· 4533 dependencies = [ 4534 "proc-macro2", 4535 "quote", 4536 + "syn 2.0.113", 4537 ] 4538 4539 [[package]] ··· 4544 dependencies = [ 4545 "proc-macro2", 4546 "quote", 4547 + "syn 2.0.113", 4548 ] 4549 4550 [[package]] 4551 name = "windows-link" 4552 version = "0.2.1" 4553 source = "registry+https://github.com/rust-lang/crates.io-index" 4554 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 4555 4556 [[package]] 4557 name = "windows-registry" 4558 version = "0.6.1" 4559 source = "registry+https://github.com/rust-lang/crates.io-index" 4560 checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 4561 dependencies = [ 4562 + "windows-link", 4563 + "windows-result", 4564 + "windows-strings", 4565 ] 4566 4567 [[package]] ··· 4570 source = "registry+https://github.com/rust-lang/crates.io-index" 4571 checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 4572 dependencies = [ 4573 + "windows-link", 4574 ] 4575 4576 [[package]] ··· 4579 source = "registry+https://github.com/rust-lang/crates.io-index" 4580 checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 4581 dependencies = [ 4582 + "windows-link", 4583 ] 4584 4585 [[package]] ··· 4633 source = "registry+https://github.com/rust-lang/crates.io-index" 4634 checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 4635 dependencies = [ 4636 + "windows-link", 4637 ] 4638 4639 [[package]] ··· 4688 source = "registry+https://github.com/rust-lang/crates.io-index" 4689 checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 4690 dependencies = [ 4691 + "windows-link", 4692 "windows_aarch64_gnullvm 0.53.1", 4693 "windows_aarch64_msvc 0.53.1", 4694 "windows_i686_gnu 0.53.1", ··· 4697 "windows_x86_64_gnu 0.53.1", 4698 "windows_x86_64_gnullvm 0.53.1", 4699 "windows_x86_64_msvc 0.53.1", 4700 ] 4701 4702 [[package]] ··· 4927 "tower-http", 4928 "url", 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", 4942 ] 4943 4944 [[package]] ··· 4989 dependencies = [ 4990 "proc-macro2", 4991 "quote", 4992 + "syn 2.0.113", 4993 "synstructure", 4994 ] 4995 4996 [[package]] 4997 name = "zerocopy" 4998 + version = "0.8.32" 4999 source = "registry+https://github.com/rust-lang/crates.io-index" 5000 + checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56" 5001 dependencies = [ 5002 "zerocopy-derive", 5003 ] 5004 5005 [[package]] 5006 name = "zerocopy-derive" 5007 + version = "0.8.32" 5008 source = "registry+https://github.com/rust-lang/crates.io-index" 5009 + checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90" 5010 dependencies = [ 5011 "proc-macro2", 5012 "quote", 5013 + "syn 2.0.113", 5014 ] 5015 5016 [[package]] ··· 5030 dependencies = [ 5031 "proc-macro2", 5032 "quote", 5033 + "syn 2.0.113", 5034 "synstructure", 5035 ] 5036 ··· 5073 dependencies = [ 5074 "proc-macro2", 5075 "quote", 5076 + "syn 2.0.113", 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 place_wisp = [] 9 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" } 18 #jacquard = { path = "../../jacquard/crates/jacquard", features = ["loopback"] } 19 #jacquard-oauth = { path = "../../jacquard/crates/jacquard-oauth" } 20 #jacquard-api = { path = "../../jacquard/crates/jacquard-api", features = ["streaming"] }
··· 8 place_wisp = [] 9 10 [dependencies] 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" } 19 #jacquard = { path = "../../jacquard/crates/jacquard", features = ["loopback"] } 20 #jacquard-oauth = { path = "../../jacquard/crates/jacquard-oauth" } 21 #jacquard-api = { path = "../../jacquard/crates/jacquard-api", features = ["streaming"] }
+72 -2
cli/README.md
··· 32 33 ## Usage 34 35 ### Basic Deployment 36 37 Deploy the current directory: 38 39 ```bash 40 - wisp-cli nekomimi.ppet --path . --site my-site 41 ``` 42 43 Deploy a specific directory: ··· 46 wisp-cli alice.bsky.social --path ./dist/ --site my-site 47 ``` 48 49 ### Authentication Methods 50 51 #### OAuth (Recommended) ··· 79 80 ## Command-Line Options 81 82 ``` 83 - wisp-cli [OPTIONS] <INPUT> 84 85 Arguments: 86 <INPUT> Handle (e.g., alice.bsky.social), DID, or PDS URL ··· 90 -s, --site <SITE> Site name (defaults to directory name) 91 --store <STORE> Path to auth store file (only used with OAuth) [default: /tmp/wisp-oauth-session.json] 92 --password <PASSWORD> App Password for authentication (alternative to OAuth) 93 -h, --help Print help 94 -V, --version Print version 95 ``` 96 97 ## How It Works
··· 32 33 ## Usage 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 + 42 ### Basic Deployment 43 44 Deploy the current directory: 45 46 ```bash 47 + wisp-cli nekomimi.pet --path . --site my-site 48 ``` 49 50 Deploy a specific directory: ··· 53 wisp-cli alice.bsky.social --path ./dist/ --site my-site 54 ``` 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 + 85 ### Authentication Methods 86 87 #### OAuth (Recommended) ··· 115 116 ## Command-Line Options 117 118 + ### Deploy Command 119 + 120 ``` 121 + wisp-cli [deploy] [OPTIONS] <INPUT> 122 123 Arguments: 124 <INPUT> Handle (e.g., alice.bsky.social), DID, or PDS URL ··· 128 -s, --site <SITE> Site name (defaults to directory name) 129 --store <STORE> Path to auth store file (only used with OAuth) [default: /tmp/wisp-oauth-session.json] 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) 134 -h, --help Print help 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 165 ``` 166 167 ## How It Works
+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
···
··· 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
···
··· 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
···
··· 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
···
··· 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
···
··· 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
···
··· 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 + pub mod fs; 7 + pub mod settings; 8 + pub mod subfs;
+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
···
··· 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
···
··· 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
··· 2 use jacquard_common::IntoStatic; 3 use std::collections::HashMap; 4 5 - use crate::place_wisp::fs::{Directory, EntryNode}; 6 7 /// Extract blob information from a directory tree 8 /// Returns a map of file paths to their blob refs and CIDs
··· 2 use jacquard_common::IntoStatic; 3 use std::collections::HashMap; 4 5 + use wisp_lexicons::place_wisp::fs::{Directory, EntryNode}; 6 7 /// Extract blob information from a directory tree 8 /// Returns a map of file paths to their blob refs and CIDs
-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
··· 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 - pub mod builder_types; 7 - 8 - #[cfg(feature = "place_wisp")] 9 - pub mod place_wisp;
···
+28 -31
cli/src/main.rs
··· 1 - mod builder_types; 2 - mod place_wisp; 3 mod cid; 4 mod blob_map; 5 mod metadata; ··· 28 use futures::stream::{self, StreamExt}; 29 use indicatif::{ProgressBar, ProgressStyle, MultiProgress}; 30 31 - use place_wisp::fs::*; 32 - use place_wisp::settings::*; 33 34 /// Maximum number of concurrent file uploads to the PDS 35 const MAX_CONCURRENT_UPLOADS: usize = 2; ··· 43 struct Args { 44 #[command(subcommand)] 45 command: Option<Commands>, 46 - 47 // Deploy arguments (when no subcommand is specified) 48 /// Handle (e.g., alice.bsky.social), DID, or PDS URL 49 - #[arg(global = true, conflicts_with = "command")] 50 input: Option<CowStr<'static>>, 51 52 /// Path to the directory containing your static site 53 - #[arg(short, long, global = true, conflicts_with = "command")] 54 path: Option<PathBuf>, 55 56 /// Site name (defaults to directory name) 57 - #[arg(short, long, global = true, conflicts_with = "command")] 58 site: Option<String>, 59 60 /// Path to auth store file 61 - #[arg(long, global = true, conflicts_with = "command")] 62 store: Option<String>, 63 64 /// App Password for authentication 65 - #[arg(long, global = true, conflicts_with = "command")] 66 password: Option<CowStr<'static>>, 67 68 /// Enable directory listing mode for paths without index files 69 - #[arg(long, global = true, conflicts_with = "command")] 70 directory: bool, 71 72 /// Enable SPA mode (serve index.html for all routes) 73 - #[arg(long, global = true, conflicts_with = "command")] 74 spa: bool, 75 76 /// Skip confirmation prompts (automatically accept warnings) 77 - #[arg(short = 'y', long, global = true, conflicts_with = "command")] 78 yes: bool, 79 } 80 ··· 124 125 /// Output directory for the downloaded site 126 #[arg(short, long, default_value = ".")] 127 - output: PathBuf, 128 }, 129 /// Serve a site locally with real-time firehose updates 130 Serve { ··· 137 138 /// Output directory for the site files 139 #[arg(short, long, default_value = ".")] 140 - output: PathBuf, 141 142 /// Port to serve on 143 - #[arg(short, long, default_value = "8080")] 144 port: u16, 145 }, 146 } ··· 158 run_with_oauth(input, store, path, site, directory, spa, yes).await 159 } 160 } 161 - Some(Commands::Pull { input, site, output }) => { 162 - pull::pull_site(input, CowStr::from(site), output).await 163 } 164 - Some(Commands::Serve { input, site, output, port }) => { 165 - serve::serve_site(input, CowStr::from(site), output, port).await 166 } 167 None => { 168 // Legacy mode: if input is provided, assume deploy command ··· 512 let chunk_file_count = subfs_utils::count_files_in_directory(chunk); 513 let chunk_size = subfs_utils::estimate_directory_size(chunk); 514 515 - let chunk_manifest = crate::place_wisp::subfs::SubfsRecord::new() 516 .root(convert_fs_dir_to_subfs_dir(chunk.clone())) 517 .file_count(Some(chunk_file_count as i64)) 518 .created_at(Datetime::now()) ··· 535 // Each chunk reference MUST have flat: true to merge chunk contents 536 println!(" โ†’ Creating parent subfs with {} chunk references...", chunk_uris.len()); 537 use jacquard_common::CowStr; 538 - use crate::place_wisp::fs::{Subfs}; 539 540 // Convert to fs::Subfs (which has the 'flat' field) instead of subfs::Subfs 541 let parent_entries_fs: Vec<Entry> = chunk_uris.iter().enumerate().map(|(i, (uri, _))| { ··· 565 let parent_tid = Tid::now_0(); 566 let parent_rkey = parent_tid.to_string(); 567 568 - let parent_manifest = crate::place_wisp::subfs::SubfsRecord::new() 569 .root(parent_root_subfs) 570 .file_count(Some(largest_dir.file_count as i64)) 571 .created_at(Datetime::now()) ··· 584 let subfs_tid = Tid::now_0(); 585 let subfs_rkey = subfs_tid.to_string(); 586 587 - let subfs_manifest = crate::place_wisp::subfs::SubfsRecord::new() 588 .root(convert_fs_dir_to_subfs_dir(largest_dir.directory.clone())) 589 .file_count(Some(largest_dir.file_count as i64)) 590 .created_at(Datetime::now()) ··· 952 953 /// Convert fs::Directory to subfs::Directory 954 /// 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}; 957 958 let subfs_entries: Vec<SubfsEntry> = fs_dir.entries.into_iter().map(|entry| { 959 let node = match entry.node { 960 - place_wisp::fs::EntryNode::File(file) => { 961 SubfsEntryNode::File(Box::new(SubfsFile::new() 962 .r#type(file.r#type) 963 .blob(file.blob) ··· 966 .base64(file.base64) 967 .build())) 968 } 969 - place_wisp::fs::EntryNode::Directory(dir) => { 970 SubfsEntryNode::Directory(Box::new(convert_fs_dir_to_subfs_dir(*dir))) 971 } 972 - place_wisp::fs::EntryNode::Subfs(subfs) => { 973 // Nested subfs in the directory we're converting 974 // 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() 976 .r#type(subfs.r#type) 977 .subject(subfs.subject) 978 .build())) 979 } 980 - place_wisp::fs::EntryNode::Unknown(unknown) => { 981 SubfsEntryNode::Unknown(unknown) 982 } 983 };
··· 1 mod cid; 2 mod blob_map; 3 mod metadata; ··· 26 use futures::stream::{self, StreamExt}; 27 use indicatif::{ProgressBar, ProgressStyle, MultiProgress}; 28 29 + use wisp_lexicons::place_wisp::fs::*; 30 + use wisp_lexicons::place_wisp::settings::*; 31 32 /// Maximum number of concurrent file uploads to the PDS 33 const MAX_CONCURRENT_UPLOADS: usize = 2; ··· 41 struct Args { 42 #[command(subcommand)] 43 command: Option<Commands>, 44 + 45 // Deploy arguments (when no subcommand is specified) 46 /// Handle (e.g., alice.bsky.social), DID, or PDS URL 47 input: Option<CowStr<'static>>, 48 49 /// Path to the directory containing your static site 50 + #[arg(short, long)] 51 path: Option<PathBuf>, 52 53 /// Site name (defaults to directory name) 54 + #[arg(short, long)] 55 site: Option<String>, 56 57 /// Path to auth store file 58 + #[arg(long)] 59 store: Option<String>, 60 61 /// App Password for authentication 62 + #[arg(long)] 63 password: Option<CowStr<'static>>, 64 65 /// Enable directory listing mode for paths without index files 66 + #[arg(long)] 67 directory: bool, 68 69 /// Enable SPA mode (serve index.html for all routes) 70 + #[arg(long)] 71 spa: bool, 72 73 /// Skip confirmation prompts (automatically accept warnings) 74 + #[arg(short = 'y', long)] 75 yes: bool, 76 } 77 ··· 121 122 /// Output directory for the downloaded site 123 #[arg(short, long, default_value = ".")] 124 + path: PathBuf, 125 }, 126 /// Serve a site locally with real-time firehose updates 127 Serve { ··· 134 135 /// Output directory for the site files 136 #[arg(short, long, default_value = ".")] 137 + path: PathBuf, 138 139 /// Port to serve on 140 + #[arg(short = 'P', long, default_value = "8080")] 141 port: u16, 142 }, 143 } ··· 155 run_with_oauth(input, store, path, site, directory, spa, yes).await 156 } 157 } 158 + Some(Commands::Pull { input, site, path }) => { 159 + pull::pull_site(input, CowStr::from(site), path).await 160 } 161 + Some(Commands::Serve { input, site, path, port }) => { 162 + serve::serve_site(input, CowStr::from(site), path, port).await 163 } 164 None => { 165 // Legacy mode: if input is provided, assume deploy command ··· 509 let chunk_file_count = subfs_utils::count_files_in_directory(chunk); 510 let chunk_size = subfs_utils::estimate_directory_size(chunk); 511 512 + let chunk_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new() 513 .root(convert_fs_dir_to_subfs_dir(chunk.clone())) 514 .file_count(Some(chunk_file_count as i64)) 515 .created_at(Datetime::now()) ··· 532 // Each chunk reference MUST have flat: true to merge chunk contents 533 println!(" โ†’ Creating parent subfs with {} chunk references...", chunk_uris.len()); 534 use jacquard_common::CowStr; 535 + use wisp_lexicons::place_wisp::fs::{Subfs}; 536 537 // Convert to fs::Subfs (which has the 'flat' field) instead of subfs::Subfs 538 let parent_entries_fs: Vec<Entry> = chunk_uris.iter().enumerate().map(|(i, (uri, _))| { ··· 562 let parent_tid = Tid::now_0(); 563 let parent_rkey = parent_tid.to_string(); 564 565 + let parent_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new() 566 .root(parent_root_subfs) 567 .file_count(Some(largest_dir.file_count as i64)) 568 .created_at(Datetime::now()) ··· 581 let subfs_tid = Tid::now_0(); 582 let subfs_rkey = subfs_tid.to_string(); 583 584 + let subfs_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new() 585 .root(convert_fs_dir_to_subfs_dir(largest_dir.directory.clone())) 586 .file_count(Some(largest_dir.file_count as i64)) 587 .created_at(Datetime::now()) ··· 949 950 /// Convert fs::Directory to subfs::Directory 951 /// They have the same structure, but different types 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}; 954 955 let subfs_entries: Vec<SubfsEntry> = fs_dir.entries.into_iter().map(|entry| { 956 let node = match entry.node { 957 + wisp_lexicons::place_wisp::fs::EntryNode::File(file) => { 958 SubfsEntryNode::File(Box::new(SubfsFile::new() 959 .r#type(file.r#type) 960 .blob(file.blob) ··· 963 .base64(file.base64) 964 .build())) 965 } 966 + wisp_lexicons::place_wisp::fs::EntryNode::Directory(dir) => { 967 SubfsEntryNode::Directory(Box::new(convert_fs_dir_to_subfs_dir(*dir))) 968 } 969 + wisp_lexicons::place_wisp::fs::EntryNode::Subfs(subfs) => { 970 // Nested subfs in the directory we're converting 971 // Note: subfs::Subfs doesn't have the 'flat' field - that's only in fs::Subfs 972 + SubfsEntryNode::Subfs(Box::new(wisp_lexicons::place_wisp::subfs::Subfs::new() 973 .r#type(subfs.r#type) 974 .subject(subfs.subject) 975 .build())) 976 } 977 + wisp_lexicons::place_wisp::fs::EntryNode::Unknown(unknown) => { 978 SubfsEntryNode::Unknown(unknown) 979 } 980 };
-9
cli/src/mod.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 - pub mod builder_types; 7 - 8 - #[cfg(feature = "place_wisp")] 9 - pub mod place_wisp;
···
-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
··· 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
··· 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
··· 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 - pub mod fs; 7 - pub mod settings; 8 - pub mod subfs;
···
+12 -12
cli/src/pull.rs
··· 1 use crate::blob_map; 2 use crate::download; 3 use crate::metadata::SiteMetadata; 4 - use crate::place_wisp::fs::*; 5 use crate::subfs_utils; 6 use jacquard::CowStr; 7 use jacquard::prelude::IdentityResolver; ··· 410 ) -> miette::Result<Directory<'static>> { 411 use jacquard_common::IntoStatic; 412 use jacquard_common::types::value::from_data; 413 - use crate::place_wisp::subfs::SubfsRecord; 414 415 - let mut all_subfs_map: HashMap<String, crate::place_wisp::subfs::Directory> = HashMap::new(); 416 let mut to_fetch = subfs_utils::extract_subfs_uris(directory, String::new()); 417 418 if to_fetch.is_empty() { ··· 516 517 /// Extract subfs URIs from a subfs::Directory (helper for pull) 518 fn extract_subfs_uris_from_subfs_dir( 519 - directory: &crate::place_wisp::subfs::Directory, 520 current_path: String, 521 ) -> Vec<(String, String)> { 522 let mut uris = Vec::new(); ··· 529 }; 530 531 match &entry.node { 532 - crate::place_wisp::subfs::EntryNode::Subfs(subfs_node) => { 533 uris.push((subfs_node.subject.to_string(), full_path.clone())); 534 } 535 - crate::place_wisp::subfs::EntryNode::Directory(subdir) => { 536 let nested = extract_subfs_uris_from_subfs_dir(subdir, full_path); 537 uris.extend(nested); 538 } ··· 546 /// Recursively replace subfs nodes with their actual content 547 fn replace_subfs_with_content( 548 directory: Directory, 549 - subfs_map: &HashMap<String, crate::place_wisp::subfs::Directory>, 550 current_path: String, 551 ) -> Directory<'static> { 552 use jacquard_common::IntoStatic; ··· 628 } 629 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> { 632 use jacquard_common::IntoStatic; 633 634 let node = match subfs_entry.node { 635 - crate::place_wisp::subfs::EntryNode::File(file) => { 636 EntryNode::File(Box::new( 637 File::new() 638 .r#type(file.r#type.into_static()) ··· 643 .build() 644 )) 645 } 646 - crate::place_wisp::subfs::EntryNode::Directory(dir) => { 647 let converted_entries: Vec<Entry<'static>> = dir 648 .entries 649 .into_iter() ··· 657 .build() 658 )) 659 } 660 - crate::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => { 661 // Nested subfs should have been expanded already - if we get here, it means expansion failed 662 // Treat it like a directory reference that should have been expanded 663 eprintln!(" โš ๏ธ Warning: unexpanded nested subfs at path, treating as empty directory"); ··· 668 .build() 669 )) 670 } 671 - crate::place_wisp::subfs::EntryNode::Unknown(unknown) => { 672 EntryNode::Unknown(unknown) 673 } 674 };
··· 1 use crate::blob_map; 2 use crate::download; 3 use crate::metadata::SiteMetadata; 4 + use wisp_lexicons::place_wisp::fs::*; 5 use crate::subfs_utils; 6 use jacquard::CowStr; 7 use jacquard::prelude::IdentityResolver; ··· 410 ) -> miette::Result<Directory<'static>> { 411 use jacquard_common::IntoStatic; 412 use jacquard_common::types::value::from_data; 413 + use wisp_lexicons::place_wisp::subfs::SubfsRecord; 414 415 + let mut all_subfs_map: HashMap<String, wisp_lexicons::place_wisp::subfs::Directory> = HashMap::new(); 416 let mut to_fetch = subfs_utils::extract_subfs_uris(directory, String::new()); 417 418 if to_fetch.is_empty() { ··· 516 517 /// Extract subfs URIs from a subfs::Directory (helper for pull) 518 fn extract_subfs_uris_from_subfs_dir( 519 + directory: &wisp_lexicons::place_wisp::subfs::Directory, 520 current_path: String, 521 ) -> Vec<(String, String)> { 522 let mut uris = Vec::new(); ··· 529 }; 530 531 match &entry.node { 532 + wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(subfs_node) => { 533 uris.push((subfs_node.subject.to_string(), full_path.clone())); 534 } 535 + wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => { 536 let nested = extract_subfs_uris_from_subfs_dir(subdir, full_path); 537 uris.extend(nested); 538 } ··· 546 /// Recursively replace subfs nodes with their actual content 547 fn replace_subfs_with_content( 548 directory: Directory, 549 + subfs_map: &HashMap<String, wisp_lexicons::place_wisp::subfs::Directory>, 550 current_path: String, 551 ) -> Directory<'static> { 552 use jacquard_common::IntoStatic; ··· 628 } 629 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: wisp_lexicons::place_wisp::subfs::Entry<'static>) -> Entry<'static> { 632 use jacquard_common::IntoStatic; 633 634 let node = match subfs_entry.node { 635 + wisp_lexicons::place_wisp::subfs::EntryNode::File(file) => { 636 EntryNode::File(Box::new( 637 File::new() 638 .r#type(file.r#type.into_static()) ··· 643 .build() 644 )) 645 } 646 + wisp_lexicons::place_wisp::subfs::EntryNode::Directory(dir) => { 647 let converted_entries: Vec<Entry<'static>> = dir 648 .entries 649 .into_iter() ··· 657 .build() 658 )) 659 } 660 + wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => { 661 // Nested subfs should have been expanded already - if we get here, it means expansion failed 662 // Treat it like a directory reference that should have been expanded 663 eprintln!(" โš ๏ธ Warning: unexpanded nested subfs at path, treating as empty directory"); ··· 668 .build() 669 )) 670 } 671 + wisp_lexicons::place_wisp::subfs::EntryNode::Unknown(unknown) => { 672 EntryNode::Unknown(unknown) 673 } 674 };
+1 -1
cli/src/serve.rs
··· 1 use crate::pull::pull_site; 2 use crate::redirects::{load_redirect_rules, match_redirect_rule, RedirectRule}; 3 - use crate::place_wisp::settings::Settings; 4 use axum::{ 5 Router, 6 extract::Request,
··· 1 use crate::pull::pull_site; 2 use crate::redirects::{load_redirect_rules, match_redirect_rule, RedirectRule}; 3 + use wisp_lexicons::place_wisp::settings::Settings; 4 use axum::{ 5 Router, 6 extract::Request,
+14 -14
cli/src/subfs_utils.rs
··· 6 use miette::IntoDiagnostic; 7 use std::collections::HashMap; 8 9 - use crate::place_wisp::fs::{Directory as FsDirectory, EntryNode as FsEntryNode}; 10 - use crate::place_wisp::subfs::SubfsRecord; 11 12 /// Extract all subfs URIs from a directory tree with their mount paths 13 pub fn extract_subfs_uris(directory: &FsDirectory, current_path: String) -> Vec<(String, String)> { ··· 145 146 /// Extract subfs URIs from a subfs::Directory 147 fn extract_subfs_uris_from_subfs_dir( 148 - directory: &crate::place_wisp::subfs::Directory, 149 current_path: String, 150 ) -> Vec<(String, String)> { 151 let mut uris = Vec::new(); 152 153 for entry in &directory.entries { 154 match &entry.node { 155 - crate::place_wisp::subfs::EntryNode::Subfs(subfs_node) => { 156 // Check if this is a chunk entry (chunk0, chunk1, etc.) 157 // Chunks should be flat-merged, so use the parent's path 158 let mount_path = if entry.name.starts_with("chunk") && ··· 171 172 uris.push((subfs_node.subject.to_string(), mount_path)); 173 } 174 - crate::place_wisp::subfs::EntryNode::Directory(subdir) => { 175 let full_path = if current_path.is_empty() { 176 entry.name.to_string() 177 } else { ··· 204 for (mount_path, subfs_record) in all_subfs { 205 // Check if this record only contains chunk subfs references (no files) 206 let only_has_chunks = subfs_record.root.entries.iter().all(|e| { 207 - matches!(&e.node, crate::place_wisp::subfs::EntryNode::Subfs(_)) && 208 e.name.starts_with("chunk") && 209 e.name.chars().skip(5).all(|c| c.is_ascii_digit()) 210 }); ··· 232 /// Extract blobs from a subfs directory (works with subfs::Directory) 233 /// Returns a map of file paths to their blob refs and CIDs 234 fn extract_subfs_blobs( 235 - directory: &crate::place_wisp::subfs::Directory, 236 current_path: String, 237 ) -> HashMap<String, (BlobRef<'static>, String)> { 238 let mut blob_map = HashMap::new(); ··· 245 }; 246 247 match &entry.node { 248 - crate::place_wisp::subfs::EntryNode::File(file_node) => { 249 let blob_ref = &file_node.blob; 250 let cid_string = blob_ref.blob().r#ref.to_string(); 251 blob_map.insert( ··· 253 (blob_ref.clone().into_static(), cid_string) 254 ); 255 } 256 - crate::place_wisp::subfs::EntryNode::Directory(subdir) => { 257 let sub_map = extract_subfs_blobs(subdir, full_path); 258 blob_map.extend(sub_map); 259 } 260 - crate::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => { 261 // Nested subfs - these should be resolved recursively in the main flow 262 // For now, we skip them (they'll be fetched separately) 263 eprintln!(" โš ๏ธ Found nested subfs at {}, skipping (should be fetched separately)", full_path); 264 } 265 - crate::place_wisp::subfs::EntryNode::Unknown(_) => { 266 // Skip unknown nodes 267 } 268 } ··· 352 flat: bool, 353 ) -> miette::Result<FsDirectory<'static>> { 354 use jacquard_common::CowStr; 355 - use crate::place_wisp::fs::{Entry, Subfs}; 356 357 let path_parts: Vec<&str> = target_path.split('/').collect(); 358 ··· 430 431 // Construct AT-URI and convert to RecordUri 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()?; 434 435 let rkey = record_uri.rkey() 436 .ok_or_else(|| miette::miette!("Invalid subfs URI: missing rkey"))? ··· 489 } 490 491 /// Estimate the JSON size of a single entry 492 - fn estimate_entry_size(entry: &crate::place_wisp::fs::Entry) -> usize { 493 match serde_json::to_string(entry) { 494 Ok(json) => json.len(), 495 Err(_) => 500, // Conservative estimate if serialization fails
··· 6 use miette::IntoDiagnostic; 7 use std::collections::HashMap; 8 9 + use wisp_lexicons::place_wisp::fs::{Directory as FsDirectory, EntryNode as FsEntryNode}; 10 + use wisp_lexicons::place_wisp::subfs::SubfsRecord; 11 12 /// Extract all subfs URIs from a directory tree with their mount paths 13 pub fn extract_subfs_uris(directory: &FsDirectory, current_path: String) -> Vec<(String, String)> { ··· 145 146 /// Extract subfs URIs from a subfs::Directory 147 fn extract_subfs_uris_from_subfs_dir( 148 + directory: &wisp_lexicons::place_wisp::subfs::Directory, 149 current_path: String, 150 ) -> Vec<(String, String)> { 151 let mut uris = Vec::new(); 152 153 for entry in &directory.entries { 154 match &entry.node { 155 + wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(subfs_node) => { 156 // Check if this is a chunk entry (chunk0, chunk1, etc.) 157 // Chunks should be flat-merged, so use the parent's path 158 let mount_path = if entry.name.starts_with("chunk") && ··· 171 172 uris.push((subfs_node.subject.to_string(), mount_path)); 173 } 174 + wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => { 175 let full_path = if current_path.is_empty() { 176 entry.name.to_string() 177 } else { ··· 204 for (mount_path, subfs_record) in all_subfs { 205 // Check if this record only contains chunk subfs references (no files) 206 let only_has_chunks = subfs_record.root.entries.iter().all(|e| { 207 + matches!(&e.node, wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_)) && 208 e.name.starts_with("chunk") && 209 e.name.chars().skip(5).all(|c| c.is_ascii_digit()) 210 }); ··· 232 /// Extract blobs from a subfs directory (works with subfs::Directory) 233 /// Returns a map of file paths to their blob refs and CIDs 234 fn extract_subfs_blobs( 235 + directory: &wisp_lexicons::place_wisp::subfs::Directory, 236 current_path: String, 237 ) -> HashMap<String, (BlobRef<'static>, String)> { 238 let mut blob_map = HashMap::new(); ··· 245 }; 246 247 match &entry.node { 248 + wisp_lexicons::place_wisp::subfs::EntryNode::File(file_node) => { 249 let blob_ref = &file_node.blob; 250 let cid_string = blob_ref.blob().r#ref.to_string(); 251 blob_map.insert( ··· 253 (blob_ref.clone().into_static(), cid_string) 254 ); 255 } 256 + wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => { 257 let sub_map = extract_subfs_blobs(subdir, full_path); 258 blob_map.extend(sub_map); 259 } 260 + wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => { 261 // Nested subfs - these should be resolved recursively in the main flow 262 // For now, we skip them (they'll be fetched separately) 263 eprintln!(" โš ๏ธ Found nested subfs at {}, skipping (should be fetched separately)", full_path); 264 } 265 + wisp_lexicons::place_wisp::subfs::EntryNode::Unknown(_) => { 266 // Skip unknown nodes 267 } 268 } ··· 352 flat: bool, 353 ) -> miette::Result<FsDirectory<'static>> { 354 use jacquard_common::CowStr; 355 + use wisp_lexicons::place_wisp::fs::{Entry, Subfs}; 356 357 let path_parts: Vec<&str> = target_path.split('/').collect(); 358 ··· 430 431 // Construct AT-URI and convert to RecordUri 432 let at_uri = AtUri::new(uri).into_diagnostic()?; 433 + let record_uri: RecordUri<'_, wisp_lexicons::place_wisp::subfs::SubfsRecordRecord> = RecordUri::try_from_uri(at_uri).into_diagnostic()?; 434 435 let rkey = record_uri.rkey() 436 .ok_or_else(|| miette::miette!("Invalid subfs URI: missing rkey"))? ··· 489 } 490 491 /// Estimate the JSON size of a single entry 492 + fn estimate_entry_size(entry: &wisp_lexicons::place_wisp::fs::Entry) -> usize { 493 match serde_json::to_string(entry) { 494 Ok(json) => json.len(), 495 Err(_) => 500, // Conservative estimate if serialization fails
+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
··· 7 integrations: [ 8 starlight({ 9 title: 'Wisp.place Docs', 10 - social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/tangled-org/wisp.place' }], 11 sidebar: [ 12 { 13 label: 'Getting Started',
··· 7 integrations: [ 8 starlight({ 9 title: 'Wisp.place Docs', 10 + components: { 11 + SocialIcons: './src/components/SocialIcons.astro', 12 + }, 13 sidebar: [ 14 { 15 label: 'Getting Started',
+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
···
··· 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
··· 71 72 engine: 'nixery' 73 74 - clone: 75 - skip: false 76 - depth: 1 77 - submodules: false 78 - 79 dependencies: 80 nixpkgs: 81 - nodejs ··· 141 # Pull a site to a specific directory 142 wisp-cli pull your-handle.bsky.social \ 143 --site my-site \ 144 - --output ./my-site 145 146 # Pull to current directory 147 wisp-cli pull your-handle.bsky.social \ ··· 238 ### Pull Command 239 240 ```bash 241 - wisp-cli pull [OPTIONS] <INPUT> 242 243 Arguments: 244 <INPUT> Handle or DID 245 246 Options: 247 -s, --site <SITE> Site name to download 248 - -o, --output <OUTPUT> Output directory [default: .] 249 -h, --help Print help 250 ``` 251 252 ### Serve Command 253 254 ```bash 255 - wisp-cli serve [OPTIONS] <INPUT> 256 257 Arguments: 258 <INPUT> Handle or DID 259 260 Options: 261 -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] 264 --spa Enable SPA mode (serve index.html for all routes) 265 --directory Enable directory listing mode for paths without index files 266 -h, --help Print help
··· 71 72 engine: 'nixery' 73 74 dependencies: 75 nixpkgs: 76 - nodejs ··· 136 # Pull a site to a specific directory 137 wisp-cli pull your-handle.bsky.social \ 138 --site my-site \ 139 + --path ./my-site 140 141 # Pull to current directory 142 wisp-cli pull your-handle.bsky.social \ ··· 233 ### Pull Command 234 235 ```bash 236 + wisp-cli pull [OPTIONS] --site <SITE> <INPUT> 237 238 Arguments: 239 <INPUT> Handle or DID 240 241 Options: 242 -s, --site <SITE> Site name to download 243 + -p, --path <PATH> Output directory [default: .] 244 -h, --help Print help 245 ``` 246 247 ### Serve Command 248 249 ```bash 250 + wisp-cli serve [OPTIONS] --site <SITE> <INPUT> 251 252 Arguments: 253 <INPUT> Handle or DID 254 255 Options: 256 -s, --site <SITE> Site name to serve 257 + -p, --path <PATH> Site files directory [default: .] 258 + -P, --port <PORT> Port to serve on [default: 8080] 259 --spa Enable SPA mode (serve index.html for all routes) 260 --directory Enable directory listing mode for paths without index files 261 -h, --help Print help
-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
··· 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
···
··· 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
···
··· 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
···
··· 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
··· 24 "check": "cd apps/main-app && npm run check && cd ../hosting-service && npm run check", 25 "screenshot": "bun run apps/main-app/scripts/screenshot-sites.ts", 26 "hosting:dev": "cd apps/hosting-service && npm run dev", 27 - "hosting:start": "cd apps/hosting-service && npm run start" 28 }, 29 "trustedDependencies": [ 30 "@parcel/watcher",
··· 24 "check": "cd apps/main-app && npm run check && cd ../hosting-service && npm run check", 25 "screenshot": "bun run apps/main-app/scripts/screenshot-sites.ts", 26 "hosting:dev": "cd apps/hosting-service && npm run dev", 27 + "hosting:start": "cd apps/hosting-service && npm run start", 28 + "codegen": "./scripts/codegen.sh" 29 }, 30 "trustedDependencies": [ 31 "@parcel/watcher",
-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
··· 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
··· 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
··· 32 } 33 }, 34 "scripts": { 35 - "codegen": "lex gen-server ./src ./lexicons" 36 }, 37 "dependencies": { 38 "@atproto/lexicon": "^0.5.1",
··· 32 } 33 }, 34 "scripts": { 35 + "codegen": "lex gen-server ./src ../../../lexicons/*.json" 36 }, 37 "dependencies": { 38 "@atproto/lexicon": "^0.5.1",
+1 -1
packages/@wisp/lexicons/src/index.ts
··· 9 type MethodConfigOrHandler, 10 createServer as createXrpcServer, 11 } from '@atproto/xrpc-server' 12 - import { schemas } from './lexicons' 13 14 export function createServer(options?: XrpcOptions): Server { 15 return new Server(options)
··· 9 type MethodConfigOrHandler, 10 createServer as createXrpcServer, 11 } from '@atproto/xrpc-server' 12 + import { schemas } from './lexicons.js' 13 14 export function createServer(options?: XrpcOptions): Server { 15 return new Server(options)
+1 -1
packages/@wisp/lexicons/src/lexicons.ts
··· 7 ValidationError, 8 type ValidationResult, 9 } from '@atproto/lexicon' 10 - import { type $Typed, is$typed, maybe$typed } from './util' 11 12 export const schemaDict = { 13 PlaceWispFs: {
··· 7 ValidationError, 8 type ValidationResult, 9 } from '@atproto/lexicon' 10 + import { type $Typed, is$typed, maybe$typed } from './util.js' 11 12 export const schemaDict = { 13 PlaceWispFs: {
+1 -1
packages/@wisp/observability/README.md
··· 214 215 ## License 216 217 - Private
··· 214 215 ## License 216 217 + MIT
+2 -2
packages/@wisp/observability/src/exporters.ts
··· 3 * Integrates with Grafana Loki for logs and Prometheus/OTLP for metrics 4 */ 5 6 - import { LogEntry, ErrorEntry, MetricEntry } from './core' 7 - import { metrics, MeterProvider } from '@opentelemetry/api' 8 import { MeterProvider as SdkMeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics' 9 import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http' 10 import { Resource } from '@opentelemetry/resources'
··· 3 * Integrates with Grafana Loki for logs and Prometheus/OTLP for metrics 4 */ 5 6 + import type { LogEntry, ErrorEntry, MetricEntry } from './core' 7 + import { metrics, type MeterProvider } from '@opentelemetry/api' 8 import { MeterProvider as SdkMeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics' 9 import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http' 10 import { Resource } from '@opentelemetry/resources'
+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 ==="