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.

+2
.tangled/workflows/deploy-wisp.yml
··· 49 49 - name: Build docs 50 50 command: | 51 51 cd docs 52 + export PATH="$HOME/.nix-profile/bin:$PATH" 53 + bun install 52 54 bun run build 53 55 - name: Deploy to Wisp.place 54 56 command: |
+2 -1
.tangled/workflows/test.yml
··· 7 7 dependencies: 8 8 nixpkgs: 9 9 - git 10 + - findutils 10 11 github:NixOS/nixpkgs/nixpkgs-unstable: 11 12 - bun 12 13 ··· 16 17 export PATH="$HOME/.nix-profile/bin:$PATH" 17 18 18 19 # have to regenerate otherwise it wont install necessary dependencies to run 19 - rm -rf bun.lock package-lock.json 20 + find . -type f \( -name "bun.lock" -o -name "package-lock.json" \) -delete 20 21 bun install 21 22 22 23 - name: run all tests
+9 -8
apps/hosting-service/package.json
··· 10 10 "backfill": "tsx src/index.ts --backfill" 11 11 }, 12 12 "dependencies": { 13 - "@wisp/lexicons": "workspace:*", 14 - "@wisp/constants": "workspace:*", 15 - "@wisp/observability": "workspace:*", 16 - "@wisp/atproto-utils": "workspace:*", 17 - "@wisp/database": "workspace:*", 18 - "@wisp/fs-utils": "workspace:*", 19 - "@wisp/safe-fetch": "workspace:*", 20 13 "@atproto/api": "^0.17.4", 21 14 "@atproto/identity": "^0.4.9", 22 15 "@atproto/lexicon": "^0.5.2", 23 16 "@atproto/sync": "^0.1.36", 24 17 "@atproto/xrpc": "^0.7.5", 25 18 "@hono/node-server": "^1.19.6", 19 + "@wisp/atproto-utils": "workspace:*", 20 + "@wisp/constants": "workspace:*", 21 + "@wisp/database": "workspace:*", 22 + "@wisp/fs-utils": "workspace:*", 23 + "@wisp/lexicons": "workspace:*", 24 + "@wisp/observability": "workspace:*", 25 + "@wisp/safe-fetch": "workspace:*", 26 26 "hono": "^4.10.4", 27 27 "mime-types": "^2.1.35", 28 28 "multiformats": "^13.4.1", 29 - "postgres": "^3.4.5" 29 + "postgres": "^3.4.5", 30 + "tiered-storage": "1.0.3" 30 31 }, 31 32 "devDependencies": { 32 33 "@types/bun": "^1.3.1",
+31 -3
apps/hosting-service/src/index.ts
··· 5 5 import { mkdirSync, existsSync } from 'fs'; 6 6 import { backfillCache } from './lib/backfill'; 7 7 import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode, closeDatabase } from './lib/db'; 8 + import { storage, getStorageConfig } from './lib/storage'; 8 9 9 10 // Initialize Grafana exporters if configured 10 11 initializeGrafanaExporters({ ··· 50 51 51 52 firehose.start(); 52 53 54 + // Optional: Bootstrap hot cache from warm tier on startup 55 + const BOOTSTRAP_HOT_ON_STARTUP = process.env.BOOTSTRAP_HOT_ON_STARTUP === 'true'; 56 + const BOOTSTRAP_HOT_LIMIT = process.env.BOOTSTRAP_HOT_LIMIT ? parseInt(process.env.BOOTSTRAP_HOT_LIMIT) : 100; 57 + 58 + if (BOOTSTRAP_HOT_ON_STARTUP) { 59 + console.log(`๐Ÿ”ฅ Bootstrapping hot cache (top ${BOOTSTRAP_HOT_LIMIT} items)...`); 60 + storage.bootstrapHot(BOOTSTRAP_HOT_LIMIT) 61 + .then((loaded: number) => { 62 + console.log(`โœ… Bootstrapped ${loaded} items into hot cache`); 63 + }) 64 + .catch((err: unknown) => { 65 + console.error('โŒ Hot cache bootstrap error:', err); 66 + }); 67 + } 68 + 53 69 // Run backfill if requested 54 70 if (backfillOnStartup) { 55 71 console.log('๐Ÿ”„ Backfill requested, starting cache backfill...'); ··· 78 94 port: PORT, 79 95 }); 80 96 97 + // Get storage configuration for display 98 + const storageConfig = getStorageConfig(); 99 + 81 100 console.log(` 82 - Wisp Hosting Service 101 + Wisp Hosting Service with Tiered Storage 83 102 84 103 Server: http://localhost:${PORT} 85 104 Health: http://localhost:${PORT}/health 86 - Cache: ${CACHE_DIR} 87 - Firehose: Connected to Firehose 88 105 Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'} 89 106 Backfill: ${backfillOnStartup ? `ENABLED (concurrency: ${BACKFILL_CONCURRENCY || 10})` : 'DISABLED'} 107 + 108 + Tiered Storage Configuration: 109 + Hot Cache: ${storageConfig.hotCacheSize} (${storageConfig.hotCacheCount} items max) 110 + Warm Cache: ${storageConfig.warmCacheSize} (${storageConfig.warmEvictionPolicy} eviction) 111 + Cold Storage: S3 - ${storageConfig.s3Bucket} 112 + S3 Region: ${storageConfig.s3Region} 113 + S3 Endpoint: ${storageConfig.s3Endpoint} 114 + S3 Prefix: ${storageConfig.s3Prefix} 115 + Metadata Bucket: ${storageConfig.metadataBucket} 116 + 117 + Firehose: Connecting... 90 118 `); 91 119 92 120 // Graceful shutdown
+1 -1
apps/hosting-service/src/lib/backfill.ts
··· 69 69 const processSite = async () => { 70 70 try { 71 71 // Check if already cached 72 - if (skipExisting && isCached(site.did, site.rkey)) { 72 + if (skipExisting && await isCached(site.did, site.rkey)) { 73 73 stats.skipped++; 74 74 processed++; 75 75 logger.debug(`Skipping already cached site`, { did: site.did, rkey: site.rkey });
+35 -43
apps/hosting-service/src/lib/cache.ts
··· 1 - // In-memory LRU cache for file contents and metadata 1 + /** 2 + * Cache management for wisp-hosting-service 3 + * 4 + * With tiered storage, most caching is handled transparently. 5 + * This module tracks sites being cached and manages rewritten HTML cache. 6 + */ 2 7 8 + import { storage } from './storage'; 9 + 10 + // In-memory LRU cache for rewritten HTML (for path rewriting in subdomain routes) 3 11 interface CacheEntry<T> { 4 12 value: T; 5 13 size: number; ··· 96 104 return true; 97 105 } 98 106 99 - // Invalidate all entries for a specific site 100 - invalidateSite(did: string, rkey: string): number { 101 - const prefix = `${did}:${rkey}:`; 102 - let count = 0; 103 - 104 - for (const key of Array.from(this.cache.keys())) { 105 - if (key.startsWith(prefix)) { 106 - this.delete(key); 107 - count++; 108 - } 109 - } 110 - 111 - return count; 112 - } 113 - 114 - // Get cache size 115 107 size(): number { 116 108 return this.cache.size; 117 109 } ··· 127 119 return { ...this.stats }; 128 120 } 129 121 130 - // Get cache hit rate 131 122 getHitRate(): number { 132 123 const total = this.stats.hits + this.stats.misses; 133 124 return total === 0 ? 0 : (this.stats.hits / total) * 100; 134 125 } 135 126 } 136 127 137 - // File metadata cache entry 138 - export interface FileMetadata { 139 - encoding?: 'gzip'; 140 - mimeType: string; 141 - } 142 - 143 - // Global cache instances 144 - const FILE_CACHE_SIZE = 100 * 1024 * 1024; // 100MB 145 - const FILE_CACHE_COUNT = 500; 146 - const METADATA_CACHE_COUNT = 2000; 147 - 148 - export const fileCache = new LRUCache<Buffer>(FILE_CACHE_SIZE, FILE_CACHE_COUNT); 149 - export const metadataCache = new LRUCache<FileMetadata>(1024 * 1024, METADATA_CACHE_COUNT); // 1MB for metadata 128 + // Rewritten HTML cache: stores HTML after path rewriting for subdomain routes 150 129 export const rewrittenHtmlCache = new LRUCache<Buffer>(50 * 1024 * 1024, 200); // 50MB for rewritten HTML 151 130 152 - // Helper to generate cache keys 131 + // Helper to generate cache keys for rewritten HTML 153 132 export function getCacheKey(did: string, rkey: string, filePath: string, suffix?: string): string { 154 133 const base = `${did}:${rkey}:${filePath}`; 155 134 return suffix ? `${base}:${suffix}` : base; 156 135 } 157 136 158 - // Invalidate all caches for a site 159 - export function invalidateSiteCache(did: string, rkey: string): void { 160 - const fileCount = fileCache.invalidateSite(did, rkey); 161 - const metaCount = metadataCache.invalidateSite(did, rkey); 162 - const htmlCount = rewrittenHtmlCache.invalidateSite(did, rkey); 137 + /** 138 + * Invalidate site cache via tiered storage 139 + * Also invalidates locally cached rewritten HTML 140 + */ 141 + export async function invalidateSiteCache(did: string, rkey: string): Promise<void> { 142 + // Invalidate in tiered storage 143 + const prefix = `${did}/${rkey}/`; 144 + const deleted = await storage.invalidate(prefix); 163 145 164 - console.log(`[Cache] Invalidated site ${did}:${rkey} - ${fileCount} files, ${metaCount} metadata, ${htmlCount} HTML`); 146 + // Invalidate rewritten HTML cache for this site 147 + const sitePrefix = `${did}:${rkey}:`; 148 + let htmlCount = 0; 149 + const cacheKeys = Array.from((rewrittenHtmlCache as any).cache?.keys() || []) as string[]; 150 + for (const key of cacheKeys) { 151 + if (key.startsWith(sitePrefix)) { 152 + rewrittenHtmlCache.delete(key); 153 + htmlCount++; 154 + } 155 + } 156 + 157 + console.log(`[Cache] Invalidated site ${did}:${rkey} - ${deleted} files in tiered storage, ${htmlCount} rewritten HTML`); 165 158 } 166 159 167 160 // Track sites currently being cached (to prevent serving stale cache during updates) ··· 183 176 } 184 177 185 178 // Get overall cache statistics 186 - export function getCacheStats() { 179 + export async function getCacheStats() { 180 + const tieredStats = await storage.getStats(); 181 + 187 182 return { 188 - files: fileCache.getStats(), 189 - fileHitRate: fileCache.getHitRate(), 190 - metadata: metadataCache.getStats(), 191 - metadataHitRate: metadataCache.getHitRate(), 183 + tieredStorage: tieredStats, 192 184 rewrittenHtml: rewrittenHtmlCache.getStats(), 193 185 rewrittenHtmlHitRate: rewrittenHtmlCache.getHitRate(), 194 186 sitesBeingCached: sitesBeingCached.size,
+64 -76
apps/hosting-service/src/lib/file-serving.ts
··· 7 7 import { lookup } from 'mime-types'; 8 8 import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings'; 9 9 import { shouldCompressMimeType } from '@wisp/atproto-utils/compression'; 10 - import { fileCache, metadataCache, rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache'; 10 + import { rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache'; 11 11 import { getCachedFilePath, getCachedSettings } from './utils'; 12 12 import { loadRedirectRules, matchRedirectRule, parseCookies, parseQueryString } from './redirects'; 13 13 import { rewriteHtmlPaths, isHtmlContent } from './html-rewriter'; 14 14 import { generate404Page, generateDirectoryListing, siteUpdatingResponse } from './page-generators'; 15 15 import { getIndexFiles, applyCustomHeaders, fileExists } from './request-utils'; 16 16 import { getRedirectRulesFromCache, setRedirectRulesInCache } from './site-cache'; 17 + import { storage } from './storage'; 18 + 19 + /** 20 + * Helper to retrieve a file with metadata from tiered storage 21 + */ 22 + async function getFileWithMetadata(did: string, rkey: string, filePath: string) { 23 + const key = `${did}/${rkey}/${filePath}`; 24 + return await storage.getWithMetadata(key); 25 + } 17 26 18 27 /** 19 28 * Helper to serve files from cache (for custom domains and subdomains) ··· 176 185 177 186 // Not a directory, try to serve as a file 178 187 const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html'; 179 - const cacheKey = getCacheKey(did, rkey, fileRequestPath); 180 - const cachedFile = getCachedFilePath(did, rkey, fileRequestPath); 181 188 182 - // Check in-memory cache first 183 - let content = fileCache.get(cacheKey); 184 - let meta = metadataCache.get(cacheKey); 189 + // Retrieve from tiered storage 190 + const result = await getFileWithMetadata(did, rkey, fileRequestPath); 185 191 186 - if (!content && await fileExists(cachedFile)) { 187 - // Read from disk and cache 188 - content = await readFile(cachedFile); 189 - fileCache.set(cacheKey, content, content.length); 192 + if (result) { 193 + const content = Buffer.from(result.data); 194 + const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 190 195 191 - const metaFile = `${cachedFile}.meta`; 192 - if (await fileExists(metaFile)) { 193 - const metaJson = await readFile(metaFile, 'utf-8'); 194 - meta = JSON.parse(metaJson); 195 - metadataCache.set(cacheKey, meta!, JSON.stringify(meta).length); 196 - } 197 - } 198 - 199 - if (content) { 200 196 // Build headers with caching 201 - const headers: Record<string, string> = {}; 197 + const headers: Record<string, string> = { 198 + 'X-Cache-Tier': result.source, 199 + }; 202 200 203 - if (meta && meta.encoding === 'gzip' && meta.mimeType) { 201 + if (meta?.encoding === 'gzip' && meta.mimeType) { 204 202 const shouldServeCompressed = shouldCompressMimeType(meta.mimeType); 205 203 206 204 if (!shouldServeCompressed) { ··· 233 231 } 234 232 235 233 // Non-compressed files 236 - const mimeType = lookup(cachedFile) || 'application/octet-stream'; 234 + const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream'; 237 235 headers['Content-Type'] = mimeType; 238 236 headers['Cache-Control'] = mimeType.startsWith('text/html') 239 237 ? 'public, max-age=300' ··· 246 244 if (!fileRequestPath.includes('.')) { 247 245 for (const indexFileName of indexFiles) { 248 246 const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName; 249 - const indexCacheKey = getCacheKey(did, rkey, indexPath); 250 - const indexFile = getCachedFilePath(did, rkey, indexPath); 251 247 252 - let indexContent = fileCache.get(indexCacheKey); 253 - let indexMeta = metadataCache.get(indexCacheKey); 248 + const indexResult = await getFileWithMetadata(did, rkey, indexPath); 254 249 255 - if (!indexContent && await fileExists(indexFile)) { 256 - indexContent = await readFile(indexFile); 257 - fileCache.set(indexCacheKey, indexContent, indexContent.length); 250 + if (indexResult) { 251 + const indexContent = Buffer.from(indexResult.data); 252 + const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 258 253 259 - const indexMetaFile = `${indexFile}.meta`; 260 - if (await fileExists(indexMetaFile)) { 261 - const metaJson = await readFile(indexMetaFile, 'utf-8'); 262 - indexMeta = JSON.parse(metaJson); 263 - metadataCache.set(indexCacheKey, indexMeta!, JSON.stringify(indexMeta).length); 264 - } 265 - } 266 - 267 - if (indexContent) { 268 254 const headers: Record<string, string> = { 269 255 'Content-Type': 'text/html; charset=utf-8', 270 256 'Cache-Control': 'public, max-age=300', 257 + 'X-Cache-Tier': indexResult.source, 271 258 }; 272 259 273 - if (indexMeta && indexMeta.encoding === 'gzip') { 260 + if (indexMeta?.encoding === 'gzip') { 274 261 headers['Content-Encoding'] = 'gzip'; 275 262 } 276 263 ··· 556 543 557 544 // Not a directory, try to serve as a file 558 545 const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html'; 559 - const cacheKey = getCacheKey(did, rkey, fileRequestPath); 560 - const cachedFile = getCachedFilePath(did, rkey, fileRequestPath); 561 546 562 547 // Check for rewritten HTML in cache first (if it's HTML) 563 548 const mimeTypeGuess = lookup(fileRequestPath) || 'application/octet-stream'; ··· 565 550 const rewrittenKey = getCacheKey(did, rkey, fileRequestPath, `rewritten:${basePath}`); 566 551 const rewrittenContent = rewrittenHtmlCache.get(rewrittenKey); 567 552 if (rewrittenContent) { 553 + console.log(`[HTML Rewrite] Serving from rewritten cache: ${rewrittenKey}`); 568 554 const headers: Record<string, string> = { 569 555 'Content-Type': 'text/html; charset=utf-8', 570 556 'Content-Encoding': 'gzip', 571 557 'Cache-Control': 'public, max-age=300', 558 + 'X-Cache-Tier': 'local', // Rewritten HTML is stored locally 572 559 }; 573 560 applyCustomHeaders(headers, fileRequestPath, settings); 574 561 return new Response(rewrittenContent, { headers }); 575 562 } 576 563 } 577 564 578 - // Check in-memory file cache 579 - let content = fileCache.get(cacheKey); 580 - let meta = metadataCache.get(cacheKey); 565 + // Retrieve from tiered storage 566 + const result = await getFileWithMetadata(did, rkey, fileRequestPath); 581 567 582 - if (!content && await fileExists(cachedFile)) { 583 - // Read from disk and cache 584 - content = await readFile(cachedFile); 585 - fileCache.set(cacheKey, content, content.length); 568 + if (result) { 569 + const content = Buffer.from(result.data); 570 + const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 571 + const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream'; 572 + const isGzipped = meta?.encoding === 'gzip'; 586 573 587 - const metaFile = `${cachedFile}.meta`; 588 - if (await fileExists(metaFile)) { 589 - const metaJson = await readFile(metaFile, 'utf-8'); 590 - meta = JSON.parse(metaJson); 591 - metadataCache.set(cacheKey, meta!, JSON.stringify(meta).length); 592 - } 593 - } 594 - 595 - if (content) { 596 - const mimeType = meta?.mimeType || lookup(cachedFile) || 'application/octet-stream'; 597 - const isGzipped = meta?.encoding === 'gzip'; 574 + console.log(`[File Serve] Serving ${fileRequestPath}, mimeType: ${mimeType}, isHTML: ${isHtmlContent(fileRequestPath, mimeType)}, basePath: ${basePath}`); 598 575 599 576 // Check if this is HTML content that needs rewriting 600 577 if (isHtmlContent(fileRequestPath, mimeType)) { 578 + console.log(`[HTML Rewrite] Processing ${fileRequestPath}, basePath: ${basePath}, mimeType: ${mimeType}, isGzipped: ${isGzipped}`); 601 579 let htmlContent: string; 602 580 if (isGzipped) { 603 581 // Verify content is actually gzipped ··· 612 590 } else { 613 591 htmlContent = content.toString('utf-8'); 614 592 } 593 + // Check for <base> tag which can override paths 594 + const baseTagMatch = htmlContent.match(/<base\s+[^>]*href=["'][^"']+["'][^>]*>/i); 595 + if (baseTagMatch) { 596 + console.warn(`[HTML Rewrite] WARNING: <base> tag found: ${baseTagMatch[0]} - this may override path rewrites`); 597 + } 598 + 599 + // Find src/href attributes (quoted and unquoted) to debug 600 + const allMatches = htmlContent.match(/(?:src|href)\s*=\s*["']?\/[^"'\s>]+/g); 601 + console.log(`[HTML Rewrite] Found ${allMatches ? allMatches.length : 0} local path attrs`); 602 + if (allMatches && allMatches.length > 0) { 603 + console.log(`[HTML Rewrite] Sample paths: ${allMatches.slice(0, 5).join(', ')}`); 604 + } 605 + 615 606 const rewritten = rewriteHtmlPaths(htmlContent, basePath, fileRequestPath); 616 607 608 + const rewrittenMatches = rewritten.match(/(?:src|href)\s*=\s*["']?\/[^"'\s>]+/g); 609 + console.log(`[HTML Rewrite] After rewrite, found ${rewrittenMatches ? rewrittenMatches.length : 0} local paths`); 610 + if (rewrittenMatches && rewrittenMatches.length > 0) { 611 + console.log(`[HTML Rewrite] Sample rewritten: ${rewrittenMatches.slice(0, 5).join(', ')}`); 612 + } 613 + 617 614 // Recompress and cache the rewritten HTML 618 615 const { gzipSync } = await import('zlib'); 619 616 const recompressed = gzipSync(Buffer.from(rewritten, 'utf-8')); ··· 625 622 'Content-Type': 'text/html; charset=utf-8', 626 623 'Content-Encoding': 'gzip', 627 624 'Cache-Control': 'public, max-age=300', 625 + 'X-Cache-Tier': result.source, 628 626 }; 629 627 applyCustomHeaders(htmlHeaders, fileRequestPath, settings); 630 628 return new Response(recompressed, { headers: htmlHeaders }); ··· 634 632 const headers: Record<string, string> = { 635 633 'Content-Type': mimeType, 636 634 'Cache-Control': 'public, max-age=31536000, immutable', 635 + 'X-Cache-Tier': result.source, 637 636 }; 638 637 639 638 if (isGzipped) { ··· 663 662 if (!fileRequestPath.includes('.')) { 664 663 for (const indexFileName of indexFiles) { 665 664 const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName; 666 - const indexCacheKey = getCacheKey(did, rkey, indexPath); 667 - const indexFile = getCachedFilePath(did, rkey, indexPath); 668 665 669 666 // Check for rewritten index file in cache 670 667 const rewrittenKey = getCacheKey(did, rkey, indexPath, `rewritten:${basePath}`); ··· 674 671 'Content-Type': 'text/html; charset=utf-8', 675 672 'Content-Encoding': 'gzip', 676 673 'Cache-Control': 'public, max-age=300', 674 + 'X-Cache-Tier': 'local', // Rewritten HTML is stored locally 677 675 }; 678 676 applyCustomHeaders(headers, indexPath, settings); 679 677 return new Response(rewrittenContent, { headers }); 680 678 } 681 679 682 - let indexContent = fileCache.get(indexCacheKey); 683 - let indexMeta = metadataCache.get(indexCacheKey); 680 + const indexResult = await getFileWithMetadata(did, rkey, indexPath); 684 681 685 - if (!indexContent && await fileExists(indexFile)) { 686 - indexContent = await readFile(indexFile); 687 - fileCache.set(indexCacheKey, indexContent, indexContent.length); 688 - 689 - const indexMetaFile = `${indexFile}.meta`; 690 - if (await fileExists(indexMetaFile)) { 691 - const metaJson = await readFile(indexMetaFile, 'utf-8'); 692 - indexMeta = JSON.parse(metaJson); 693 - metadataCache.set(indexCacheKey, indexMeta!, JSON.stringify(indexMeta).length); 694 - } 695 - } 696 - 697 - if (indexContent) { 682 + if (indexResult) { 683 + const indexContent = Buffer.from(indexResult.data); 684 + const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined; 698 685 const isGzipped = indexMeta?.encoding === 'gzip'; 699 686 700 687 let htmlContent: string; ··· 722 709 'Content-Type': 'text/html; charset=utf-8', 723 710 'Content-Encoding': 'gzip', 724 711 'Cache-Control': 'public, max-age=300', 712 + 'X-Cache-Tier': indexResult.source, 725 713 }; 726 714 applyCustomHeaders(headers, indexPath, settings); 727 715 return new Response(recompressed, { headers });
+46 -35
apps/hosting-service/src/lib/firehose.ts
··· 1 - import { existsSync, rmSync } from 'fs' 1 + import { existsSync } from 'fs' 2 2 import { 3 3 getPdsForDid, 4 4 downloadAndCacheSite, ··· 13 13 import { invalidateSiteCache, markSiteAsBeingCached, unmarkSiteAsBeingCached } from './cache' 14 14 import { clearRedirectRulesCache } from './site-cache' 15 15 16 - const CACHE_DIR = './cache/sites' 16 + const CACHE_DIR = process.env.CACHE_DIR || './cache/sites' 17 17 18 18 export class FirehoseWorker { 19 19 private firehose: Firehose | null = null 20 20 private idResolver: IdResolver 21 21 private isShuttingDown = false 22 22 private lastEventTime = Date.now() 23 + private eventCount = 0 23 24 private cacheCleanupInterval: NodeJS.Timeout | null = null 25 + private healthCheckInterval: NodeJS.Timeout | null = null 24 26 25 27 constructor( 26 28 private logger?: (msg: string, data?: Record<string, unknown>) => void ··· 47 49 48 50 this.log('IdResolver cache cleared') 49 51 }, 60 * 60 * 1000) // Every hour 52 + 53 + // Health check: log if no events received for 30 seconds 54 + this.healthCheckInterval = setInterval(() => { 55 + if (this.isShuttingDown) return 56 + 57 + const timeSinceLastEvent = Date.now() - this.lastEventTime 58 + if (timeSinceLastEvent > 30000 && this.eventCount === 0) { 59 + this.log('Warning: No firehose events received in the last 30 seconds', { 60 + timeSinceLastEvent, 61 + eventsReceived: this.eventCount 62 + }) 63 + } else if (timeSinceLastEvent > 60000) { 64 + this.log('Firehose status check', { 65 + timeSinceLastEvent, 66 + eventsReceived: this.eventCount 67 + }) 68 + } 69 + }, 30000) // Every 30 seconds 50 70 } 51 71 52 72 start() { ··· 61 81 if (this.cacheCleanupInterval) { 62 82 clearInterval(this.cacheCleanupInterval) 63 83 this.cacheCleanupInterval = null 84 + } 85 + 86 + if (this.healthCheckInterval) { 87 + clearInterval(this.healthCheckInterval) 88 + this.healthCheckInterval = null 64 89 } 65 90 66 91 if (this.firehose) { ··· 80 105 filterCollections: ['place.wisp.fs', 'place.wisp.settings'], 81 106 handleEvent: async (evt: any) => { 82 107 this.lastEventTime = Date.now() 108 + this.eventCount++ 109 + 110 + if (this.eventCount === 1) { 111 + this.log('First firehose event received - connection established', { 112 + eventType: evt.event, 113 + collection: evt.collection 114 + }) 115 + } 83 116 84 117 // Watch for write events 85 118 if (evt.event === 'create' || evt.event === 'update') { ··· 189 222 } 190 223 }) 191 224 192 - this.firehose.start() 193 - this.log('Firehose started') 225 + this.firehose.start().catch((err: unknown) => { 226 + this.log('Fatal firehose error', { 227 + error: err instanceof Error ? err.message : String(err) 228 + }) 229 + console.error('Fatal firehose error:', err) 230 + }) 231 + this.log('Firehose starting') 194 232 } 195 233 196 234 private async handleCreateOrUpdate( ··· 250 288 } 251 289 252 290 // Invalidate in-memory caches before updating 253 - invalidateSiteCache(did, site) 291 + await invalidateSiteCache(did, site) 254 292 255 293 // Mark site as being cached to prevent serving stale content during update 256 294 markSiteAsBeingCached(did, site) ··· 340 378 }) 341 379 } 342 380 343 - // Invalidate in-memory caches 344 - invalidateSiteCache(did, site) 345 - 346 - // Delete disk cache 347 - this.deleteCache(did, site) 381 + // Invalidate all caches (tiered storage invalidation is handled by invalidateSiteCache) 382 + await invalidateSiteCache(did, site) 348 383 349 384 this.log('Successfully processed delete', { did, site }) 350 385 } ··· 353 388 this.log('Processing settings change', { did, rkey }) 354 389 355 390 // Invalidate in-memory caches (includes metadata which stores settings) 356 - invalidateSiteCache(did, rkey) 391 + await invalidateSiteCache(did, rkey) 357 392 358 393 // Check if site is already cached 359 394 const cacheDir = `${CACHE_DIR}/${did}/${rkey}` ··· 413 448 } 414 449 415 450 this.log('Successfully processed settings change', { did, rkey }) 416 - } 417 - 418 - private deleteCache(did: string, site: string) { 419 - const cacheDir = `${CACHE_DIR}/${did}/${site}` 420 - 421 - if (!existsSync(cacheDir)) { 422 - this.log('Cache directory does not exist, nothing to delete', { 423 - did, 424 - site 425 - }) 426 - return 427 - } 428 - 429 - try { 430 - rmSync(cacheDir, { recursive: true, force: true }) 431 - this.log('Cache deleted', { did, site, path: cacheDir }) 432 - } catch (err) { 433 - this.log('Failed to delete cache', { 434 - did, 435 - site, 436 - path: cacheDir, 437 - error: err instanceof Error ? err.message : String(err) 438 - }) 439 - } 440 451 } 441 452 442 453 getHealth() {
+16
apps/hosting-service/src/lib/html-rewriter.ts
··· 189 189 `\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}'([^']*)'`, 190 190 'gi' 191 191 ) 192 + // Unquoted attributes (valid in HTML5 for values without spaces/special chars) 193 + // Match: attr=value where value starts immediately (no quotes) and continues until space or > 194 + // Use negative lookahead to ensure we don't match quoted attributes 195 + const unquotedRegex = new RegExp( 196 + `\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}(?!["'])([^\\s>]+)`, 197 + 'gi' 198 + ) 192 199 193 200 rewritten = rewritten.replace(doubleQuoteRegex, (match, value) => { 194 201 const rewrittenValue = rewritePath( ··· 206 213 documentPath 207 214 ) 208 215 return `${attr}='${rewrittenValue}'` 216 + }) 217 + 218 + rewritten = rewritten.replace(unquotedRegex, (match, value) => { 219 + const rewrittenValue = rewritePath( 220 + value, 221 + normalizedBase, 222 + documentPath 223 + ) 224 + return `${attr}=${rewrittenValue}` 209 225 }) 210 226 } 211 227 }
+1 -1
apps/hosting-service/src/lib/site-cache.ts
··· 42 42 * Returns true if site is successfully cached, false otherwise 43 43 */ 44 44 export async function ensureSiteCached(did: string, rkey: string): Promise<boolean> { 45 - if (isCached(did, rkey)) { 45 + if (await isCached(did, rkey)) { 46 46 return true; 47 47 } 48 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 4 import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings'; 5 5 import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs'; 6 6 import { writeFile, readFile, rename } from 'fs/promises'; 7 + import { Readable } from 'stream'; 7 8 import { safeFetchJson, safeFetchBlob } from '@wisp/safe-fetch'; 8 9 import { CID } from 'multiformats'; 9 10 import { extractBlobCid } from '@wisp/atproto-utils'; 10 11 import { sanitizePath, collectFileCidsFromEntries, countFilesInDirectory } from '@wisp/fs-utils'; 11 12 import { shouldCompressMimeType } from '@wisp/atproto-utils/compression'; 12 13 import { MAX_BLOB_SIZE, MAX_FILE_COUNT, MAX_SITE_SIZE } from '@wisp/constants'; 14 + import { storage } from './storage'; 13 15 14 16 // Re-export shared utilities for local usage and tests 15 17 export { extractBlobCid, sanitizePath }; ··· 395 397 const existingMetadata = await getCacheMetadata(did, rkey); 396 398 const existingFileCids = existingMetadata?.fileCids || {}; 397 399 398 - // Use a temporary directory with timestamp to avoid collisions 399 - const tempSuffix = `.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; 400 - const tempDir = `${CACHE_DIR}/${did}/${rkey}${tempSuffix}`; 401 - const finalDir = `${CACHE_DIR}/${did}/${rkey}`; 402 - 403 - try { 404 - // Collect file CIDs from the new record (using expanded root) 405 - const newFileCids: Record<string, string> = {}; 406 - collectFileCidsFromEntries(expandedRoot.entries, '', newFileCids); 400 + // Collect file CIDs from the new record (using expanded root) 401 + const newFileCids: Record<string, string> = {}; 402 + collectFileCidsFromEntries(expandedRoot.entries, '', newFileCids); 407 403 408 - // Fetch site settings (optional) 409 - const settings = await fetchSiteSettings(did, rkey); 404 + // Fetch site settings (optional) 405 + const settings = await fetchSiteSettings(did, rkey); 410 406 411 - // Download/copy files to temporary directory (with incremental logic, using expanded root) 412 - await cacheFiles(did, rkey, expandedRoot.entries, pdsEndpoint, '', tempSuffix, existingFileCids, finalDir); 413 - await saveCacheMetadata(did, rkey, recordCid, tempSuffix, newFileCids, settings); 407 + // Download files directly to tiered storage (with incremental logic) 408 + await cacheFiles(did, rkey, expandedRoot.entries, pdsEndpoint, '', existingFileCids); 409 + await saveCacheMetadata(did, rkey, recordCid, newFileCids, settings); 414 410 415 - // Atomically replace old cache with new cache 416 - // On POSIX systems (Linux/macOS), rename is atomic 417 - if (existsSync(finalDir)) { 418 - // Rename old directory to backup 419 - const backupDir = `${finalDir}.old-${Date.now()}`; 420 - await rename(finalDir, backupDir); 421 - 422 - try { 423 - // Rename new directory to final location 424 - await rename(tempDir, finalDir); 425 - 426 - // Clean up old backup 427 - rmSync(backupDir, { recursive: true, force: true }); 428 - } catch (err) { 429 - // If rename failed, restore backup 430 - if (existsSync(backupDir) && !existsSync(finalDir)) { 431 - await rename(backupDir, finalDir); 432 - } 433 - throw err; 434 - } 435 - } else { 436 - // No existing cache, just rename temp to final 437 - await rename(tempDir, finalDir); 438 - } 439 - 440 - console.log('Successfully cached site atomically', did, rkey); 441 - } catch (err) { 442 - // Clean up temp directory on failure 443 - if (existsSync(tempDir)) { 444 - rmSync(tempDir, { recursive: true, force: true }); 445 - } 446 - throw err; 447 - } 411 + console.log('Successfully cached site', did, rkey); 448 412 } 449 413 450 414 ··· 454 418 entries: Entry[], 455 419 pdsEndpoint: string, 456 420 pathPrefix: string, 457 - dirSuffix: string = '', 458 - existingFileCids: Record<string, string> = {}, 459 - existingCacheDir?: string 421 + existingFileCids: Record<string, string> = {} 460 422 ): Promise<void> { 461 - // Collect file tasks, separating unchanged files from new/changed files 423 + // Collect file download tasks (skip unchanged files) 462 424 const downloadTasks: Array<() => Promise<void>> = []; 463 - const copyTasks: Array<() => Promise<void>> = []; 464 425 465 426 function collectFileTasks( 466 427 entries: Entry[], ··· 477 438 const cid = extractBlobCid(fileNode.blob); 478 439 479 440 // Check if file is unchanged (same CID as existing cache) 480 - if (cid && existingFileCids[currentPath] === cid && existingCacheDir) { 481 - // File unchanged - copy from existing cache instead of downloading 482 - copyTasks.push(() => copyExistingFile( 483 - did, 484 - site, 485 - currentPath, 486 - dirSuffix, 487 - existingCacheDir 488 - )); 441 + if (cid && existingFileCids[currentPath] === cid) { 442 + // File unchanged - skip download (already in tiered storage) 443 + console.log(`Skipping unchanged file: ${currentPath}`); 489 444 } else { 490 445 // File new or changed - download it 491 446 downloadTasks.push(() => cacheFileBlob( ··· 496 451 pdsEndpoint, 497 452 fileNode.encoding, 498 453 fileNode.mimeType, 499 - fileNode.base64, 500 - dirSuffix 454 + fileNode.base64 501 455 )); 502 456 } 503 457 } ··· 506 460 507 461 collectFileTasks(entries, pathPrefix); 508 462 509 - console.log(`[Incremental Update] Files to copy: ${copyTasks.length}, Files to download: ${downloadTasks.length}`); 463 + console.log(`[Incremental Update] Files to download: ${downloadTasks.length}`); 510 464 511 - // Copy unchanged files in parallel (fast local operations) - increased limit for better performance 512 - const copyLimit = 50; 513 - for (let i = 0; i < copyTasks.length; i += copyLimit) { 514 - const batch = copyTasks.slice(i, i + copyLimit); 515 - await Promise.all(batch.map(task => task())); 516 - if (copyTasks.length > copyLimit) { 517 - console.log(`[Cache Progress] Copied ${Math.min(i + copyLimit, copyTasks.length)}/${copyTasks.length} unchanged files`); 518 - } 519 - } 520 - 521 - // Download new/changed files concurrently - increased from 3 to 20 for much better performance 465 + // Download new/changed files concurrently 522 466 const downloadLimit = 20; 523 467 let successCount = 0; 524 468 let failureCount = 0; ··· 547 491 } 548 492 } 549 493 550 - /** 551 - * Copy an unchanged file from existing cache to new cache location 552 - */ 553 - async function copyExistingFile( 554 - did: string, 555 - site: string, 556 - filePath: string, 557 - dirSuffix: string, 558 - existingCacheDir: string 559 - ): Promise<void> { 560 - const { copyFile } = await import('fs/promises'); 561 - 562 - const sourceFile = `${existingCacheDir}/${filePath}`; 563 - const destFile = `${CACHE_DIR}/${did}/${site}${dirSuffix}/${filePath}`; 564 - const destDir = destFile.substring(0, destFile.lastIndexOf('/')); 565 - 566 - // Create destination directory if needed 567 - if (destDir && !existsSync(destDir)) { 568 - mkdirSync(destDir, { recursive: true }); 569 - } 570 - 571 - try { 572 - // Copy the file 573 - await copyFile(sourceFile, destFile); 574 - 575 - // Copy metadata file if it exists 576 - const sourceMetaFile = `${sourceFile}.meta`; 577 - const destMetaFile = `${destFile}.meta`; 578 - if (existsSync(sourceMetaFile)) { 579 - await copyFile(sourceMetaFile, destMetaFile); 580 - } 581 - } catch (err) { 582 - console.error(`Failed to copy cached file ${filePath}, will attempt download:`, err); 583 - throw err; 584 - } 585 - } 586 - 587 494 async function cacheFileBlob( 588 495 did: string, 589 496 site: string, ··· 592 499 pdsEndpoint: string, 593 500 encoding?: 'gzip', 594 501 mimeType?: string, 595 - base64?: boolean, 596 - dirSuffix: string = '' 502 + base64?: boolean 597 503 ): Promise<void> { 598 504 const cid = extractBlobCid(blobRef); 599 505 if (!cid) { ··· 616 522 content = Buffer.from(base64String, 'base64'); 617 523 } 618 524 619 - const cacheFile = `${CACHE_DIR}/${did}/${site}${dirSuffix}/${filePath}`; 620 - const fileDir = cacheFile.substring(0, cacheFile.lastIndexOf('/')); 621 - 622 - if (fileDir && !existsSync(fileDir)) { 623 - mkdirSync(fileDir, { recursive: true }); 624 - } 625 - 626 525 // Use the shared function to determine if this should remain compressed 627 526 const shouldStayCompressed = shouldCompressMimeType(mimeType); 628 527 ··· 640 539 } 641 540 } 642 541 643 - await writeFile(cacheFile, content); 542 + // Write to tiered storage with metadata 543 + const stream = Readable.from([content]); 544 + const key = `${did}/${site}/${filePath}`; 545 + 546 + // Build metadata object, only including defined values 547 + const customMetadata: Record<string, string> = {}; 548 + if (encoding) customMetadata.encoding = encoding; 549 + if (mimeType) customMetadata.mimeType = mimeType; 550 + 551 + await storage.setStream(key, stream, { 552 + size: content.length, 553 + skipTiers: ['hot'], // Don't put in memory on ingest, only on access 554 + metadata: customMetadata, 555 + }); 644 556 645 - // Store metadata only if file is still compressed 557 + // Log completion 646 558 if (encoding === 'gzip' && mimeType) { 647 - const metaFile = `${cacheFile}.meta`; 648 - await writeFile(metaFile, JSON.stringify({ encoding, mimeType })); 649 559 console.log('Cached file', filePath, content.length, 'bytes (gzipped,', mimeType + ')'); 650 560 } else { 651 561 console.log('Cached file', filePath, content.length, 'bytes'); ··· 658 568 return `${CACHE_DIR}/${did}/${site}/${sanitizedPath}`; 659 569 } 660 570 661 - export function isCached(did: string, site: string): boolean { 662 - return existsSync(`${CACHE_DIR}/${did}/${site}`); 571 + /** 572 + * Check if a site exists in any tier of the cache (without checking metadata) 573 + * This is a quick existence check - for actual retrieval, use storage.get() 574 + */ 575 + export async function isCached(did: string, site: string): Promise<boolean> { 576 + // Check if any file exists for this site by checking for the index.html 577 + // If index.html exists, the site is cached 578 + const indexKey = `${did}/${site}/index.html`; 579 + return await storage.exists(indexKey); 663 580 } 664 581 665 - async function saveCacheMetadata(did: string, rkey: string, recordCid: string, dirSuffix: string = '', fileCids?: Record<string, string>, settings?: WispSettings | null): Promise<void> { 582 + async function saveCacheMetadata(did: string, rkey: string, recordCid: string, fileCids?: Record<string, string>, settings?: WispSettings | null): Promise<void> { 666 583 const metadata: CacheMetadata = { 667 584 recordCid, 668 585 cachedAt: Date.now(), ··· 672 589 settings: settings || undefined 673 590 }; 674 591 675 - const metadataPath = `${CACHE_DIR}/${did}/${rkey}${dirSuffix}/.metadata.json`; 676 - const metadataDir = metadataPath.substring(0, metadataPath.lastIndexOf('/')); 677 - 678 - if (!existsSync(metadataDir)) { 679 - mkdirSync(metadataDir, { recursive: true }); 680 - } 681 - 682 - await writeFile(metadataPath, JSON.stringify(metadata, null, 2)); 592 + // Store through tiered storage for persistence to S3/cold tier 593 + const metadataKey = `${did}/${rkey}/.metadata.json`; 594 + const metadataBytes = new TextEncoder().encode(JSON.stringify(metadata, null, 2)); 595 + await storage.set(metadataKey, metadataBytes); 683 596 } 684 597 685 598 async function getCacheMetadata(did: string, rkey: string): Promise<CacheMetadata | null> { 686 599 try { 687 - const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`; 688 - if (!existsSync(metadataPath)) return null; 600 + // Retrieve metadata from tiered storage 601 + const metadataKey = `${did}/${rkey}/.metadata.json`; 602 + const data = await storage.get(metadataKey); 689 603 690 - const content = await readFile(metadataPath, 'utf-8'); 691 - return JSON.parse(content) as CacheMetadata; 604 + if (!data) return null; 605 + 606 + // Deserialize from Uint8Array to JSON (storage uses identity serialization) 607 + const jsonString = new TextDecoder().decode(data as Uint8Array); 608 + return JSON.parse(jsonString) as CacheMetadata; 692 609 } catch (err) { 693 610 console.error('Failed to read cache metadata', err); 694 611 return null; ··· 722 639 } 723 640 724 641 export async function updateCacheMetadataSettings(did: string, rkey: string, settings: WispSettings | null): Promise<void> { 725 - const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`; 726 - 727 - if (!existsSync(metadataPath)) { 728 - console.warn('Metadata file does not exist, cannot update settings', { did, rkey }); 729 - return; 730 - } 731 - 732 642 try { 733 - // Read existing metadata 734 - const content = await readFile(metadataPath, 'utf-8'); 735 - const metadata = JSON.parse(content) as CacheMetadata; 643 + // Read existing metadata from tiered storage 644 + const metadata = await getCacheMetadata(did, rkey); 645 + 646 + if (!metadata) { 647 + console.warn('Metadata does not exist, cannot update settings', { did, rkey }); 648 + return; 649 + } 736 650 737 651 // Update settings field 738 652 // Store null explicitly to cache "no settings" state and avoid repeated fetches 739 653 metadata.settings = settings ?? null; 740 654 741 - // Write back to disk 742 - await writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf-8'); 655 + // Write back through tiered storage 656 + // Convert to Uint8Array since storage is typed for binary data 657 + const metadataKey = `${did}/${rkey}/.metadata.json`; 658 + const metadataBytes = new TextEncoder().encode(JSON.stringify(metadata, null, 2)); 659 + await storage.set(metadataKey, metadataBytes); 743 660 console.log('Updated metadata settings', { did, rkey, hasSettings: !!settings }); 744 661 } catch (err) { 745 662 console.error('Failed to update metadata settings', err);
+4 -1
apps/hosting-service/src/server.ts
··· 80 80 return c.text('Invalid identifier', 400); 81 81 } 82 82 83 + console.log(`[Server] sites.wisp.place request: identifier=${identifier}, site=${site}, filePath=${filePath}`); 84 + 83 85 // Check if site is currently being cached - return updating response early 84 86 if (isSiteBeingCached(did, site)) { 85 87 return siteUpdatingResponse(); ··· 93 95 94 96 // Serve with HTML path rewriting to handle absolute paths 95 97 const basePath = `/${identifier}/${site}/`; 98 + console.log(`[Server] Serving with basePath: ${basePath}`); 96 99 const headers = extractHeaders(c.req.raw.headers); 97 100 return serveFromCacheWithRewrite(did, site, filePath, basePath, c.req.url, headers); 98 101 } ··· 227 230 228 231 app.get('/__internal__/observability/cache', async (c) => { 229 232 const { getCacheStats } = await import('./lib/cache'); 230 - const stats = getCacheStats(); 233 + const stats = await getCacheStats(); 231 234 return c.json({ cache: stats }); 232 235 }); 233 236
+59
backup.nix
··· 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 36 "mime-types": "^2.1.35", 37 37 "multiformats": "^13.4.1", 38 38 "postgres": "^3.4.5", 39 + "tiered-storage": "1.0.3", 39 40 }, 40 41 "devDependencies": { 41 42 "@types/bun": "^1.3.1", ··· 262 263 263 264 "@atproto/xrpc-server": ["@atproto/xrpc-server@0.9.6", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@atproto/ws-client": "^0.0.2", "@atproto/xrpc": "^0.7.5", "cbor-x": "^1.5.1", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "uint8arrays": "3.0.0", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-N/wPK0VEk8lZLkVsfG1wlkINQnBLO2fzWT+xclOjYl5lJwDi5xgiiyEQJAyZN49d6cmbsONu0SuOVw9pa5xLCw=="], 264 265 266 + "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], 267 + 268 + "@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="], 269 + 270 + "@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="], 271 + 272 + "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], 273 + 274 + "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], 275 + 276 + "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="], 277 + 278 + "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], 279 + 280 + "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.962.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/credential-provider-node": "3.962.0", "@aws-sdk/middleware-bucket-endpoint": "3.957.0", "@aws-sdk/middleware-expect-continue": "3.957.0", "@aws-sdk/middleware-flexible-checksums": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-location-constraint": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-sdk-s3": "3.957.0", "@aws-sdk/middleware-ssec": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/signature-v4-multi-region": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/eventstream-serde-browser": "^4.2.7", "@smithy/eventstream-serde-config-resolver": "^4.3.7", "@smithy/eventstream-serde-node": "^4.2.7", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-blob-browser": "^4.2.8", "@smithy/hash-node": "^4.2.7", "@smithy/hash-stream-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/md5-js": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-I2/1McBZCcM3PfM4ck8D6gnZR3K7+yl1fGkwTq/3ThEn9tdLjNwcdgTbPfxfX6LoecLrH9Ekoo+D9nmQ0T261w=="], 281 + 282 + "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.958.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6qNCIeaMzKzfqasy2nNRuYnMuaMebCcCPP4J2CVGkA8QYMbIVKPlkn9bpB20Vxe6H/r3jtCCLQaOJjVTx/6dXg=="], 283 + 284 + "@aws-sdk/core": ["@aws-sdk/core@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrZgDnF1lQZv75a52nFWs6MExihJF2GZB6ETZRqr6jMwhrk2kbJPUtvgbifwcL7AYmVqHQDJBrR/MqkwwFCpiw=="], 285 + 286 + "@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-qSwSfI+qBU9HDsd6/4fM9faCxYJx2yDuHtj+NVOQ6XYDWQzFab/hUdwuKZ77Pi6goLF1pBZhJ2azaC2w7LbnTA=="], 287 + 288 + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-475mkhGaWCr+Z52fOOVb/q2VHuNvqEDixlYIkeaO6xJ6t9qR0wpLt4hOQaR6zR1wfZV0SlE7d8RErdYq/PByog=="], 289 + 290 + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-8dS55QHRxXgJlHkEYaCGZIhieCs9NU1HU1BcqQ4RfUdSsfRdxxktqUKgCnBnOOn0oD3PPA8cQOCAVgIyRb3Rfw=="], 291 + 292 + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.962.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/credential-provider-env": "3.957.0", "@aws-sdk/credential-provider-http": "3.957.0", "@aws-sdk/credential-provider-login": "3.962.0", "@aws-sdk/credential-provider-process": "3.957.0", "@aws-sdk/credential-provider-sso": "3.958.0", "@aws-sdk/credential-provider-web-identity": "3.958.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-h0kVnXLW2d3nxbcrR/Pfg3W/+YoCguasWz7/3nYzVqmdKarGrpJzaFdoZtLgvDSZ8VgWUC4lWOTcsDMV0UNqUQ=="], 293 + 294 + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.962.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-kHYH6Av2UifG3mPkpPUNRh/PuX6adaAcpmsclJdHdxlixMCRdh8GNeEihq480DC0GmfqdpoSf1w2CLmLLPIS6w=="], 295 + 296 + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.962.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.957.0", "@aws-sdk/credential-provider-http": "3.957.0", "@aws-sdk/credential-provider-ini": "3.962.0", "@aws-sdk/credential-provider-process": "3.957.0", "@aws-sdk/credential-provider-sso": "3.958.0", "@aws-sdk/credential-provider-web-identity": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-CS78NsWRxLa+nWqeWBEYMZTLacMFIXs1C5WJuM9kD05LLiWL32ksljoPsvNN24Bc7rCSQIIMx/U3KGvkDVZMVg=="], 297 + 298 + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/KIz9kadwbeLy6SKvT79W81Y+hb/8LMDyeloA2zhouE28hmne+hLn0wNCQXAAupFFlYOAtZR2NTBs7HBAReJlg=="], 299 + 300 + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.958.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.958.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/token-providers": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-CBYHJ5ufp8HC4q+o7IJejCUctJXWaksgpmoFpXerbjAso7/Fg7LLUu9inXVOxlHKLlvYekDXjIUBXDJS2WYdgg=="], 301 + 302 + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.958.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-dgnvwjMq5Y66WozzUzxNkCFap+umHUtqMMKlr8z/vl9NYMLem/WUbWNpFFOVFWquXikc+ewtpBMR4KEDXfZ+KA=="], 303 + 304 + "@aws-sdk/lib-storage": ["@aws-sdk/lib-storage@3.962.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/smithy-client": "^4.10.2", "buffer": "5.6.0", "events": "3.3.0", "stream-browserify": "3.0.0", "tslib": "^2.6.2" }, "peerDependencies": { "@aws-sdk/client-s3": "^3.962.0" } }, "sha512-Ai5gWRQkzsUMQ6NPoZZoiLXoQ6/yPRcR4oracIVjyWcu48TfBpsRgbqY/5zNOM55ag1wPX9TtJJGOhK3TNk45g=="], 305 + 306 + "@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/util-arn-parser": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iczcn/QRIBSpvsdAS/rbzmoBpleX1JBjXvCynMbDceVLBIcVrwT1hXECrhtIC2cjh4HaLo9ClAbiOiWuqt+6MA=="], 307 + 308 + "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-AlbK3OeVNwZZil0wlClgeI/ISlOt/SPUxBsIns876IFaVu/Pj3DgImnYhpcJuFRek4r4XM51xzIaGQXM6GDHGg=="], 309 + 310 + "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.957.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/crc64-nvme": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iJpeVR5V8se1hl2pt+k8bF/e9JO4KWgPCMjg8BtRspNtKIUGy7j6msYvbDixaKZaF2Veg9+HoYcOhwnZumjXSA=="], 311 + 312 + "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA=="], 313 + 314 + "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-y8/W7TOQpmDJg/fPYlqAhwA4+I15LrS7TwgUEoxogtkD8gfur9wFMRLT8LCyc9o4NMEcAnK50hSb4+wB0qv6tQ=="], 315 + 316 + "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ=="], 317 + 318 + "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA=="], 319 + 320 + "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-arn-parser": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-5B2qY2nR2LYpxoQP0xUum5A1UNvH2JQpLHDH1nWFNF/XetV7ipFHksMxPNhtJJ6ARaWhQIDXfOUj0jcnkJxXUg=="], 321 + 322 + "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-qwkmrK0lizdjNt5qxl4tHYfASh8DFpHXM1iDVo+qHe+zuslfMqQEGRkzxS8tJq/I+8F0c6v3IKOveKJAfIvfqQ=="], 323 + 324 + "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-50vcHu96XakQnIvlKJ1UoltrFODjsq2KvtTgHiPFteUS884lQnK5VC/8xd1Msz/1ONpLMzdCVproCQqhDTtMPQ=="], 325 + 326 + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.958.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-/KuCcS8b5TpQXkYOrPLYytrgxBhv81+5pChkOlhegbeHttjM69pyUpQVJqyfDM/A7wPLnDrzCAnk4zaAOkY0Nw=="], 327 + 328 + "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A=="], 329 + 330 + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.957.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-t6UfP1xMUigMMzHcb7vaZcjv7dA2DQkk9C/OAP1dKyrE0vb4lFGDaTApi17GN6Km9zFxJthEMUbBc7DL0hq1Bg=="], 331 + 332 + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.958.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-UCj7lQXODduD1myNJQkV+LYcGYJ9iiMggR8ow8Hva1g3A/Na5imNXzz6O67k7DAee0TYpy+gkNw+SizC6min8Q=="], 333 + 334 + "@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="], 335 + 336 + "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.957.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Aj6m+AyrhWyg8YQ4LDPg2/gIfGHCEcoQdBt5DeSFogN5k9mmJPOJ+IAmNSWmWRjpOxEy6eY813RNDI6qS97M0g=="], 337 + 338 + "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw=="], 339 + 340 + "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.957.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nhmgKHnNV9K+i9daumaIz8JTLsIIML9PE/HUks5liyrjUzenjW/aHoc7WJ9/Td/gPZtayxFnXQSJRb/fDlBuJw=="], 341 + 342 + "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw=="], 343 + 344 + "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.957.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-ycbYCwqXk4gJGp0Oxkzf2KBeeGBdTxz559D41NJP8FlzSej1Gh7Rk40Zo6AyTfsNWkrl/kVi1t937OIzC5t+9Q=="], 345 + 346 + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="], 347 + 348 + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="], 349 + 265 350 "@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="], 266 351 267 352 "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], ··· 544 629 545 630 "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], 546 631 632 + "@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], 633 + 634 + "@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA=="], 635 + 636 + "@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.1", "", { "dependencies": { "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ=="], 637 + 638 + "@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="], 639 + 640 + "@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="], 641 + 642 + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA=="], 643 + 644 + "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="], 645 + 646 + "@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ujzPk8seYoDBmABDE5YqlhQZAXLOrtxtJLrbhHMKjBoG5b4dK4i6/mEU+6/7yXIAkqOO8sJ6YxZl+h0QQ1IJ7g=="], 647 + 648 + "@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-x7BtAiIPSaNaWuzm24Q/mtSkv+BrISO/fmheiJ39PKRNH3RmH2Hph/bUKSOBOBC9unqfIYDhKTHwpyZycLGPVQ=="], 649 + 650 + "@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-roySCtHC5+pQq5lK4be1fZ/WR6s/AxnPaLfCODIPArtN2du8s5Ot4mKVK3pPtijL/L654ws592JHJ1PbZFF6+A=="], 651 + 652 + "@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.7", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-QVD+g3+icFkThoy4r8wVFZMsIP08taHVKjE6Jpmz8h5CgX/kk6pTODq5cht0OMtcapUx+xrPzUTQdA+TmO0m1g=="], 653 + 654 + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="], 655 + 656 + "@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.8", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.0", "@smithy/chunked-blob-reader-native": "^4.2.1", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-07InZontqsM1ggTCPSRgI7d8DirqRrnpL7nIACT4PW0AWrgDiHhjGZzbAE5UtRSiU0NISGUYe7/rri9ZeWyDpw=="], 657 + 658 + "@smithy/hash-node": ["@smithy/hash-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw=="], 659 + 660 + "@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZQVoAwNYnFMIbd4DUc517HuwNelJUY6YOzwqrbcAgCnVn+79/OK7UjwA93SPpdTOpKDVkLIzavWm/Ck7SmnDPQ=="], 661 + 662 + "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="], 663 + 664 + "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="], 665 + 666 + "@smithy/md5-js": ["@smithy/md5-js@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Wv6JcUxtOLTnxvNjDnAiATUsk8gvA6EeS8zzHig07dotpByYsLot+m0AaQEniUBjx97AC41MQR4hW0baraD1Xw=="], 667 + 668 + "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg=="], 669 + 670 + "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.1", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg=="], 671 + 672 + "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.17", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg=="], 673 + 674 + "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="], 675 + 676 + "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="], 677 + 678 + "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="], 679 + 680 + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="], 681 + 682 + "@smithy/property-provider": ["@smithy/property-provider@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA=="], 683 + 684 + "@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="], 685 + 686 + "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="], 687 + 688 + "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="], 689 + 690 + "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="], 691 + 692 + "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="], 693 + 694 + "@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="], 695 + 696 + "@smithy/smithy-client": ["@smithy/smithy-client@4.10.2", "", { "dependencies": { "@smithy/core": "^3.20.0", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g=="], 697 + 698 + "@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="], 699 + 700 + "@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="], 701 + 702 + "@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="], 703 + 704 + "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="], 705 + 706 + "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="], 707 + 708 + "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="], 709 + 710 + "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="], 711 + 712 + "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.16", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ=="], 713 + 714 + "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.19", "", { "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA=="], 715 + 716 + "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="], 717 + 718 + "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="], 719 + 720 + "@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="], 721 + 722 + "@smithy/util-retry": ["@smithy/util-retry@4.2.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg=="], 723 + 724 + "@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="], 725 + 726 + "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="], 727 + 728 + "@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="], 729 + 730 + "@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="], 731 + 732 + "@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="], 733 + 547 734 "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], 548 735 549 736 "@tailwindcss/cli": ["@tailwindcss/cli@4.1.17", "", { "dependencies": { "@parcel/watcher": "^2.5.1", "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "enhanced-resolve": "^5.18.3", "mri": "^1.2.0", "picocolors": "^1.1.1", "tailwindcss": "4.1.17" }, "bin": { "tailwindcss": "dist/index.mjs" } }, "sha512-jUIxcyUNlCC2aNPnyPEWU/L2/ik3pB4fF3auKGXr8AvN3T3OFESVctFKOBoPZQaZJIeUpPn1uCLp0MRxuek8gg=="], ··· 643 830 "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], 644 831 645 832 "body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="], 833 + 834 + "bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="], 646 835 647 836 "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], 648 837 649 838 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 650 839 651 - "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], 840 + "buffer": ["buffer@5.6.0", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw=="], 652 841 653 842 "bun": ["bun@1.3.3", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.3.3", "@oven/bun-darwin-x64": "1.3.3", "@oven/bun-darwin-x64-baseline": "1.3.3", "@oven/bun-linux-aarch64": "1.3.3", "@oven/bun-linux-aarch64-musl": "1.3.3", "@oven/bun-linux-x64": "1.3.3", "@oven/bun-linux-x64-baseline": "1.3.3", "@oven/bun-linux-x64-musl": "1.3.3", "@oven/bun-linux-x64-musl-baseline": "1.3.3", "@oven/bun-windows-x64": "1.3.3", "@oven/bun-windows-x64-baseline": "1.3.3" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-2hJ4ocTZ634/Ptph4lysvO+LbbRZq8fzRvMwX0/CqaLBxrF2UB5D1LdMB8qGcdtCer4/VR9Bx5ORub0yn+yzmw=="], 654 843 ··· 750 939 751 940 "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], 752 941 942 + "fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], 943 + 753 944 "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], 754 945 755 946 "file-type": ["file-type@21.1.1", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-ifJXo8zUqbQ/bLbl9sFoqHNTNWbnPY1COImFfM6CCy7z+E+jC1eY9YfOKkx0fckIg+VljAy2/87T61fp0+eEkg=="], ··· 960 1151 961 1152 "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], 962 1153 963 - "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], 1154 + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], 964 1155 965 1156 "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], 966 1157 ··· 1004 1195 1005 1196 "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], 1006 1197 1198 + "stream-browserify": ["stream-browserify@3.0.0", "", { "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" } }, "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA=="], 1199 + 1007 1200 "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], 1008 1201 1009 1202 "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], 1010 1203 1011 1204 "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 1205 + 1206 + "strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="], 1012 1207 1013 1208 "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], 1014 1209 ··· 1024 1219 1025 1220 "thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="], 1026 1221 1222 + "tiered-storage": ["tiered-storage@1.0.3", "", { "dependencies": { "@aws-sdk/client-s3": "^3.500.0", "@aws-sdk/lib-storage": "^3.500.0", "hono": "^4.10.7", "mime-types": "^3.0.2", "tiny-lru": "^11.0.0" } }, "sha512-ntJCsWWYHSQWIDbObMfnJ8xw7cRSJCPzfbrjoY4hu0YIRizCthRWg8kCvJOgsgC+Upt259YHmfNwEr1wLv6Rxw=="], 1223 + 1224 + "tiny-lru": ["tiny-lru@11.4.5", "", {}, "sha512-hkcz3FjNJfKXjV4mjQ1OrXSLAehg8Hw+cEZclOVT+5c/cWQWImQ9wolzTjth+dmmDe++p3bme3fTxz6Q4Etsqw=="], 1225 + 1027 1226 "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 1028 1227 1029 1228 "tlds": ["tlds@1.261.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA=="], ··· 1063 1262 "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], 1064 1263 1065 1264 "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], 1265 + 1266 + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], 1066 1267 1067 1268 "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], 1068 1269 ··· 1118 1319 1119 1320 "@atproto/sync/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1120 1321 1322 + "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], 1323 + 1324 + "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], 1325 + 1326 + "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], 1327 + 1121 1328 "@ipld/dag-cbor/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1122 1329 1123 1330 "@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="], ··· 1274 1481 1275 1482 "@wisp/main-app/@atproto/api": ["@atproto/api@0.17.7", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/lexicon": "^0.5.1", "@atproto/syntax": "^0.4.1", "@atproto/xrpc": "^0.7.5", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-V+OJBZq9chcrD21xk1bUa6oc5DSKfQj5DmUPf5rmZncqL1w9ZEbS38H5cMyqqdhfgo2LWeDRdZHD0rvNyJsIaw=="], 1276 1483 1484 + "@wisp/observability/bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], 1485 + 1277 1486 "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], 1278 1487 1279 1488 "iron-session/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], ··· 1282 1491 1283 1492 "node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 1284 1493 1494 + "pino-abstract-transport/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], 1495 + 1285 1496 "require-in-the-middle/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 1286 1497 1287 1498 "send/http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], ··· 1291 1502 "send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 1292 1503 1293 1504 "serve-static/send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], 1505 + 1506 + "tiered-storage/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], 1294 1507 1295 1508 "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], 1296 1509 ··· 1302 1515 1303 1516 "wisp-hosting-service/@atproto/api": ["@atproto/api@0.17.7", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/lexicon": "^0.5.1", "@atproto/syntax": "^0.4.1", "@atproto/xrpc": "^0.7.5", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-V+OJBZq9chcrD21xk1bUa6oc5DSKfQj5DmUPf5rmZncqL1w9ZEbS38H5cMyqqdhfgo2LWeDRdZHD0rvNyJsIaw=="], 1304 1517 1305 - "wisp-hosting-service/@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="], 1518 + "@atproto/sync/@atproto/xrpc-server/@atproto/ws-client": ["@atproto/ws-client@0.0.3", "", { "dependencies": { "@atproto/common": "^0.5.0", "ws": "^8.12.0" } }, "sha512-eKqkTWBk6zuMY+6gs02eT7mS8Btewm8/qaL/Dp00NDCqpNC+U59MWvQsOWT3xkNGfd9Eip+V6VI4oyPvAfsfTA=="], 1306 1519 1307 - "@atproto/sync/@atproto/xrpc-server/@atproto/ws-client": ["@atproto/ws-client@0.0.3", "", { "dependencies": { "@atproto/common": "^0.5.0", "ws": "^8.12.0" } }, "sha512-eKqkTWBk6zuMY+6gs02eT7mS8Btewm8/qaL/Dp00NDCqpNC+U59MWvQsOWT3xkNGfd9Eip+V6VI4oyPvAfsfTA=="], 1520 + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], 1521 + 1522 + "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], 1523 + 1524 + "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], 1308 1525 1309 1526 "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="], 1310 1527 ··· 1342 1559 1343 1560 "@wisp/main-app/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1344 1561 1562 + "pino-abstract-transport/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], 1563 + 1345 1564 "require-in-the-middle/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 1346 1565 1347 1566 "serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], ··· 1351 1570 "serve-static/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 1352 1571 1353 1572 "serve-static/send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 1573 + 1574 + "tiered-storage/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], 1354 1575 1355 1576 "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA=="], 1356 1577 ··· 1406 1627 1407 1628 "wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 1408 1629 1409 - "wisp-hosting-service/@types/bun/bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="], 1630 + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], 1631 + 1632 + "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], 1633 + 1634 + "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], 1410 1635 } 1411 1636 }
+190 -262
cli/Cargo.lock
··· 126 126 127 127 [[package]] 128 128 name = "async-compression" 129 - version = "0.4.34" 129 + version = "0.4.36" 130 130 source = "registry+https://github.com/rust-lang/crates.io-index" 131 - checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473" 131 + checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" 132 132 dependencies = [ 133 133 "compression-codecs", 134 134 "compression-core", ··· 145 145 dependencies = [ 146 146 "proc-macro2", 147 147 "quote", 148 - "syn 2.0.111", 148 + "syn 2.0.113", 149 149 ] 150 150 151 151 [[package]] ··· 171 171 172 172 [[package]] 173 173 name = "axum" 174 - version = "0.8.7" 174 + version = "0.8.8" 175 175 source = "registry+https://github.com/rust-lang/crates.io-index" 176 - checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" 176 + checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" 177 177 dependencies = [ 178 178 "axum-core", 179 179 "bytes", ··· 204 204 205 205 [[package]] 206 206 name = "axum-core" 207 - version = "0.5.5" 207 + version = "0.5.6" 208 208 source = "registry+https://github.com/rust-lang/crates.io-index" 209 - checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" 209 + checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" 210 210 dependencies = [ 211 211 "bytes", 212 212 "futures-core", ··· 233 233 "miniz_oxide", 234 234 "object", 235 235 "rustc-demangle", 236 - "windows-link 0.2.1", 236 + "windows-link", 237 237 ] 238 238 239 239 [[package]] ··· 281 281 282 282 [[package]] 283 283 name = "base64ct" 284 - version = "1.8.0" 284 + version = "1.8.2" 285 285 source = "registry+https://github.com/rust-lang/crates.io-index" 286 - checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" 286 + checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" 287 287 288 288 [[package]] 289 289 name = "bitflags" ··· 322 322 "proc-macro2", 323 323 "quote", 324 324 "rustversion", 325 - "syn 2.0.111", 325 + "syn 2.0.113", 326 326 ] 327 327 328 328 [[package]] 329 329 name = "borsh" 330 - version = "1.5.7" 330 + version = "1.6.0" 331 331 source = "registry+https://github.com/rust-lang/crates.io-index" 332 - checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" 332 + checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 333 333 dependencies = [ 334 334 "cfg_aliases", 335 335 ] ··· 377 377 378 378 [[package]] 379 379 name = "bumpalo" 380 - version = "3.19.0" 380 + version = "3.19.1" 381 381 source = "registry+https://github.com/rust-lang/crates.io-index" 382 - checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" 382 + checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" 383 383 384 384 [[package]] 385 385 name = "byteorder" ··· 407 407 408 408 [[package]] 409 409 name = "cc" 410 - version = "1.2.47" 410 + version = "1.2.51" 411 411 source = "registry+https://github.com/rust-lang/crates.io-index" 412 - checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" 412 + checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" 413 413 dependencies = [ 414 414 "find-msvc-tools", 415 415 "shlex", ··· 444 444 "num-traits", 445 445 "serde", 446 446 "wasm-bindgen", 447 - "windows-link 0.2.1", 447 + "windows-link", 448 448 ] 449 449 450 450 [[package]] ··· 496 496 497 497 [[package]] 498 498 name = "clap" 499 - version = "4.5.53" 499 + version = "4.5.54" 500 500 source = "registry+https://github.com/rust-lang/crates.io-index" 501 - checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" 501 + checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" 502 502 dependencies = [ 503 503 "clap_builder", 504 504 "clap_derive", ··· 506 506 507 507 [[package]] 508 508 name = "clap_builder" 509 - version = "4.5.53" 509 + version = "4.5.54" 510 510 source = "registry+https://github.com/rust-lang/crates.io-index" 511 - checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" 511 + checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" 512 512 dependencies = [ 513 513 "anstream", 514 514 "anstyle", ··· 525 525 "heck 0.5.0", 526 526 "proc-macro2", 527 527 "quote", 528 - "syn 2.0.111", 528 + "syn 2.0.113", 529 529 ] 530 530 531 531 [[package]] ··· 561 561 562 562 [[package]] 563 563 name = "compression-codecs" 564 - version = "0.4.33" 564 + version = "0.4.35" 565 565 source = "registry+https://github.com/rust-lang/crates.io-index" 566 - checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad" 566 + checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" 567 567 dependencies = [ 568 568 "compression-core", 569 569 "flate2", ··· 753 753 "proc-macro2", 754 754 "quote", 755 755 "strsim", 756 - "syn 2.0.111", 756 + "syn 2.0.113", 757 757 ] 758 758 759 759 [[package]] ··· 764 764 dependencies = [ 765 765 "darling_core", 766 766 "quote", 767 - "syn 2.0.111", 767 + "syn 2.0.113", 768 768 ] 769 769 770 770 [[package]] ··· 804 804 checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" 805 805 dependencies = [ 806 806 "data-encoding", 807 - "syn 2.0.111", 807 + "syn 2.0.113", 808 808 ] 809 809 810 810 [[package]] ··· 854 854 dependencies = [ 855 855 "proc-macro2", 856 856 "quote", 857 - "syn 2.0.111", 857 + "syn 2.0.113", 858 858 "unicode-xid", 859 859 ] 860 860 ··· 905 905 dependencies = [ 906 906 "proc-macro2", 907 907 "quote", 908 - "syn 2.0.111", 908 + "syn 2.0.113", 909 909 ] 910 910 911 911 [[package]] ··· 978 978 "heck 0.5.0", 979 979 "proc-macro2", 980 980 "quote", 981 - "syn 2.0.111", 981 + "syn 2.0.113", 982 982 ] 983 983 984 984 [[package]] ··· 1027 1027 1028 1028 [[package]] 1029 1029 name = "find-msvc-tools" 1030 - version = "0.1.5" 1030 + version = "0.1.6" 1031 1031 source = "registry+https://github.com/rust-lang/crates.io-index" 1032 - checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 1032 + checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" 1033 1033 1034 1034 [[package]] 1035 1035 name = "flate2" ··· 1154 1154 dependencies = [ 1155 1155 "proc-macro2", 1156 1156 "quote", 1157 - "syn 2.0.111", 1157 + "syn 2.0.113", 1158 1158 ] 1159 1159 1160 1160 [[package]] ··· 1189 1189 1190 1190 [[package]] 1191 1191 name = "generator" 1192 - version = "0.8.7" 1192 + version = "0.8.8" 1193 1193 source = "registry+https://github.com/rust-lang/crates.io-index" 1194 - checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" 1194 + checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" 1195 1195 dependencies = [ 1196 1196 "cc", 1197 1197 "cfg-if", 1198 1198 "libc", 1199 1199 "log", 1200 1200 "rustversion", 1201 - "windows", 1201 + "windows-link", 1202 + "windows-result", 1202 1203 ] 1203 1204 1204 1205 [[package]] ··· 1308 1309 1309 1310 [[package]] 1310 1311 name = "h2" 1311 - version = "0.4.12" 1312 + version = "0.4.13" 1312 1313 source = "registry+https://github.com/rust-lang/crates.io-index" 1313 - checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" 1314 + checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" 1314 1315 dependencies = [ 1315 1316 "atomic-waker", 1316 1317 "bytes", ··· 1471 1472 "markup5ever", 1472 1473 "proc-macro2", 1473 1474 "quote", 1474 - "syn 2.0.111", 1475 + "syn 2.0.113", 1475 1476 ] 1476 1477 1477 1478 [[package]] ··· 1567 1568 1568 1569 [[package]] 1569 1570 name = "hyper-util" 1570 - version = "0.1.18" 1571 + version = "0.1.19" 1571 1572 source = "registry+https://github.com/rust-lang/crates.io-index" 1572 - checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" 1573 + checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" 1573 1574 dependencies = [ 1574 1575 "base64 0.22.1", 1575 1576 "bytes", ··· 1603 1604 "js-sys", 1604 1605 "log", 1605 1606 "wasm-bindgen", 1606 - "windows-core 0.62.2", 1607 + "windows-core", 1607 1608 ] 1608 1609 1609 1610 [[package]] ··· 1663 1664 1664 1665 [[package]] 1665 1666 name = "icu_properties" 1666 - version = "2.1.1" 1667 + version = "2.1.2" 1667 1668 source = "registry+https://github.com/rust-lang/crates.io-index" 1668 - checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" 1669 + checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 1669 1670 dependencies = [ 1670 1671 "icu_collections", 1671 1672 "icu_locale_core", ··· 1677 1678 1678 1679 [[package]] 1679 1680 name = "icu_properties_data" 1680 - version = "2.1.1" 1681 + version = "2.1.2" 1681 1682 source = "registry+https://github.com/rust-lang/crates.io-index" 1682 - checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" 1683 + checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 1683 1684 1684 1685 [[package]] 1685 1686 name = "icu_provider" ··· 1802 1803 1803 1804 [[package]] 1804 1805 name = "iri-string" 1805 - version = "0.7.9" 1806 + version = "0.7.10" 1806 1807 source = "registry+https://github.com/rust-lang/crates.io-index" 1807 - checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" 1808 + checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" 1808 1809 dependencies = [ 1809 1810 "memchr", 1810 1811 "serde", ··· 1824 1825 1825 1826 [[package]] 1826 1827 name = "itoa" 1827 - version = "1.0.15" 1828 + version = "1.0.17" 1828 1829 source = "registry+https://github.com/rust-lang/crates.io-index" 1829 - checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 1830 + checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 1830 1831 1831 1832 [[package]] 1832 1833 name = "jacquard" ··· 1935 1936 "jacquard-lexicon", 1936 1937 "proc-macro2", 1937 1938 "quote", 1938 - "syn 2.0.111", 1939 + "syn 2.0.113", 1939 1940 ] 1940 1941 1941 1942 [[package]] ··· 1986 1987 "serde_repr", 1987 1988 "serde_with", 1988 1989 "sha2", 1989 - "syn 2.0.111", 1990 + "syn 2.0.113", 1990 1991 "thiserror 2.0.17", 1991 1992 "unicode-segmentation", 1992 1993 ] ··· 2082 2083 2083 2084 [[package]] 2084 2085 name = "js-sys" 2085 - version = "0.3.82" 2086 + version = "0.3.83" 2086 2087 source = "registry+https://github.com/rust-lang/crates.io-index" 2087 - checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" 2088 + checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" 2088 2089 dependencies = [ 2089 2090 "once_cell", 2090 2091 "wasm-bindgen", ··· 2113 2114 2114 2115 [[package]] 2115 2116 name = "libc" 2116 - version = "0.2.177" 2117 + version = "0.2.179" 2117 2118 source = "registry+https://github.com/rust-lang/crates.io-index" 2118 - checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 2119 + checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" 2119 2120 2120 2121 [[package]] 2121 2122 name = "libm" ··· 2125 2126 2126 2127 [[package]] 2127 2128 name = "libredox" 2128 - version = "0.1.10" 2129 + version = "0.1.12" 2129 2130 source = "registry+https://github.com/rust-lang/crates.io-index" 2130 - checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" 2131 + checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" 2131 2132 dependencies = [ 2132 2133 "bitflags", 2133 2134 "libc", 2134 - "redox_syscall", 2135 + "redox_syscall 0.7.0", 2135 2136 ] 2136 2137 2137 2138 [[package]] ··· 2163 2164 2164 2165 [[package]] 2165 2166 name = "log" 2166 - version = "0.4.28" 2167 + version = "0.4.29" 2167 2168 source = "registry+https://github.com/rust-lang/crates.io-index" 2168 - checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 2169 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 2169 2170 2170 2171 [[package]] 2171 2172 name = "loom" ··· 2299 2300 dependencies = [ 2300 2301 "proc-macro2", 2301 2302 "quote", 2302 - "syn 2.0.111", 2303 + "syn 2.0.113", 2303 2304 ] 2304 2305 2305 2306 [[package]] ··· 2344 2345 2345 2346 [[package]] 2346 2347 name = "mio" 2347 - version = "1.1.0" 2348 + version = "1.1.1" 2348 2349 source = "registry+https://github.com/rust-lang/crates.io-index" 2349 - checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" 2350 + checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" 2350 2351 dependencies = [ 2351 2352 "libc", 2352 2353 "wasi", ··· 2588 2589 2589 2590 [[package]] 2590 2591 name = "openssl-probe" 2591 - version = "0.1.6" 2592 + version = "0.2.0" 2592 2593 source = "registry+https://github.com/rust-lang/crates.io-index" 2593 - checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 2594 + checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" 2594 2595 2595 2596 [[package]] 2596 2597 name = "option-ext" ··· 2619 2620 "proc-macro2", 2620 2621 "proc-macro2-diagnostics", 2621 2622 "quote", 2622 - "syn 2.0.111", 2623 + "syn 2.0.113", 2623 2624 ] 2624 2625 2625 2626 [[package]] ··· 2683 2684 dependencies = [ 2684 2685 "cfg-if", 2685 2686 "libc", 2686 - "redox_syscall", 2687 + "redox_syscall 0.5.18", 2687 2688 "smallvec", 2688 - "windows-link 0.2.1", 2689 + "windows-link", 2689 2690 ] 2690 2691 2691 2692 [[package]] ··· 2758 2759 dependencies = [ 2759 2760 "proc-macro2", 2760 2761 "quote", 2761 - "syn 2.0.111", 2762 + "syn 2.0.113", 2762 2763 ] 2763 2764 2764 2765 [[package]] ··· 2796 2797 2797 2798 [[package]] 2798 2799 name = "portable-atomic" 2799 - version = "1.11.1" 2800 + version = "1.13.0" 2800 2801 source = "registry+https://github.com/rust-lang/crates.io-index" 2801 - checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" 2802 + checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" 2802 2803 2803 2804 [[package]] 2804 2805 name = "postcard" ··· 2850 2851 checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 2851 2852 dependencies = [ 2852 2853 "proc-macro2", 2853 - "syn 2.0.111", 2854 + "syn 2.0.113", 2854 2855 ] 2855 2856 2856 2857 [[package]] ··· 2864 2865 2865 2866 [[package]] 2866 2867 name = "proc-macro2" 2867 - version = "1.0.103" 2868 + version = "1.0.105" 2868 2869 source = "registry+https://github.com/rust-lang/crates.io-index" 2869 - checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 2870 + checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" 2870 2871 dependencies = [ 2871 2872 "unicode-ident", 2872 2873 ] ··· 2879 2880 dependencies = [ 2880 2881 "proc-macro2", 2881 2882 "quote", 2882 - "syn 2.0.111", 2883 + "syn 2.0.113", 2883 2884 "version_check", 2884 2885 "yansi", 2885 2886 ] ··· 2947 2948 2948 2949 [[package]] 2949 2950 name = "quote" 2950 - version = "1.0.42" 2951 + version = "1.0.43" 2951 2952 source = "registry+https://github.com/rust-lang/crates.io-index" 2952 - checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 2953 + checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" 2953 2954 dependencies = [ 2954 2955 "proc-macro2", 2955 2956 ] ··· 3029 3030 ] 3030 3031 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 + ] 3040 + 3041 + [[package]] 3032 3042 name = "redox_users" 3033 3043 version = "0.5.2" 3034 3044 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3076 3086 3077 3087 [[package]] 3078 3088 name = "reqwest" 3079 - version = "0.12.24" 3089 + version = "0.12.28" 3080 3090 source = "registry+https://github.com/rust-lang/crates.io-index" 3081 - checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" 3091 + checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" 3082 3092 dependencies = [ 3083 - "async-compression", 3084 3093 "base64 0.22.1", 3085 3094 "bytes", 3086 3095 "encoding_rs", ··· 3175 3184 3176 3185 [[package]] 3177 3186 name = "rsa" 3178 - version = "0.9.9" 3187 + version = "0.9.10" 3179 3188 source = "registry+https://github.com/rust-lang/crates.io-index" 3180 - checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" 3189 + checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" 3181 3190 dependencies = [ 3182 3191 "const-oid", 3183 3192 "digest", ··· 3216 3225 3217 3226 [[package]] 3218 3227 name = "rustix" 3219 - version = "1.1.2" 3228 + version = "1.1.3" 3220 3229 source = "registry+https://github.com/rust-lang/crates.io-index" 3221 - checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 3230 + checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" 3222 3231 dependencies = [ 3223 3232 "bitflags", 3224 3233 "errno", ··· 3229 3238 3230 3239 [[package]] 3231 3240 name = "rustls" 3232 - version = "0.23.35" 3241 + version = "0.23.36" 3233 3242 source = "registry+https://github.com/rust-lang/crates.io-index" 3234 - checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" 3243 + checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" 3235 3244 dependencies = [ 3236 3245 "once_cell", 3237 3246 "ring", ··· 3243 3252 3244 3253 [[package]] 3245 3254 name = "rustls-native-certs" 3246 - version = "0.8.2" 3255 + version = "0.8.3" 3247 3256 source = "registry+https://github.com/rust-lang/crates.io-index" 3248 - checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" 3257 + checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" 3249 3258 dependencies = [ 3250 3259 "openssl-probe", 3251 3260 "rustls-pki-types", ··· 3255 3264 3256 3265 [[package]] 3257 3266 name = "rustls-pki-types" 3258 - version = "1.13.0" 3267 + version = "1.13.2" 3259 3268 source = "registry+https://github.com/rust-lang/crates.io-index" 3260 - checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" 3269 + checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" 3261 3270 dependencies = [ 3262 3271 "web-time", 3263 3272 "zeroize", ··· 3282 3291 3283 3292 [[package]] 3284 3293 name = "ryu" 3285 - version = "1.0.20" 3294 + version = "1.0.22" 3286 3295 source = "registry+https://github.com/rust-lang/crates.io-index" 3287 - checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 3296 + checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" 3288 3297 3289 3298 [[package]] 3290 3299 name = "safemem" ··· 3408 3417 dependencies = [ 3409 3418 "proc-macro2", 3410 3419 "quote", 3411 - "syn 2.0.111", 3420 + "syn 2.0.113", 3412 3421 ] 3413 3422 3414 3423 [[package]] ··· 3437 3446 3438 3447 [[package]] 3439 3448 name = "serde_json" 3440 - version = "1.0.145" 3449 + version = "1.0.149" 3441 3450 source = "registry+https://github.com/rust-lang/crates.io-index" 3442 - checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 3451 + checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" 3443 3452 dependencies = [ 3444 3453 "itoa", 3445 3454 "memchr", 3446 - "ryu", 3447 3455 "serde", 3448 3456 "serde_core", 3457 + "zmij", 3449 3458 ] 3450 3459 3451 3460 [[package]] ··· 3467 3476 dependencies = [ 3468 3477 "proc-macro2", 3469 3478 "quote", 3470 - "syn 2.0.111", 3479 + "syn 2.0.113", 3471 3480 ] 3472 3481 3473 3482 [[package]] ··· 3484 3493 3485 3494 [[package]] 3486 3495 name = "serde_with" 3487 - version = "3.16.0" 3496 + version = "3.16.1" 3488 3497 source = "registry+https://github.com/rust-lang/crates.io-index" 3489 - checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" 3498 + checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" 3490 3499 dependencies = [ 3491 3500 "base64 0.22.1", 3492 3501 "chrono", ··· 3499 3508 3500 3509 [[package]] 3501 3510 name = "serde_with_macros" 3502 - version = "3.16.0" 3511 + version = "3.16.1" 3503 3512 source = "registry+https://github.com/rust-lang/crates.io-index" 3504 - checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" 3513 + checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" 3505 3514 dependencies = [ 3506 3515 "darling", 3507 3516 "proc-macro2", 3508 3517 "quote", 3509 - "syn 2.0.111", 3518 + "syn 2.0.113", 3510 3519 ] 3511 3520 3512 3521 [[package]] ··· 3563 3572 3564 3573 [[package]] 3565 3574 name = "signal-hook-registry" 3566 - version = "1.4.7" 3575 + version = "1.4.8" 3567 3576 source = "registry+https://github.com/rust-lang/crates.io-index" 3568 - checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" 3577 + checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" 3569 3578 dependencies = [ 3579 + "errno", 3570 3580 "libc", 3571 3581 ] 3572 3582 ··· 3582 3592 3583 3593 [[package]] 3584 3594 name = "simd-adler32" 3585 - version = "0.3.7" 3595 + version = "0.3.8" 3586 3596 source = "registry+https://github.com/rust-lang/crates.io-index" 3587 - checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 3597 + checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" 3588 3598 3589 3599 [[package]] 3590 3600 name = "siphasher" ··· 3719 3729 3720 3730 [[package]] 3721 3731 name = "supports-hyperlinks" 3722 - version = "3.1.0" 3732 + version = "3.2.0" 3723 3733 source = "registry+https://github.com/rust-lang/crates.io-index" 3724 - checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" 3734 + checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" 3725 3735 3726 3736 [[package]] 3727 3737 name = "supports-unicode" ··· 3742 3752 3743 3753 [[package]] 3744 3754 name = "syn" 3745 - version = "2.0.111" 3755 + version = "2.0.113" 3746 3756 source = "registry+https://github.com/rust-lang/crates.io-index" 3747 - checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" 3757 + checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4" 3748 3758 dependencies = [ 3749 3759 "proc-macro2", 3750 3760 "quote", ··· 3768 3778 dependencies = [ 3769 3779 "proc-macro2", 3770 3780 "quote", 3771 - "syn 2.0.111", 3781 + "syn 2.0.113", 3772 3782 ] 3773 3783 3774 3784 [[package]] ··· 3800 3810 3801 3811 [[package]] 3802 3812 name = "tempfile" 3803 - version = "3.23.0" 3813 + version = "3.24.0" 3804 3814 source = "registry+https://github.com/rust-lang/crates.io-index" 3805 - checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" 3815 + checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" 3806 3816 dependencies = [ 3807 3817 "fastrand", 3808 3818 "getrandom 0.3.4", ··· 3868 3878 dependencies = [ 3869 3879 "proc-macro2", 3870 3880 "quote", 3871 - "syn 2.0.111", 3881 + "syn 2.0.113", 3872 3882 ] 3873 3883 3874 3884 [[package]] ··· 3879 3889 dependencies = [ 3880 3890 "proc-macro2", 3881 3891 "quote", 3882 - "syn 2.0.111", 3892 + "syn 2.0.113", 3883 3893 ] 3884 3894 3885 3895 [[package]] ··· 3960 3970 3961 3971 [[package]] 3962 3972 name = "tokio" 3963 - version = "1.48.0" 3973 + version = "1.49.0" 3964 3974 source = "registry+https://github.com/rust-lang/crates.io-index" 3965 - checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" 3975 + checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" 3966 3976 dependencies = [ 3967 3977 "bytes", 3968 3978 "libc", ··· 3983 3993 dependencies = [ 3984 3994 "proc-macro2", 3985 3995 "quote", 3986 - "syn 2.0.111", 3996 + "syn 2.0.113", 3987 3997 ] 3988 3998 3989 3999 [[package]] ··· 4033 4043 4034 4044 [[package]] 4035 4045 name = "tokio-util" 4036 - version = "0.7.17" 4046 + version = "0.7.18" 4037 4047 source = "registry+https://github.com/rust-lang/crates.io-index" 4038 - checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" 4048 + checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" 4039 4049 dependencies = [ 4040 4050 "bytes", 4041 4051 "futures-core", ··· 4063 4073 4064 4074 [[package]] 4065 4075 name = "tower-http" 4066 - version = "0.6.7" 4076 + version = "0.6.8" 4067 4077 source = "registry+https://github.com/rust-lang/crates.io-index" 4068 - checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" 4078 + checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" 4069 4079 dependencies = [ 4070 4080 "async-compression", 4071 4081 "bitflags", ··· 4104 4114 4105 4115 [[package]] 4106 4116 name = "tracing" 4107 - version = "0.1.41" 4117 + version = "0.1.44" 4108 4118 source = "registry+https://github.com/rust-lang/crates.io-index" 4109 - checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 4119 + checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 4110 4120 dependencies = [ 4111 4121 "log", 4112 4122 "pin-project-lite", ··· 4116 4126 4117 4127 [[package]] 4118 4128 name = "tracing-attributes" 4119 - version = "0.1.30" 4129 + version = "0.1.31" 4120 4130 source = "registry+https://github.com/rust-lang/crates.io-index" 4121 - checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 4131 + checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" 4122 4132 dependencies = [ 4123 4133 "proc-macro2", 4124 4134 "quote", 4125 - "syn 2.0.111", 4135 + "syn 2.0.113", 4126 4136 ] 4127 4137 4128 4138 [[package]] 4129 4139 name = "tracing-core" 4130 - version = "0.1.34" 4140 + version = "0.1.36" 4131 4141 source = "registry+https://github.com/rust-lang/crates.io-index" 4132 - checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 4142 + checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" 4133 4143 dependencies = [ 4134 4144 "once_cell", 4135 4145 "valuable", ··· 4148 4158 4149 4159 [[package]] 4150 4160 name = "tracing-subscriber" 4151 - version = "0.3.20" 4161 + version = "0.3.22" 4152 4162 source = "registry+https://github.com/rust-lang/crates.io-index" 4153 - checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" 4163 + checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" 4154 4164 dependencies = [ 4155 4165 "matchers", 4156 4166 "nu-ansi-term", ··· 4172 4182 dependencies = [ 4173 4183 "proc-macro2", 4174 4184 "quote", 4175 - "syn 2.0.111", 4185 + "syn 2.0.113", 4176 4186 ] 4177 4187 4178 4188 [[package]] ··· 4224 4234 4225 4235 [[package]] 4226 4236 name = "unicase" 4227 - version = "2.8.1" 4237 + version = "2.9.0" 4228 4238 source = "registry+https://github.com/rust-lang/crates.io-index" 4229 - checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 4239 + checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" 4230 4240 4231 4241 [[package]] 4232 4242 name = "unicode-ident" ··· 4278 4288 4279 4289 [[package]] 4280 4290 name = "url" 4281 - version = "2.5.7" 4291 + version = "2.5.8" 4282 4292 source = "registry+https://github.com/rust-lang/crates.io-index" 4283 - checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 4293 + checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" 4284 4294 dependencies = [ 4285 4295 "form_urlencoded", 4286 4296 "idna", 4287 4297 "percent-encoding", 4288 4298 "serde", 4299 + "serde_derive", 4289 4300 ] 4290 4301 4291 4302 [[package]] ··· 4360 4371 4361 4372 [[package]] 4362 4373 name = "wasm-bindgen" 4363 - version = "0.2.105" 4374 + version = "0.2.106" 4364 4375 source = "registry+https://github.com/rust-lang/crates.io-index" 4365 - checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" 4376 + checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 4366 4377 dependencies = [ 4367 4378 "cfg-if", 4368 4379 "once_cell", ··· 4373 4384 4374 4385 [[package]] 4375 4386 name = "wasm-bindgen-futures" 4376 - version = "0.4.55" 4387 + version = "0.4.56" 4377 4388 source = "registry+https://github.com/rust-lang/crates.io-index" 4378 - checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" 4389 + checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" 4379 4390 dependencies = [ 4380 4391 "cfg-if", 4381 4392 "js-sys", ··· 4386 4397 4387 4398 [[package]] 4388 4399 name = "wasm-bindgen-macro" 4389 - version = "0.2.105" 4400 + version = "0.2.106" 4390 4401 source = "registry+https://github.com/rust-lang/crates.io-index" 4391 - checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" 4402 + checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" 4392 4403 dependencies = [ 4393 4404 "quote", 4394 4405 "wasm-bindgen-macro-support", ··· 4396 4407 4397 4408 [[package]] 4398 4409 name = "wasm-bindgen-macro-support" 4399 - version = "0.2.105" 4410 + version = "0.2.106" 4400 4411 source = "registry+https://github.com/rust-lang/crates.io-index" 4401 - checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" 4412 + checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" 4402 4413 dependencies = [ 4403 4414 "bumpalo", 4404 4415 "proc-macro2", 4405 4416 "quote", 4406 - "syn 2.0.111", 4417 + "syn 2.0.113", 4407 4418 "wasm-bindgen-shared", 4408 4419 ] 4409 4420 4410 4421 [[package]] 4411 4422 name = "wasm-bindgen-shared" 4412 - version = "0.2.105" 4423 + version = "0.2.106" 4413 4424 source = "registry+https://github.com/rust-lang/crates.io-index" 4414 - checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" 4425 + checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" 4415 4426 dependencies = [ 4416 4427 "unicode-ident", 4417 4428 ] ··· 4431 4442 4432 4443 [[package]] 4433 4444 name = "web-sys" 4434 - version = "0.3.82" 4445 + version = "0.3.83" 4435 4446 source = "registry+https://github.com/rust-lang/crates.io-index" 4436 - checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" 4447 + checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" 4437 4448 dependencies = [ 4438 4449 "js-sys", 4439 4450 "wasm-bindgen", ··· 4479 4490 4480 4491 [[package]] 4481 4492 name = "webpki-roots" 4482 - version = "1.0.4" 4493 + version = "1.0.5" 4483 4494 source = "registry+https://github.com/rust-lang/crates.io-index" 4484 - checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" 4495 + checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" 4485 4496 dependencies = [ 4486 4497 "rustls-pki-types", 4487 4498 ] ··· 4499 4510 checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" 4500 4511 dependencies = [ 4501 4512 "windows-sys 0.61.2", 4502 - ] 4503 - 4504 - [[package]] 4505 - name = "windows" 4506 - version = "0.61.3" 4507 - source = "registry+https://github.com/rust-lang/crates.io-index" 4508 - checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" 4509 - dependencies = [ 4510 - "windows-collections", 4511 - "windows-core 0.61.2", 4512 - "windows-future", 4513 - "windows-link 0.1.3", 4514 - "windows-numerics", 4515 - ] 4516 - 4517 - [[package]] 4518 - name = "windows-collections" 4519 - version = "0.2.0" 4520 - source = "registry+https://github.com/rust-lang/crates.io-index" 4521 - checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" 4522 - dependencies = [ 4523 - "windows-core 0.61.2", 4524 - ] 4525 - 4526 - [[package]] 4527 - name = "windows-core" 4528 - version = "0.61.2" 4529 - source = "registry+https://github.com/rust-lang/crates.io-index" 4530 - checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" 4531 - dependencies = [ 4532 - "windows-implement", 4533 - "windows-interface", 4534 - "windows-link 0.1.3", 4535 - "windows-result 0.3.4", 4536 - "windows-strings 0.4.2", 4537 4513 ] 4538 4514 4539 4515 [[package]] ··· 4544 4520 dependencies = [ 4545 4521 "windows-implement", 4546 4522 "windows-interface", 4547 - "windows-link 0.2.1", 4548 - "windows-result 0.4.1", 4549 - "windows-strings 0.5.1", 4550 - ] 4551 - 4552 - [[package]] 4553 - name = "windows-future" 4554 - version = "0.2.1" 4555 - source = "registry+https://github.com/rust-lang/crates.io-index" 4556 - checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" 4557 - dependencies = [ 4558 - "windows-core 0.61.2", 4559 - "windows-link 0.1.3", 4560 - "windows-threading", 4523 + "windows-link", 4524 + "windows-result", 4525 + "windows-strings", 4561 4526 ] 4562 4527 4563 4528 [[package]] ··· 4568 4533 dependencies = [ 4569 4534 "proc-macro2", 4570 4535 "quote", 4571 - "syn 2.0.111", 4536 + "syn 2.0.113", 4572 4537 ] 4573 4538 4574 4539 [[package]] ··· 4579 4544 dependencies = [ 4580 4545 "proc-macro2", 4581 4546 "quote", 4582 - "syn 2.0.111", 4547 + "syn 2.0.113", 4583 4548 ] 4584 4549 4585 4550 [[package]] 4586 4551 name = "windows-link" 4587 - version = "0.1.3" 4588 - source = "registry+https://github.com/rust-lang/crates.io-index" 4589 - checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 4590 - 4591 - [[package]] 4592 - name = "windows-link" 4593 4552 version = "0.2.1" 4594 4553 source = "registry+https://github.com/rust-lang/crates.io-index" 4595 4554 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 4596 4555 4597 4556 [[package]] 4598 - name = "windows-numerics" 4599 - version = "0.2.0" 4600 - source = "registry+https://github.com/rust-lang/crates.io-index" 4601 - checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" 4602 - dependencies = [ 4603 - "windows-core 0.61.2", 4604 - "windows-link 0.1.3", 4605 - ] 4606 - 4607 - [[package]] 4608 4557 name = "windows-registry" 4609 4558 version = "0.6.1" 4610 4559 source = "registry+https://github.com/rust-lang/crates.io-index" 4611 4560 checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 4612 4561 dependencies = [ 4613 - "windows-link 0.2.1", 4614 - "windows-result 0.4.1", 4615 - "windows-strings 0.5.1", 4616 - ] 4617 - 4618 - [[package]] 4619 - name = "windows-result" 4620 - version = "0.3.4" 4621 - source = "registry+https://github.com/rust-lang/crates.io-index" 4622 - checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" 4623 - dependencies = [ 4624 - "windows-link 0.1.3", 4562 + "windows-link", 4563 + "windows-result", 4564 + "windows-strings", 4625 4565 ] 4626 4566 4627 4567 [[package]] ··· 4630 4570 source = "registry+https://github.com/rust-lang/crates.io-index" 4631 4571 checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 4632 4572 dependencies = [ 4633 - "windows-link 0.2.1", 4634 - ] 4635 - 4636 - [[package]] 4637 - name = "windows-strings" 4638 - version = "0.4.2" 4639 - source = "registry+https://github.com/rust-lang/crates.io-index" 4640 - checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" 4641 - dependencies = [ 4642 - "windows-link 0.1.3", 4573 + "windows-link", 4643 4574 ] 4644 4575 4645 4576 [[package]] ··· 4648 4579 source = "registry+https://github.com/rust-lang/crates.io-index" 4649 4580 checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 4650 4581 dependencies = [ 4651 - "windows-link 0.2.1", 4582 + "windows-link", 4652 4583 ] 4653 4584 4654 4585 [[package]] ··· 4702 4633 source = "registry+https://github.com/rust-lang/crates.io-index" 4703 4634 checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 4704 4635 dependencies = [ 4705 - "windows-link 0.2.1", 4636 + "windows-link", 4706 4637 ] 4707 4638 4708 4639 [[package]] ··· 4757 4688 source = "registry+https://github.com/rust-lang/crates.io-index" 4758 4689 checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 4759 4690 dependencies = [ 4760 - "windows-link 0.2.1", 4691 + "windows-link", 4761 4692 "windows_aarch64_gnullvm 0.53.1", 4762 4693 "windows_aarch64_msvc 0.53.1", 4763 4694 "windows_i686_gnu 0.53.1", ··· 4766 4697 "windows_x86_64_gnu 0.53.1", 4767 4698 "windows_x86_64_gnullvm 0.53.1", 4768 4699 "windows_x86_64_msvc 0.53.1", 4769 - ] 4770 - 4771 - [[package]] 4772 - name = "windows-threading" 4773 - version = "0.1.0" 4774 - source = "registry+https://github.com/rust-lang/crates.io-index" 4775 - checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" 4776 - dependencies = [ 4777 - "windows-link 0.1.3", 4778 4700 ] 4779 4701 4780 4702 [[package]] ··· 5067 4989 dependencies = [ 5068 4990 "proc-macro2", 5069 4991 "quote", 5070 - "syn 2.0.111", 4992 + "syn 2.0.113", 5071 4993 "synstructure", 5072 4994 ] 5073 4995 5074 4996 [[package]] 5075 4997 name = "zerocopy" 5076 - version = "0.8.30" 4998 + version = "0.8.32" 5077 4999 source = "registry+https://github.com/rust-lang/crates.io-index" 5078 - checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" 5000 + checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56" 5079 5001 dependencies = [ 5080 5002 "zerocopy-derive", 5081 5003 ] 5082 5004 5083 5005 [[package]] 5084 5006 name = "zerocopy-derive" 5085 - version = "0.8.30" 5007 + version = "0.8.32" 5086 5008 source = "registry+https://github.com/rust-lang/crates.io-index" 5087 - checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" 5009 + checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90" 5088 5010 dependencies = [ 5089 5011 "proc-macro2", 5090 5012 "quote", 5091 - "syn 2.0.111", 5013 + "syn 2.0.113", 5092 5014 ] 5093 5015 5094 5016 [[package]] ··· 5108 5030 dependencies = [ 5109 5031 "proc-macro2", 5110 5032 "quote", 5111 - "syn 2.0.111", 5033 + "syn 2.0.113", 5112 5034 "synstructure", 5113 5035 ] 5114 5036 ··· 5151 5073 dependencies = [ 5152 5074 "proc-macro2", 5153 5075 "quote", 5154 - "syn 2.0.111", 5076 + "syn 2.0.113", 5155 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"
+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 + }
+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:
+6 -6
docs/src/content/docs/cli.md
··· 136 136 # Pull a site to a specific directory 137 137 wisp-cli pull your-handle.bsky.social \ 138 138 --site my-site \ 139 - --output ./my-site 139 + --path ./my-site 140 140 141 141 # Pull to current directory 142 142 wisp-cli pull your-handle.bsky.social \ ··· 233 233 ### Pull Command 234 234 235 235 ```bash 236 - wisp-cli pull [OPTIONS] <INPUT> 236 + wisp-cli pull [OPTIONS] --site <SITE> <INPUT> 237 237 238 238 Arguments: 239 239 <INPUT> Handle or DID 240 240 241 241 Options: 242 242 -s, --site <SITE> Site name to download 243 - -o, --output <OUTPUT> Output directory [default: .] 243 + -p, --path <PATH> Output directory [default: .] 244 244 -h, --help Print help 245 245 ``` 246 246 247 247 ### Serve Command 248 248 249 249 ```bash 250 - wisp-cli serve [OPTIONS] <INPUT> 250 + wisp-cli serve [OPTIONS] --site <SITE> <INPUT> 251 251 252 252 Arguments: 253 253 <INPUT> Handle or DID 254 254 255 255 Options: 256 256 -s, --site <SITE> Site name to serve 257 - -o, --output <OUTPUT> Site files directory [default: .] 258 - -p, --port <PORT> Port to serve on [default: 8080] 257 + -p, --path <PATH> Site files directory [default: .] 258 + -P, --port <PORT> Port to serve on [default: 8080] 259 259 --spa Enable SPA mode (serve index.html for all routes) 260 260 --directory Enable directory listing mode for paths without index files 261 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 - }
+2 -2
packages/@wisp/observability/src/exporters.ts
··· 3 3 * Integrates with Grafana Loki for logs and Prometheus/OTLP for metrics 4 4 */ 5 5 6 - import { LogEntry, ErrorEntry, MetricEntry } from './core' 7 - import { metrics, MeterProvider } from '@opentelemetry/api' 6 + import type { LogEntry, ErrorEntry, MetricEntry } from './core' 7 + import { metrics, type MeterProvider } from '@opentelemetry/api' 8 8 import { MeterProvider as SdkMeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics' 9 9 import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http' 10 10 import { Resource } from '@opentelemetry/resources'