+72
.env.grafana.example
+72
.env.grafana.example
···
1
+
# Grafana Cloud Configuration for wisp.place monorepo
2
+
# Copy these variables to your .env file to enable Grafana integration
3
+
# The observability package will automatically pick up these environment variables
4
+
5
+
# ============================================================================
6
+
# Grafana Loki (for logs)
7
+
# ============================================================================
8
+
# Get this from your Grafana Cloud portal under Loki โ Details
9
+
# Example: https://logs-prod-012.grafana.net
10
+
GRAFANA_LOKI_URL=https://logs-prod-xxx.grafana.net
11
+
12
+
# Authentication Option 1: Bearer Token (Grafana Cloud)
13
+
GRAFANA_LOKI_TOKEN=glc_xxx
14
+
15
+
# Authentication Option 2: Username/Password (Self-hosted or some Grafana setups)
16
+
# GRAFANA_LOKI_USERNAME=your-username
17
+
# GRAFANA_LOKI_PASSWORD=your-password
18
+
19
+
# ============================================================================
20
+
# Grafana Prometheus (for metrics)
21
+
# ============================================================================
22
+
# Get this from your Grafana Cloud portal under Prometheus โ Details
23
+
# Note: You need to add /api/prom to the base URL for OTLP export
24
+
# Example: https://prometheus-prod-10-prod-us-central-0.grafana.net/api/prom
25
+
GRAFANA_PROMETHEUS_URL=https://prometheus-prod-xxx.grafana.net/api/prom
26
+
27
+
# Authentication Option 1: Bearer Token (Grafana Cloud)
28
+
GRAFANA_PROMETHEUS_TOKEN=glc_xxx
29
+
30
+
# Authentication Option 2: Username/Password (Self-hosted or some Grafana setups)
31
+
# GRAFANA_PROMETHEUS_USERNAME=your-username
32
+
# GRAFANA_PROMETHEUS_PASSWORD=your-password
33
+
34
+
# ============================================================================
35
+
# Optional Configuration
36
+
# ============================================================================
37
+
# These will be used by both main-app and hosting-service if not overridden
38
+
39
+
# Service metadata (optional - defaults are provided in code)
40
+
# SERVICE_NAME=wisp-app
41
+
# SERVICE_VERSION=1.0.0
42
+
43
+
# Batching configuration (optional)
44
+
# GRAFANA_BATCH_SIZE=100 # Flush after this many entries
45
+
# GRAFANA_FLUSH_INTERVAL=5000 # Flush every 5 seconds
46
+
47
+
# ============================================================================
48
+
# How to get these values:
49
+
# ============================================================================
50
+
# 1. Sign up for Grafana Cloud at https://grafana.com/
51
+
# 2. Go to your Grafana Cloud portal
52
+
# 3. For Loki:
53
+
# - Navigate to "Connections" โ "Loki"
54
+
# - Click "Details"
55
+
# - Copy the Push endpoint URL (without /loki/api/v1/push)
56
+
# - Create an API token with push permissions
57
+
# 4. For Prometheus:
58
+
# - Navigate to "Connections" โ "Prometheus"
59
+
# - Click "Details"
60
+
# - Copy the Remote Write endpoint (add /api/prom for OTLP)
61
+
# - Create an API token with write permissions
62
+
63
+
# ============================================================================
64
+
# Testing the integration:
65
+
# ============================================================================
66
+
# 1. Copy this file's contents to your .env file
67
+
# 2. Fill in the actual values
68
+
# 3. Restart your services (main-app and hosting-service)
69
+
# 4. Check your Grafana Cloud dashboard for incoming data
70
+
# 5. Use Grafana Explore to query:
71
+
# - Loki: {job="main-app"} or {job="hosting-service"}
72
+
# - Prometheus: http_requests_total{service="main-app"}
+1
.gitignore
+1
.gitignore
+2
.tangled/workflows/deploy-wisp.yml
+2
.tangled/workflows/deploy-wisp.yml
+2
-1
.tangled/workflows/test.yml
+2
-1
.tangled/workflows/test.yml
···
7
7
dependencies:
8
8
nixpkgs:
9
9
- git
10
+
- findutils
10
11
github:NixOS/nixpkgs/nixpkgs-unstable:
11
12
- bun
12
13
···
16
17
export PATH="$HOME/.nix-profile/bin:$PATH"
17
18
18
19
# have to regenerate otherwise it wont install necessary dependencies to run
19
-
rm -rf bun.lock package-lock.json
20
+
find . -type f \( -name "bun.lock" -o -name "package-lock.json" \) -delete
20
21
bun install
21
22
22
23
- name: run all tests
+15
-58
Dockerfile
+15
-58
Dockerfile
···
1
-
# Build stage
2
-
FROM oven/bun:1.3 AS build
1
+
# Production stage
2
+
FROM oven/bun:1.3
3
3
4
4
WORKDIR /app
5
5
···
7
7
COPY package.json bunfig.toml tsconfig.json bun.lock* ./
8
8
9
9
# Copy all workspace package.json files first (for dependency resolution)
10
-
COPY packages ./packages
10
+
COPY packages/@wisp/atproto-utils/package.json ./packages/@wisp/atproto-utils/package.json
11
+
COPY packages/@wisp/constants/package.json ./packages/@wisp/constants/package.json
12
+
COPY packages/@wisp/database/package.json ./packages/@wisp/database/package.json
13
+
COPY packages/@wisp/fs-utils/package.json ./packages/@wisp/fs-utils/package.json
14
+
COPY packages/@wisp/lexicons/package.json ./packages/@wisp/lexicons/package.json
15
+
COPY packages/@wisp/observability/package.json ./packages/@wisp/observability/package.json
16
+
COPY packages/@wisp/safe-fetch/package.json ./packages/@wisp/safe-fetch/package.json
11
17
COPY apps/main-app/package.json ./apps/main-app/package.json
12
18
COPY apps/hosting-service/package.json ./apps/hosting-service/package.json
13
19
14
-
# Install all dependencies (including workspaces)
15
-
RUN bun install --frozen-lockfile
20
+
# Install dependencies
21
+
RUN bun install --frozen-lockfile --production
16
22
17
-
# Copy source files
18
-
COPY apps/main-app ./apps/main-app
19
-
20
-
# Build compiled server
21
-
RUN bun build \
22
-
--compile \
23
-
--target bun \
24
-
--minify \
25
-
--outfile server \
26
-
apps/main-app/src/index.ts
27
-
28
-
# Production dependencies stage
29
-
FROM oven/bun:1.3 AS prod-deps
30
-
31
-
WORKDIR /app
32
-
33
-
COPY package.json bunfig.toml tsconfig.json bun.lock* ./
23
+
# Copy workspace source files
34
24
COPY packages ./packages
35
-
COPY apps/main-app/package.json ./apps/main-app/package.json
36
-
COPY apps/hosting-service/package.json ./apps/hosting-service/package.json
37
25
38
-
# Install only production dependencies
39
-
RUN bun install --frozen-lockfile --production
40
-
41
-
# Remove unnecessary large packages (bun is already in base image, these are dev tools)
42
-
RUN rm -rf /app/node_modules/bun \
43
-
/app/node_modules/@oven \
44
-
/app/node_modules/prettier \
45
-
/app/node_modules/@ts-morph
46
-
47
-
# Final stage - use distroless or slim debian-based image
48
-
FROM debian:bookworm-slim
49
-
50
-
# Install Bun runtime
51
-
COPY --from=oven/bun:1.3 /usr/local/bin/bun /usr/local/bin/bun
52
-
53
-
WORKDIR /app
54
-
55
-
# Copy compiled server
56
-
COPY --from=build /app/server /app/server
57
-
58
-
# Copy public files
59
-
COPY apps/main-app/public apps/main-app/public
60
-
61
-
# Copy production dependencies only
62
-
COPY --from=prod-deps /app/node_modules /app/node_modules
63
-
64
-
# Copy configs
65
-
COPY package.json bunfig.toml tsconfig.json /app/
66
-
COPY apps/main-app/tsconfig.json /app/apps/main-app/tsconfig.json
67
-
COPY apps/main-app/package.json /app/apps/main-app/package.json
68
-
69
-
# Create symlink for module resolution
70
-
RUN ln -s /app/node_modules /app/apps/main-app/node_modules
26
+
# Copy app source and public files
27
+
COPY apps/main-app ./apps/main-app
71
28
72
29
ENV PORT=8000
73
30
74
31
EXPOSE 8000
75
32
76
-
CMD ["./server"]
33
+
CMD ["bun", "run", "apps/main-app/src/index.ts"]
+3
-3
README.md
+3
-3
README.md
+9
-8
apps/hosting-service/package.json
+9
-8
apps/hosting-service/package.json
···
10
10
"backfill": "tsx src/index.ts --backfill"
11
11
},
12
12
"dependencies": {
13
-
"@wisp/lexicons": "workspace:*",
14
-
"@wisp/constants": "workspace:*",
15
-
"@wisp/observability": "workspace:*",
16
-
"@wisp/atproto-utils": "workspace:*",
17
-
"@wisp/database": "workspace:*",
18
-
"@wisp/fs-utils": "workspace:*",
19
-
"@wisp/safe-fetch": "workspace:*",
20
13
"@atproto/api": "^0.17.4",
21
14
"@atproto/identity": "^0.4.9",
22
15
"@atproto/lexicon": "^0.5.2",
23
16
"@atproto/sync": "^0.1.36",
24
17
"@atproto/xrpc": "^0.7.5",
25
18
"@hono/node-server": "^1.19.6",
19
+
"@wisp/atproto-utils": "workspace:*",
20
+
"@wisp/constants": "workspace:*",
21
+
"@wisp/database": "workspace:*",
22
+
"@wisp/fs-utils": "workspace:*",
23
+
"@wisp/lexicons": "workspace:*",
24
+
"@wisp/observability": "workspace:*",
25
+
"@wisp/safe-fetch": "workspace:*",
26
26
"hono": "^4.10.4",
27
27
"mime-types": "^2.1.35",
28
28
"multiformats": "^13.4.1",
29
-
"postgres": "^3.4.5"
29
+
"postgres": "^3.4.5",
30
+
"tiered-storage": "1.0.3"
30
31
},
31
32
"devDependencies": {
32
33
"@types/bun": "^1.3.1",
+46
-6
apps/hosting-service/src/index.ts
+46
-6
apps/hosting-service/src/index.ts
···
1
1
import app from './server';
2
2
import { serve } from '@hono/node-server';
3
3
import { FirehoseWorker } from './lib/firehose';
4
-
import { createLogger } from '@wisp/observability';
4
+
import { createLogger, initializeGrafanaExporters } from '@wisp/observability';
5
5
import { mkdirSync, existsSync } from 'fs';
6
6
import { backfillCache } from './lib/backfill';
7
-
import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode } from './lib/db';
7
+
import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode, closeDatabase } from './lib/db';
8
+
import { storage, getStorageConfig } from './lib/storage';
9
+
10
+
// Initialize Grafana exporters if configured
11
+
initializeGrafanaExporters({
12
+
serviceName: 'hosting-service',
13
+
serviceVersion: '1.0.0'
14
+
});
8
15
9
16
const logger = createLogger('hosting-service');
10
17
11
18
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3001;
12
19
const CACHE_DIR = process.env.CACHE_DIR || './cache/sites';
20
+
const BACKFILL_CONCURRENCY = process.env.BACKFILL_CONCURRENCY
21
+
? parseInt(process.env.BACKFILL_CONCURRENCY)
22
+
: undefined; // Let backfill.ts default (10) apply
13
23
14
24
// Parse CLI arguments
15
25
const args = process.argv.slice(2);
···
41
51
42
52
firehose.start();
43
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
+
44
69
// Run backfill if requested
45
70
if (backfillOnStartup) {
46
71
console.log('๐ Backfill requested, starting cache backfill...');
47
72
backfillCache({
48
73
skipExisting: true,
49
-
concurrency: 3,
74
+
concurrency: BACKFILL_CONCURRENCY,
50
75
}).then((stats) => {
51
76
console.log('โ
Cache backfill completed');
52
77
}).catch((err) => {
···
69
94
port: PORT,
70
95
});
71
96
97
+
// Get storage configuration for display
98
+
const storageConfig = getStorageConfig();
99
+
72
100
console.log(`
73
-
Wisp Hosting Service
101
+
Wisp Hosting Service with Tiered Storage
74
102
75
103
Server: http://localhost:${PORT}
76
104
Health: http://localhost:${PORT}/health
77
-
Cache: ${CACHE_DIR}
78
-
Firehose: Connected to Firehose
79
105
Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'}
106
+
Backfill: ${backfillOnStartup ? `ENABLED (concurrency: ${BACKFILL_CONCURRENCY || 10})` : 'DISABLED'}
107
+
108
+
Tiered Storage Configuration:
109
+
Hot Cache: ${storageConfig.hotCacheSize} (${storageConfig.hotCacheCount} items max)
110
+
Warm Cache: ${storageConfig.warmCacheSize} (${storageConfig.warmEvictionPolicy} eviction)
111
+
Cold Storage: S3 - ${storageConfig.s3Bucket}
112
+
S3 Region: ${storageConfig.s3Region}
113
+
S3 Endpoint: ${storageConfig.s3Endpoint}
114
+
S3 Prefix: ${storageConfig.s3Prefix}
115
+
Metadata Bucket: ${storageConfig.metadataBucket}
116
+
117
+
Firehose: Connecting...
80
118
`);
81
119
82
120
// Graceful shutdown
···
84
122
console.log('\n๐ Shutting down...');
85
123
firehose.stop();
86
124
stopDomainCacheCleanup();
125
+
await closeDatabase();
87
126
server.close();
88
127
process.exit(0);
89
128
});
···
92
131
console.log('\n๐ Shutting down...');
93
132
firehose.stop();
94
133
stopDomainCacheCleanup();
134
+
await closeDatabase();
95
135
server.close();
96
136
process.exit(0);
97
137
});
+65
-57
apps/hosting-service/src/lib/backfill.ts
+65
-57
apps/hosting-service/src/lib/backfill.ts
···
60
60
console.log(`โ๏ธ Limited to ${maxSites} sites for backfill`);
61
61
}
62
62
63
-
// Process sites in batches
64
-
const batches: typeof sites[] = [];
65
-
for (let i = 0; i < sites.length; i += concurrency) {
66
-
batches.push(sites.slice(i, i + concurrency));
67
-
}
68
-
63
+
// Process sites with sliding window concurrency pool
64
+
const executing = new Set<Promise<void>>();
69
65
let processed = 0;
70
-
for (const batch of batches) {
71
-
await Promise.all(
72
-
batch.map(async (site) => {
73
-
try {
74
-
// Check if already cached
75
-
if (skipExisting && isCached(site.did, site.rkey)) {
76
-
stats.skipped++;
77
-
processed++;
78
-
logger.debug(`Skipping already cached site`, { did: site.did, rkey: site.rkey });
79
-
console.log(`โญ๏ธ [${processed}/${sites.length}] Skipped (cached): ${site.display_name || site.rkey}`);
80
-
return;
81
-
}
82
66
83
-
// Fetch site record
84
-
const siteData = await fetchSiteRecord(site.did, site.rkey);
85
-
if (!siteData) {
86
-
stats.failed++;
87
-
processed++;
88
-
logger.error('Site record not found during backfill', null, { did: site.did, rkey: site.rkey });
89
-
console.log(`โ [${processed}/${sites.length}] Failed (not found): ${site.display_name || site.rkey}`);
90
-
return;
91
-
}
92
-
93
-
// Get PDS endpoint
94
-
const pdsEndpoint = await getPdsForDid(site.did);
95
-
if (!pdsEndpoint) {
96
-
stats.failed++;
97
-
processed++;
98
-
logger.error('PDS not found during backfill', null, { did: site.did });
99
-
console.log(`โ [${processed}/${sites.length}] Failed (no PDS): ${site.display_name || site.rkey}`);
100
-
return;
101
-
}
67
+
for (const site of sites) {
68
+
// Create task for this site
69
+
const processSite = async () => {
70
+
try {
71
+
// Check if already cached
72
+
if (skipExisting && await isCached(site.did, site.rkey)) {
73
+
stats.skipped++;
74
+
processed++;
75
+
logger.debug(`Skipping already cached site`, { did: site.did, rkey: site.rkey });
76
+
console.log(`โญ๏ธ [${processed}/${sites.length}] Skipped (cached): ${site.display_name || site.rkey}`);
77
+
return;
78
+
}
102
79
103
-
// Mark site as being cached to prevent serving stale content during update
104
-
markSiteAsBeingCached(site.did, site.rkey);
80
+
// Fetch site record
81
+
const siteData = await fetchSiteRecord(site.did, site.rkey);
82
+
if (!siteData) {
83
+
stats.failed++;
84
+
processed++;
85
+
logger.error('Site record not found during backfill', null, { did: site.did, rkey: site.rkey });
86
+
console.log(`โ [${processed}/${sites.length}] Failed (not found): ${site.display_name || site.rkey}`);
87
+
return;
88
+
}
105
89
106
-
try {
107
-
// Download and cache site
108
-
await downloadAndCacheSite(site.did, site.rkey, siteData.record, pdsEndpoint, siteData.cid);
109
-
// Clear redirect rules cache since the site was updated
110
-
clearRedirectRulesCache(site.did, site.rkey);
111
-
stats.cached++;
112
-
processed++;
113
-
logger.info('Successfully cached site during backfill', { did: site.did, rkey: site.rkey });
114
-
console.log(`โ
[${processed}/${sites.length}] Cached: ${site.display_name || site.rkey}`);
115
-
} finally {
116
-
// Always unmark, even if caching fails
117
-
unmarkSiteAsBeingCached(site.did, site.rkey);
118
-
}
119
-
} catch (err) {
90
+
// Get PDS endpoint
91
+
const pdsEndpoint = await getPdsForDid(site.did);
92
+
if (!pdsEndpoint) {
120
93
stats.failed++;
121
94
processed++;
122
-
logger.error('Failed to cache site during backfill', err, { did: site.did, rkey: site.rkey });
123
-
console.log(`โ [${processed}/${sites.length}] Failed: ${site.display_name || site.rkey}`);
95
+
logger.error('PDS not found during backfill', null, { did: site.did });
96
+
console.log(`โ [${processed}/${sites.length}] Failed (no PDS): ${site.display_name || site.rkey}`);
97
+
return;
98
+
}
99
+
100
+
// Mark site as being cached to prevent serving stale content during update
101
+
markSiteAsBeingCached(site.did, site.rkey);
102
+
103
+
try {
104
+
// Download and cache site
105
+
await downloadAndCacheSite(site.did, site.rkey, siteData.record, pdsEndpoint, siteData.cid);
106
+
// Clear redirect rules cache since the site was updated
107
+
clearRedirectRulesCache(site.did, site.rkey);
108
+
stats.cached++;
109
+
processed++;
110
+
logger.info('Successfully cached site during backfill', { did: site.did, rkey: site.rkey });
111
+
console.log(`โ
[${processed}/${sites.length}] Cached: ${site.display_name || site.rkey}`);
112
+
} finally {
113
+
// Always unmark, even if caching fails
114
+
unmarkSiteAsBeingCached(site.did, site.rkey);
124
115
}
125
-
})
126
-
);
116
+
} catch (err) {
117
+
stats.failed++;
118
+
processed++;
119
+
logger.error('Failed to cache site during backfill', err, { did: site.did, rkey: site.rkey });
120
+
console.log(`โ [${processed}/${sites.length}] Failed: ${site.display_name || site.rkey}`);
121
+
}
122
+
};
123
+
124
+
// Add to executing pool and remove when done
125
+
const promise = processSite().finally(() => executing.delete(promise));
126
+
executing.add(promise);
127
+
128
+
// When pool is full, wait for at least one to complete
129
+
if (executing.size >= concurrency) {
130
+
await Promise.race(executing);
131
+
}
127
132
}
133
+
134
+
// Wait for all remaining tasks to complete
135
+
await Promise.all(executing);
128
136
129
137
stats.duration = Date.now() - startTime;
130
138
+35
-43
apps/hosting-service/src/lib/cache.ts
+35
-43
apps/hosting-service/src/lib/cache.ts
···
1
-
// In-memory LRU cache for file contents and metadata
1
+
/**
2
+
* Cache management for wisp-hosting-service
3
+
*
4
+
* With tiered storage, most caching is handled transparently.
5
+
* This module tracks sites being cached and manages rewritten HTML cache.
6
+
*/
2
7
8
+
import { storage } from './storage';
9
+
10
+
// In-memory LRU cache for rewritten HTML (for path rewriting in subdomain routes)
3
11
interface CacheEntry<T> {
4
12
value: T;
5
13
size: number;
···
96
104
return true;
97
105
}
98
106
99
-
// Invalidate all entries for a specific site
100
-
invalidateSite(did: string, rkey: string): number {
101
-
const prefix = `${did}:${rkey}:`;
102
-
let count = 0;
103
-
104
-
for (const key of Array.from(this.cache.keys())) {
105
-
if (key.startsWith(prefix)) {
106
-
this.delete(key);
107
-
count++;
108
-
}
109
-
}
110
-
111
-
return count;
112
-
}
113
-
114
-
// Get cache size
115
107
size(): number {
116
108
return this.cache.size;
117
109
}
···
127
119
return { ...this.stats };
128
120
}
129
121
130
-
// Get cache hit rate
131
122
getHitRate(): number {
132
123
const total = this.stats.hits + this.stats.misses;
133
124
return total === 0 ? 0 : (this.stats.hits / total) * 100;
134
125
}
135
126
}
136
127
137
-
// File metadata cache entry
138
-
export interface FileMetadata {
139
-
encoding?: 'gzip';
140
-
mimeType: string;
141
-
}
142
-
143
-
// Global cache instances
144
-
const FILE_CACHE_SIZE = 100 * 1024 * 1024; // 100MB
145
-
const FILE_CACHE_COUNT = 500;
146
-
const METADATA_CACHE_COUNT = 2000;
147
-
148
-
export const fileCache = new LRUCache<Buffer>(FILE_CACHE_SIZE, FILE_CACHE_COUNT);
149
-
export const metadataCache = new LRUCache<FileMetadata>(1024 * 1024, METADATA_CACHE_COUNT); // 1MB for metadata
128
+
// Rewritten HTML cache: stores HTML after path rewriting for subdomain routes
150
129
export const rewrittenHtmlCache = new LRUCache<Buffer>(50 * 1024 * 1024, 200); // 50MB for rewritten HTML
151
130
152
-
// Helper to generate cache keys
131
+
// Helper to generate cache keys for rewritten HTML
153
132
export function getCacheKey(did: string, rkey: string, filePath: string, suffix?: string): string {
154
133
const base = `${did}:${rkey}:${filePath}`;
155
134
return suffix ? `${base}:${suffix}` : base;
156
135
}
157
136
158
-
// Invalidate all caches for a site
159
-
export function invalidateSiteCache(did: string, rkey: string): void {
160
-
const fileCount = fileCache.invalidateSite(did, rkey);
161
-
const metaCount = metadataCache.invalidateSite(did, rkey);
162
-
const htmlCount = rewrittenHtmlCache.invalidateSite(did, rkey);
137
+
/**
138
+
* Invalidate site cache via tiered storage
139
+
* Also invalidates locally cached rewritten HTML
140
+
*/
141
+
export async function invalidateSiteCache(did: string, rkey: string): Promise<void> {
142
+
// Invalidate in tiered storage
143
+
const prefix = `${did}/${rkey}/`;
144
+
const deleted = await storage.invalidate(prefix);
163
145
164
-
console.log(`[Cache] Invalidated site ${did}:${rkey} - ${fileCount} files, ${metaCount} metadata, ${htmlCount} HTML`);
146
+
// Invalidate rewritten HTML cache for this site
147
+
const sitePrefix = `${did}:${rkey}:`;
148
+
let htmlCount = 0;
149
+
const cacheKeys = Array.from((rewrittenHtmlCache as any).cache?.keys() || []) as string[];
150
+
for (const key of cacheKeys) {
151
+
if (key.startsWith(sitePrefix)) {
152
+
rewrittenHtmlCache.delete(key);
153
+
htmlCount++;
154
+
}
155
+
}
156
+
157
+
console.log(`[Cache] Invalidated site ${did}:${rkey} - ${deleted} files in tiered storage, ${htmlCount} rewritten HTML`);
165
158
}
166
159
167
160
// Track sites currently being cached (to prevent serving stale cache during updates)
···
183
176
}
184
177
185
178
// Get overall cache statistics
186
-
export function getCacheStats() {
179
+
export async function getCacheStats() {
180
+
const tieredStats = await storage.getStats();
181
+
187
182
return {
188
-
files: fileCache.getStats(),
189
-
fileHitRate: fileCache.getHitRate(),
190
-
metadata: metadataCache.getStats(),
191
-
metadataHitRate: metadataCache.getHitRate(),
183
+
tieredStorage: tieredStats,
192
184
rewrittenHtml: rewrittenHtmlCache.getStats(),
193
185
rewrittenHtmlHitRate: rewrittenHtmlCache.getHitRate(),
194
186
sitesBeingCached: sitesBeingCached.size,
+32
-1
apps/hosting-service/src/lib/db.ts
+32
-1
apps/hosting-service/src/lib/db.ts
···
183
183
return hashNum & 0x7FFFFFFFFFFFFFFFn;
184
184
}
185
185
186
+
// Track active locks for cleanup on shutdown
187
+
const activeLocks = new Set<string>();
188
+
186
189
/**
187
190
* Acquire a distributed lock using PostgreSQL advisory locks
188
191
* Returns true if lock was acquired, false if already held by another instance
···
193
196
194
197
try {
195
198
const result = await sql`SELECT pg_try_advisory_lock(${Number(lockId)}) as acquired`;
196
-
return result[0]?.acquired === true;
199
+
const acquired = result[0]?.acquired === true;
200
+
if (acquired) {
201
+
activeLocks.add(key);
202
+
}
203
+
return acquired;
197
204
} catch (err) {
198
205
console.error('Failed to acquire lock', { key, error: err });
199
206
return false;
···
208
215
209
216
try {
210
217
await sql`SELECT pg_advisory_unlock(${Number(lockId)})`;
218
+
activeLocks.delete(key);
211
219
} catch (err) {
212
220
console.error('Failed to release lock', { key, error: err });
221
+
// Still remove from tracking even if unlock fails
222
+
activeLocks.delete(key);
223
+
}
224
+
}
225
+
226
+
/**
227
+
* Close all database connections
228
+
* Call this during graceful shutdown
229
+
*/
230
+
export async function closeDatabase(): Promise<void> {
231
+
try {
232
+
// Release all active advisory locks before closing connections
233
+
if (activeLocks.size > 0) {
234
+
console.log(`[DB] Releasing ${activeLocks.size} active advisory locks before shutdown`);
235
+
for (const key of activeLocks) {
236
+
await releaseLock(key);
237
+
}
238
+
}
239
+
240
+
await sql.end({ timeout: 5 });
241
+
console.log('[DB] Database connections closed');
242
+
} catch (err) {
243
+
console.error('[DB] Error closing database connections:', err);
213
244
}
214
245
}
215
246
+64
-76
apps/hosting-service/src/lib/file-serving.ts
+64
-76
apps/hosting-service/src/lib/file-serving.ts
···
7
7
import { lookup } from 'mime-types';
8
8
import type { Record as WispSettings } from '@wisp/lexicons/types/place/wisp/settings';
9
9
import { shouldCompressMimeType } from '@wisp/atproto-utils/compression';
10
-
import { fileCache, metadataCache, rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache';
10
+
import { rewrittenHtmlCache, getCacheKey, isSiteBeingCached } from './cache';
11
11
import { getCachedFilePath, getCachedSettings } from './utils';
12
12
import { loadRedirectRules, matchRedirectRule, parseCookies, parseQueryString } from './redirects';
13
13
import { rewriteHtmlPaths, isHtmlContent } from './html-rewriter';
14
14
import { generate404Page, generateDirectoryListing, siteUpdatingResponse } from './page-generators';
15
15
import { getIndexFiles, applyCustomHeaders, fileExists } from './request-utils';
16
16
import { getRedirectRulesFromCache, setRedirectRulesInCache } from './site-cache';
17
+
import { storage } from './storage';
18
+
19
+
/**
20
+
* Helper to retrieve a file with metadata from tiered storage
21
+
*/
22
+
async function getFileWithMetadata(did: string, rkey: string, filePath: string) {
23
+
const key = `${did}/${rkey}/${filePath}`;
24
+
return await storage.getWithMetadata(key);
25
+
}
17
26
18
27
/**
19
28
* Helper to serve files from cache (for custom domains and subdomains)
···
176
185
177
186
// Not a directory, try to serve as a file
178
187
const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html';
179
-
const cacheKey = getCacheKey(did, rkey, fileRequestPath);
180
-
const cachedFile = getCachedFilePath(did, rkey, fileRequestPath);
181
188
182
-
// Check in-memory cache first
183
-
let content = fileCache.get(cacheKey);
184
-
let meta = metadataCache.get(cacheKey);
189
+
// Retrieve from tiered storage
190
+
const result = await getFileWithMetadata(did, rkey, fileRequestPath);
185
191
186
-
if (!content && await fileExists(cachedFile)) {
187
-
// Read from disk and cache
188
-
content = await readFile(cachedFile);
189
-
fileCache.set(cacheKey, content, content.length);
192
+
if (result) {
193
+
const content = Buffer.from(result.data);
194
+
const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
190
195
191
-
const metaFile = `${cachedFile}.meta`;
192
-
if (await fileExists(metaFile)) {
193
-
const metaJson = await readFile(metaFile, 'utf-8');
194
-
meta = JSON.parse(metaJson);
195
-
metadataCache.set(cacheKey, meta!, JSON.stringify(meta).length);
196
-
}
197
-
}
198
-
199
-
if (content) {
200
196
// Build headers with caching
201
-
const headers: Record<string, string> = {};
197
+
const headers: Record<string, string> = {
198
+
'X-Cache-Tier': result.source,
199
+
};
202
200
203
-
if (meta && meta.encoding === 'gzip' && meta.mimeType) {
201
+
if (meta?.encoding === 'gzip' && meta.mimeType) {
204
202
const shouldServeCompressed = shouldCompressMimeType(meta.mimeType);
205
203
206
204
if (!shouldServeCompressed) {
···
233
231
}
234
232
235
233
// Non-compressed files
236
-
const mimeType = lookup(cachedFile) || 'application/octet-stream';
234
+
const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream';
237
235
headers['Content-Type'] = mimeType;
238
236
headers['Cache-Control'] = mimeType.startsWith('text/html')
239
237
? 'public, max-age=300'
···
246
244
if (!fileRequestPath.includes('.')) {
247
245
for (const indexFileName of indexFiles) {
248
246
const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName;
249
-
const indexCacheKey = getCacheKey(did, rkey, indexPath);
250
-
const indexFile = getCachedFilePath(did, rkey, indexPath);
251
247
252
-
let indexContent = fileCache.get(indexCacheKey);
253
-
let indexMeta = metadataCache.get(indexCacheKey);
248
+
const indexResult = await getFileWithMetadata(did, rkey, indexPath);
254
249
255
-
if (!indexContent && await fileExists(indexFile)) {
256
-
indexContent = await readFile(indexFile);
257
-
fileCache.set(indexCacheKey, indexContent, indexContent.length);
250
+
if (indexResult) {
251
+
const indexContent = Buffer.from(indexResult.data);
252
+
const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
258
253
259
-
const indexMetaFile = `${indexFile}.meta`;
260
-
if (await fileExists(indexMetaFile)) {
261
-
const metaJson = await readFile(indexMetaFile, 'utf-8');
262
-
indexMeta = JSON.parse(metaJson);
263
-
metadataCache.set(indexCacheKey, indexMeta!, JSON.stringify(indexMeta).length);
264
-
}
265
-
}
266
-
267
-
if (indexContent) {
268
254
const headers: Record<string, string> = {
269
255
'Content-Type': 'text/html; charset=utf-8',
270
256
'Cache-Control': 'public, max-age=300',
257
+
'X-Cache-Tier': indexResult.source,
271
258
};
272
259
273
-
if (indexMeta && indexMeta.encoding === 'gzip') {
260
+
if (indexMeta?.encoding === 'gzip') {
274
261
headers['Content-Encoding'] = 'gzip';
275
262
}
276
263
···
556
543
557
544
// Not a directory, try to serve as a file
558
545
const fileRequestPath: string = requestPath || indexFiles[0] || 'index.html';
559
-
const cacheKey = getCacheKey(did, rkey, fileRequestPath);
560
-
const cachedFile = getCachedFilePath(did, rkey, fileRequestPath);
561
546
562
547
// Check for rewritten HTML in cache first (if it's HTML)
563
548
const mimeTypeGuess = lookup(fileRequestPath) || 'application/octet-stream';
···
565
550
const rewrittenKey = getCacheKey(did, rkey, fileRequestPath, `rewritten:${basePath}`);
566
551
const rewrittenContent = rewrittenHtmlCache.get(rewrittenKey);
567
552
if (rewrittenContent) {
553
+
console.log(`[HTML Rewrite] Serving from rewritten cache: ${rewrittenKey}`);
568
554
const headers: Record<string, string> = {
569
555
'Content-Type': 'text/html; charset=utf-8',
570
556
'Content-Encoding': 'gzip',
571
557
'Cache-Control': 'public, max-age=300',
558
+
'X-Cache-Tier': 'local', // Rewritten HTML is stored locally
572
559
};
573
560
applyCustomHeaders(headers, fileRequestPath, settings);
574
561
return new Response(rewrittenContent, { headers });
575
562
}
576
563
}
577
564
578
-
// Check in-memory file cache
579
-
let content = fileCache.get(cacheKey);
580
-
let meta = metadataCache.get(cacheKey);
565
+
// Retrieve from tiered storage
566
+
const result = await getFileWithMetadata(did, rkey, fileRequestPath);
581
567
582
-
if (!content && await fileExists(cachedFile)) {
583
-
// Read from disk and cache
584
-
content = await readFile(cachedFile);
585
-
fileCache.set(cacheKey, content, content.length);
568
+
if (result) {
569
+
const content = Buffer.from(result.data);
570
+
const meta = result.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
571
+
const mimeType = meta?.mimeType || lookup(fileRequestPath) || 'application/octet-stream';
572
+
const isGzipped = meta?.encoding === 'gzip';
586
573
587
-
const metaFile = `${cachedFile}.meta`;
588
-
if (await fileExists(metaFile)) {
589
-
const metaJson = await readFile(metaFile, 'utf-8');
590
-
meta = JSON.parse(metaJson);
591
-
metadataCache.set(cacheKey, meta!, JSON.stringify(meta).length);
592
-
}
593
-
}
594
-
595
-
if (content) {
596
-
const mimeType = meta?.mimeType || lookup(cachedFile) || 'application/octet-stream';
597
-
const isGzipped = meta?.encoding === 'gzip';
574
+
console.log(`[File Serve] Serving ${fileRequestPath}, mimeType: ${mimeType}, isHTML: ${isHtmlContent(fileRequestPath, mimeType)}, basePath: ${basePath}`);
598
575
599
576
// Check if this is HTML content that needs rewriting
600
577
if (isHtmlContent(fileRequestPath, mimeType)) {
578
+
console.log(`[HTML Rewrite] Processing ${fileRequestPath}, basePath: ${basePath}, mimeType: ${mimeType}, isGzipped: ${isGzipped}`);
601
579
let htmlContent: string;
602
580
if (isGzipped) {
603
581
// Verify content is actually gzipped
···
612
590
} else {
613
591
htmlContent = content.toString('utf-8');
614
592
}
593
+
// Check for <base> tag which can override paths
594
+
const baseTagMatch = htmlContent.match(/<base\s+[^>]*href=["'][^"']+["'][^>]*>/i);
595
+
if (baseTagMatch) {
596
+
console.warn(`[HTML Rewrite] WARNING: <base> tag found: ${baseTagMatch[0]} - this may override path rewrites`);
597
+
}
598
+
599
+
// Find src/href attributes (quoted and unquoted) to debug
600
+
const allMatches = htmlContent.match(/(?:src|href)\s*=\s*["']?\/[^"'\s>]+/g);
601
+
console.log(`[HTML Rewrite] Found ${allMatches ? allMatches.length : 0} local path attrs`);
602
+
if (allMatches && allMatches.length > 0) {
603
+
console.log(`[HTML Rewrite] Sample paths: ${allMatches.slice(0, 5).join(', ')}`);
604
+
}
605
+
615
606
const rewritten = rewriteHtmlPaths(htmlContent, basePath, fileRequestPath);
616
607
608
+
const rewrittenMatches = rewritten.match(/(?:src|href)\s*=\s*["']?\/[^"'\s>]+/g);
609
+
console.log(`[HTML Rewrite] After rewrite, found ${rewrittenMatches ? rewrittenMatches.length : 0} local paths`);
610
+
if (rewrittenMatches && rewrittenMatches.length > 0) {
611
+
console.log(`[HTML Rewrite] Sample rewritten: ${rewrittenMatches.slice(0, 5).join(', ')}`);
612
+
}
613
+
617
614
// Recompress and cache the rewritten HTML
618
615
const { gzipSync } = await import('zlib');
619
616
const recompressed = gzipSync(Buffer.from(rewritten, 'utf-8'));
···
625
622
'Content-Type': 'text/html; charset=utf-8',
626
623
'Content-Encoding': 'gzip',
627
624
'Cache-Control': 'public, max-age=300',
625
+
'X-Cache-Tier': result.source,
628
626
};
629
627
applyCustomHeaders(htmlHeaders, fileRequestPath, settings);
630
628
return new Response(recompressed, { headers: htmlHeaders });
···
634
632
const headers: Record<string, string> = {
635
633
'Content-Type': mimeType,
636
634
'Cache-Control': 'public, max-age=31536000, immutable',
635
+
'X-Cache-Tier': result.source,
637
636
};
638
637
639
638
if (isGzipped) {
···
663
662
if (!fileRequestPath.includes('.')) {
664
663
for (const indexFileName of indexFiles) {
665
664
const indexPath = fileRequestPath ? `${fileRequestPath}/${indexFileName}` : indexFileName;
666
-
const indexCacheKey = getCacheKey(did, rkey, indexPath);
667
-
const indexFile = getCachedFilePath(did, rkey, indexPath);
668
665
669
666
// Check for rewritten index file in cache
670
667
const rewrittenKey = getCacheKey(did, rkey, indexPath, `rewritten:${basePath}`);
···
674
671
'Content-Type': 'text/html; charset=utf-8',
675
672
'Content-Encoding': 'gzip',
676
673
'Cache-Control': 'public, max-age=300',
674
+
'X-Cache-Tier': 'local', // Rewritten HTML is stored locally
677
675
};
678
676
applyCustomHeaders(headers, indexPath, settings);
679
677
return new Response(rewrittenContent, { headers });
680
678
}
681
679
682
-
let indexContent = fileCache.get(indexCacheKey);
683
-
let indexMeta = metadataCache.get(indexCacheKey);
680
+
const indexResult = await getFileWithMetadata(did, rkey, indexPath);
684
681
685
-
if (!indexContent && await fileExists(indexFile)) {
686
-
indexContent = await readFile(indexFile);
687
-
fileCache.set(indexCacheKey, indexContent, indexContent.length);
688
-
689
-
const indexMetaFile = `${indexFile}.meta`;
690
-
if (await fileExists(indexMetaFile)) {
691
-
const metaJson = await readFile(indexMetaFile, 'utf-8');
692
-
indexMeta = JSON.parse(metaJson);
693
-
metadataCache.set(indexCacheKey, indexMeta!, JSON.stringify(indexMeta).length);
694
-
}
695
-
}
696
-
697
-
if (indexContent) {
682
+
if (indexResult) {
683
+
const indexContent = Buffer.from(indexResult.data);
684
+
const indexMeta = indexResult.metadata.customMetadata as { encoding?: string; mimeType?: string } | undefined;
698
685
const isGzipped = indexMeta?.encoding === 'gzip';
699
686
700
687
let htmlContent: string;
···
722
709
'Content-Type': 'text/html; charset=utf-8',
723
710
'Content-Encoding': 'gzip',
724
711
'Cache-Control': 'public, max-age=300',
712
+
'X-Cache-Tier': indexResult.source,
725
713
};
726
714
applyCustomHeaders(headers, indexPath, settings);
727
715
return new Response(recompressed, { headers });
+46
-35
apps/hosting-service/src/lib/firehose.ts
+46
-35
apps/hosting-service/src/lib/firehose.ts
···
1
-
import { existsSync, rmSync } from 'fs'
1
+
import { existsSync } from 'fs'
2
2
import {
3
3
getPdsForDid,
4
4
downloadAndCacheSite,
···
13
13
import { invalidateSiteCache, markSiteAsBeingCached, unmarkSiteAsBeingCached } from './cache'
14
14
import { clearRedirectRulesCache } from './site-cache'
15
15
16
-
const CACHE_DIR = './cache/sites'
16
+
const CACHE_DIR = process.env.CACHE_DIR || './cache/sites'
17
17
18
18
export class FirehoseWorker {
19
19
private firehose: Firehose | null = null
20
20
private idResolver: IdResolver
21
21
private isShuttingDown = false
22
22
private lastEventTime = Date.now()
23
+
private eventCount = 0
23
24
private cacheCleanupInterval: NodeJS.Timeout | null = null
25
+
private healthCheckInterval: NodeJS.Timeout | null = null
24
26
25
27
constructor(
26
28
private logger?: (msg: string, data?: Record<string, unknown>) => void
···
47
49
48
50
this.log('IdResolver cache cleared')
49
51
}, 60 * 60 * 1000) // Every hour
52
+
53
+
// Health check: log if no events received for 30 seconds
54
+
this.healthCheckInterval = setInterval(() => {
55
+
if (this.isShuttingDown) return
56
+
57
+
const timeSinceLastEvent = Date.now() - this.lastEventTime
58
+
if (timeSinceLastEvent > 30000 && this.eventCount === 0) {
59
+
this.log('Warning: No firehose events received in the last 30 seconds', {
60
+
timeSinceLastEvent,
61
+
eventsReceived: this.eventCount
62
+
})
63
+
} else if (timeSinceLastEvent > 60000) {
64
+
this.log('Firehose status check', {
65
+
timeSinceLastEvent,
66
+
eventsReceived: this.eventCount
67
+
})
68
+
}
69
+
}, 30000) // Every 30 seconds
50
70
}
51
71
52
72
start() {
···
61
81
if (this.cacheCleanupInterval) {
62
82
clearInterval(this.cacheCleanupInterval)
63
83
this.cacheCleanupInterval = null
84
+
}
85
+
86
+
if (this.healthCheckInterval) {
87
+
clearInterval(this.healthCheckInterval)
88
+
this.healthCheckInterval = null
64
89
}
65
90
66
91
if (this.firehose) {
···
80
105
filterCollections: ['place.wisp.fs', 'place.wisp.settings'],
81
106
handleEvent: async (evt: any) => {
82
107
this.lastEventTime = Date.now()
108
+
this.eventCount++
109
+
110
+
if (this.eventCount === 1) {
111
+
this.log('First firehose event received - connection established', {
112
+
eventType: evt.event,
113
+
collection: evt.collection
114
+
})
115
+
}
83
116
84
117
// Watch for write events
85
118
if (evt.event === 'create' || evt.event === 'update') {
···
189
222
}
190
223
})
191
224
192
-
this.firehose.start()
193
-
this.log('Firehose started')
225
+
this.firehose.start().catch((err: unknown) => {
226
+
this.log('Fatal firehose error', {
227
+
error: err instanceof Error ? err.message : String(err)
228
+
})
229
+
console.error('Fatal firehose error:', err)
230
+
})
231
+
this.log('Firehose starting')
194
232
}
195
233
196
234
private async handleCreateOrUpdate(
···
250
288
}
251
289
252
290
// Invalidate in-memory caches before updating
253
-
invalidateSiteCache(did, site)
291
+
await invalidateSiteCache(did, site)
254
292
255
293
// Mark site as being cached to prevent serving stale content during update
256
294
markSiteAsBeingCached(did, site)
···
340
378
})
341
379
}
342
380
343
-
// Invalidate in-memory caches
344
-
invalidateSiteCache(did, site)
345
-
346
-
// Delete disk cache
347
-
this.deleteCache(did, site)
381
+
// Invalidate all caches (tiered storage invalidation is handled by invalidateSiteCache)
382
+
await invalidateSiteCache(did, site)
348
383
349
384
this.log('Successfully processed delete', { did, site })
350
385
}
···
353
388
this.log('Processing settings change', { did, rkey })
354
389
355
390
// Invalidate in-memory caches (includes metadata which stores settings)
356
-
invalidateSiteCache(did, rkey)
391
+
await invalidateSiteCache(did, rkey)
357
392
358
393
// Check if site is already cached
359
394
const cacheDir = `${CACHE_DIR}/${did}/${rkey}`
···
413
448
}
414
449
415
450
this.log('Successfully processed settings change', { did, rkey })
416
-
}
417
-
418
-
private deleteCache(did: string, site: string) {
419
-
const cacheDir = `${CACHE_DIR}/${did}/${site}`
420
-
421
-
if (!existsSync(cacheDir)) {
422
-
this.log('Cache directory does not exist, nothing to delete', {
423
-
did,
424
-
site
425
-
})
426
-
return
427
-
}
428
-
429
-
try {
430
-
rmSync(cacheDir, { recursive: true, force: true })
431
-
this.log('Cache deleted', { did, site, path: cacheDir })
432
-
} catch (err) {
433
-
this.log('Failed to delete cache', {
434
-
did,
435
-
site,
436
-
path: cacheDir,
437
-
error: err instanceof Error ? err.message : String(err)
438
-
})
439
-
}
440
451
}
441
452
442
453
getHealth() {
+16
apps/hosting-service/src/lib/html-rewriter.ts
+16
apps/hosting-service/src/lib/html-rewriter.ts
···
189
189
`\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}'([^']*)'`,
190
190
'gi'
191
191
)
192
+
// Unquoted attributes (valid in HTML5 for values without spaces/special chars)
193
+
// Match: attr=value where value starts immediately (no quotes) and continues until space or >
194
+
// Use negative lookahead to ensure we don't match quoted attributes
195
+
const unquotedRegex = new RegExp(
196
+
`\\b${attr}[ \\t]{0,5}=[ \\t]{0,5}(?!["'])([^\\s>]+)`,
197
+
'gi'
198
+
)
192
199
193
200
rewritten = rewritten.replace(doubleQuoteRegex, (match, value) => {
194
201
const rewrittenValue = rewritePath(
···
206
213
documentPath
207
214
)
208
215
return `${attr}='${rewrittenValue}'`
216
+
})
217
+
218
+
rewritten = rewritten.replace(unquotedRegex, (match, value) => {
219
+
const rewrittenValue = rewritePath(
220
+
value,
221
+
normalizedBase,
222
+
documentPath
223
+
)
224
+
return `${attr}=${rewrittenValue}`
209
225
})
210
226
}
211
227
}
+1
-1
apps/hosting-service/src/lib/site-cache.ts
+1
-1
apps/hosting-service/src/lib/site-cache.ts
+270
apps/hosting-service/src/lib/storage.ts
+270
apps/hosting-service/src/lib/storage.ts
···
1
+
/**
2
+
* Tiered storage configuration for wisp-hosting-service
3
+
*
4
+
* Implements a three-tier caching strategy:
5
+
* - Hot (Memory): Instant access for frequently used files (index.html, CSS, JS)
6
+
* - Warm (Disk): Local cache with eviction policy
7
+
* - Cold (S3/R2): Object storage as source of truth (optional)
8
+
*
9
+
* When S3 is not configured, falls back to disk-only mode (warm tier acts as source of truth).
10
+
* In cache-only mode (non-master nodes), S3 writes are skipped even if configured.
11
+
*/
12
+
13
+
import {
14
+
TieredStorage,
15
+
MemoryStorageTier,
16
+
DiskStorageTier,
17
+
S3StorageTier,
18
+
type StorageTier,
19
+
type StorageMetadata,
20
+
} from 'tiered-storage';
21
+
22
+
const CACHE_DIR = process.env.CACHE_DIR || './cache/sites';
23
+
const HOT_CACHE_SIZE = parseInt(process.env.HOT_CACHE_SIZE || '104857600', 10); // 100MB default
24
+
const HOT_CACHE_COUNT = parseInt(process.env.HOT_CACHE_COUNT || '500', 10);
25
+
const WARM_CACHE_SIZE = parseInt(process.env.WARM_CACHE_SIZE || '10737418240', 10); // 10GB default
26
+
const WARM_EVICTION_POLICY = (process.env.WARM_EVICTION_POLICY || 'lru') as 'lru' | 'fifo' | 'size';
27
+
28
+
// Cache-only mode: skip S3 writes (non-master nodes)
29
+
// This is the same flag used to skip database writes
30
+
const CACHE_ONLY_MODE = process.env.CACHE_ONLY_MODE === 'true';
31
+
32
+
// S3/Cold tier configuration (optional)
33
+
const S3_BUCKET = process.env.S3_BUCKET || '';
34
+
const S3_METADATA_BUCKET = process.env.S3_METADATA_BUCKET;
35
+
const S3_REGION = process.env.S3_REGION || 'us-east-1';
36
+
const S3_ENDPOINT = process.env.S3_ENDPOINT;
37
+
const S3_FORCE_PATH_STYLE = process.env.S3_FORCE_PATH_STYLE !== 'false';
38
+
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
39
+
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
40
+
const S3_PREFIX = process.env.S3_PREFIX || 'sites/';
41
+
42
+
// Identity serializers for raw binary data (no JSON transformation)
43
+
// Files are stored as-is without any encoding/decoding
44
+
const identitySerialize = async (data: unknown): Promise<Uint8Array> => {
45
+
if (data instanceof Uint8Array) return data;
46
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
47
+
if (Buffer.isBuffer(data)) return new Uint8Array(data);
48
+
// For other types, fall back to JSON (shouldn't happen with file storage)
49
+
return new TextEncoder().encode(JSON.stringify(data));
50
+
};
51
+
52
+
const identityDeserialize = async (data: Uint8Array): Promise<unknown> => {
53
+
// Return as-is for binary file storage
54
+
return data;
55
+
};
56
+
57
+
/**
58
+
* Read-only wrapper for S3 tier in cache-only mode.
59
+
* Allows reads from S3 but skips all writes (for non-master nodes).
60
+
*/
61
+
class ReadOnlyS3Tier implements StorageTier {
62
+
private static hasLoggedWriteSkip = false;
63
+
64
+
constructor(private tier: StorageTier) {}
65
+
66
+
// Read operations - pass through to underlying tier
67
+
async get(key: string) {
68
+
return this.tier.get(key);
69
+
}
70
+
71
+
async getWithMetadata(key: string) {
72
+
return this.tier.getWithMetadata?.(key) ?? null;
73
+
}
74
+
75
+
async getStream(key: string) {
76
+
return this.tier.getStream?.(key) ?? null;
77
+
}
78
+
79
+
async exists(key: string) {
80
+
return this.tier.exists(key);
81
+
}
82
+
83
+
async getMetadata(key: string) {
84
+
return this.tier.getMetadata(key);
85
+
}
86
+
87
+
async *listKeys(prefix?: string) {
88
+
yield* this.tier.listKeys(prefix);
89
+
}
90
+
91
+
async getStats() {
92
+
return this.tier.getStats();
93
+
}
94
+
95
+
// Write operations - no-op in cache-only mode
96
+
async set(key: string, _data: Uint8Array, _metadata: StorageMetadata) {
97
+
this.logWriteSkip('set', key);
98
+
}
99
+
100
+
async setStream(key: string, _stream: NodeJS.ReadableStream, _metadata: StorageMetadata) {
101
+
this.logWriteSkip('setStream', key);
102
+
}
103
+
104
+
async setMetadata(key: string, _metadata: StorageMetadata) {
105
+
this.logWriteSkip('setMetadata', key);
106
+
}
107
+
108
+
async delete(key: string) {
109
+
this.logWriteSkip('delete', key);
110
+
}
111
+
112
+
async deleteMany(keys: string[]) {
113
+
this.logWriteSkip('deleteMany', `${keys.length} keys`);
114
+
}
115
+
116
+
async clear() {
117
+
this.logWriteSkip('clear', 'all keys');
118
+
}
119
+
120
+
private logWriteSkip(operation: string, key: string) {
121
+
// Only log once to avoid spam
122
+
if (!ReadOnlyS3Tier.hasLoggedWriteSkip) {
123
+
console.log(`[Storage] Cache-only mode: skipping S3 writes (operation: ${operation})`);
124
+
ReadOnlyS3Tier.hasLoggedWriteSkip = true;
125
+
}
126
+
}
127
+
}
128
+
129
+
/**
130
+
* Initialize tiered storage
131
+
* Must be called before serving requests
132
+
*/
133
+
function initializeStorage(): TieredStorage<Uint8Array> {
134
+
// Determine cold tier: S3 if configured, otherwise disk acts as cold
135
+
let coldTier: StorageTier;
136
+
let warmTier: StorageTier | undefined;
137
+
138
+
const diskTier = new DiskStorageTier({
139
+
directory: CACHE_DIR,
140
+
maxSizeBytes: WARM_CACHE_SIZE,
141
+
evictionPolicy: WARM_EVICTION_POLICY,
142
+
encodeColons: false, // Preserve colons for readable DID paths on Unix/macOS
143
+
});
144
+
145
+
if (S3_BUCKET) {
146
+
// Full three-tier setup with S3 as cold storage
147
+
const s3Tier = new S3StorageTier({
148
+
bucket: S3_BUCKET,
149
+
metadataBucket: S3_METADATA_BUCKET,
150
+
region: S3_REGION,
151
+
endpoint: S3_ENDPOINT,
152
+
forcePathStyle: S3_FORCE_PATH_STYLE,
153
+
credentials:
154
+
AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY
155
+
? { accessKeyId: AWS_ACCESS_KEY_ID, secretAccessKey: AWS_SECRET_ACCESS_KEY }
156
+
: undefined,
157
+
prefix: S3_PREFIX,
158
+
});
159
+
160
+
// In cache-only mode, wrap S3 tier to make it read-only
161
+
coldTier = CACHE_ONLY_MODE ? new ReadOnlyS3Tier(s3Tier) : s3Tier;
162
+
warmTier = diskTier;
163
+
164
+
if (CACHE_ONLY_MODE) {
165
+
console.log('[Storage] Cache-only mode: S3 as read-only cold tier (no writes), disk as warm tier');
166
+
} else {
167
+
console.log('[Storage] Using S3 as cold tier, disk as warm tier');
168
+
}
169
+
} else {
170
+
// Disk-only mode: disk tier acts as source of truth (cold)
171
+
coldTier = diskTier;
172
+
warmTier = undefined;
173
+
console.log('[Storage] S3 not configured - using disk-only mode (disk as cold tier)');
174
+
}
175
+
176
+
const storage = new TieredStorage<Uint8Array>({
177
+
tiers: {
178
+
// Hot tier: In-memory LRU for instant serving
179
+
hot: new MemoryStorageTier({
180
+
maxSizeBytes: HOT_CACHE_SIZE,
181
+
maxItems: HOT_CACHE_COUNT,
182
+
}),
183
+
184
+
// Warm tier: Disk-based cache (only when S3 is configured)
185
+
warm: warmTier,
186
+
187
+
// Cold tier: S3/R2 as source of truth, or disk in disk-only mode
188
+
cold: coldTier,
189
+
},
190
+
191
+
// Placement rules: determine which tiers each file goes to
192
+
placementRules: [
193
+
// Metadata is critical: frequently accessed for cache validity checks
194
+
{
195
+
pattern: '**/.metadata.json',
196
+
tiers: ['hot', 'warm', 'cold'],
197
+
},
198
+
199
+
// index.html is critical: write to all tiers for instant serving
200
+
{
201
+
pattern: '**/index.html',
202
+
tiers: ['hot', 'warm', 'cold'],
203
+
},
204
+
{
205
+
pattern: 'index.html',
206
+
tiers: ['hot', 'warm', 'cold'],
207
+
},
208
+
209
+
// CSS and JS: eligible for hot tier if accessed frequently
210
+
{
211
+
pattern: '**/*.{css,js}',
212
+
tiers: ['hot', 'warm', 'cold'],
213
+
},
214
+
215
+
// Media files: never needed in memory, skip hot tier
216
+
{
217
+
pattern: '**/*.{jpg,jpeg,png,gif,webp,svg,ico,mp4,webm,mp3,woff,woff2,ttf,eot}',
218
+
tiers: ['warm', 'cold'],
219
+
},
220
+
221
+
// Default: everything else goes to warm and cold
222
+
{
223
+
pattern: '**',
224
+
tiers: ['warm', 'cold'],
225
+
},
226
+
],
227
+
228
+
// IMPORTANT: Compression is disabled at the tiered-storage level
229
+
// Text files (HTML, CSS, JS, JSON) are pre-compressed with gzip at the app level
230
+
// Binary files (images, video) are stored uncompressed as they're already compressed
231
+
// The file's compression state is tracked in customMetadata.encoding
232
+
compression: false,
233
+
234
+
// TTL for cache entries (14 days)
235
+
defaultTTL: 14 * 24 * 60 * 60 * 1000,
236
+
237
+
// Eager promotion: promote data to upper tiers on read
238
+
// This ensures frequently accessed files end up in hot tier
239
+
promotionStrategy: 'eager',
240
+
241
+
// Identity serialization: store raw binary without JSON transformation
242
+
serialization: {
243
+
serialize: identitySerialize,
244
+
deserialize: identityDeserialize,
245
+
},
246
+
});
247
+
248
+
return storage;
249
+
}
250
+
251
+
// Export singleton instance
252
+
export const storage = initializeStorage();
253
+
254
+
/**
255
+
* Get storage configuration summary for logging
256
+
*/
257
+
export function getStorageConfig() {
258
+
return {
259
+
cacheDir: CACHE_DIR,
260
+
hotCacheSize: `${(HOT_CACHE_SIZE / 1024 / 1024).toFixed(0)}MB`,
261
+
hotCacheCount: HOT_CACHE_COUNT,
262
+
warmCacheSize: `${(WARM_CACHE_SIZE / 1024 / 1024 / 1024).toFixed(1)}GB`,
263
+
warmEvictionPolicy: WARM_EVICTION_POLICY,
264
+
s3Bucket: S3_BUCKET,
265
+
s3Region: S3_REGION,
266
+
s3Endpoint: S3_ENDPOINT || '(default AWS S3)',
267
+
s3Prefix: S3_PREFIX,
268
+
metadataBucket: S3_METADATA_BUCKET || '(embedded in data bucket)',
269
+
};
270
+
}
+473
-8
apps/hosting-service/src/lib/utils.test.ts
+473
-8
apps/hosting-service/src/lib/utils.test.ts
···
1
1
import { describe, test, expect } from 'bun:test'
2
-
import { sanitizePath, extractBlobCid } from './utils'
2
+
import { sanitizePath, extractBlobCid, extractSubfsUris, expandSubfsNodes } from './utils'
3
3
import { CID } from 'multiformats'
4
+
import { BlobRef } from '@atproto/lexicon'
5
+
import type {
6
+
Record as WispFsRecord,
7
+
Directory as FsDirectory,
8
+
Entry as FsEntry,
9
+
File as FsFile,
10
+
Subfs as FsSubfs,
11
+
} from '@wisp/lexicons/types/place/wisp/fs'
12
+
import type {
13
+
Record as SubfsRecord,
14
+
Directory as SubfsDirectory,
15
+
Entry as SubfsEntry,
16
+
File as SubfsFile,
17
+
Subfs as SubfsSubfs,
18
+
} from '@wisp/lexicons/types/place/wisp/subfs'
19
+
import type { $Typed } from '@wisp/lexicons/util'
4
20
5
21
describe('sanitizePath', () => {
6
22
test('allows normal file paths', () => {
···
31
47
32
48
test('blocks directory traversal in middle of path', () => {
33
49
expect(sanitizePath('images/../../../etc/passwd')).toBe('images/etc/passwd')
34
-
// Note: sanitizePath only filters out ".." segments, doesn't resolve paths
35
50
expect(sanitizePath('a/b/../c')).toBe('a/b/c')
36
51
expect(sanitizePath('a/../b/../c')).toBe('a/b/c')
37
52
})
···
50
65
})
51
66
52
67
test('blocks null bytes', () => {
53
-
// Null bytes cause the entire segment to be filtered out
54
68
expect(sanitizePath('index.html\0.txt')).toBe('')
55
69
expect(sanitizePath('test\0')).toBe('')
56
-
// Null byte in middle segment
57
70
expect(sanitizePath('css/bad\0name/styles.css')).toBe('css/styles.css')
58
71
})
59
72
···
89
102
90
103
describe('extractBlobCid', () => {
91
104
const TEST_CID = 'bafkreid7ybejd5s2vv2j7d4aajjlmdgazguemcnuliiyfn6coxpwp2mi6y'
92
-
105
+
93
106
test('extracts CID from IPLD link', () => {
94
107
const blobRef = { $link: TEST_CID }
95
108
expect(extractBlobCid(blobRef)).toBe(TEST_CID)
···
103
116
})
104
117
105
118
test('extracts CID from typed BlobRef with IPLD link', () => {
106
-
const blobRef = {
119
+
const blobRef = {
107
120
ref: { $link: TEST_CID }
108
121
}
109
122
expect(extractBlobCid(blobRef)).toBe(TEST_CID)
···
129
142
})
130
143
131
144
test('handles nested structures from AT Proto API', () => {
132
-
// Real structure from AT Proto
133
145
const blobRef = {
134
146
$type: 'blob',
135
147
ref: CID.parse(TEST_CID),
···
150
162
})
151
163
152
164
test('prioritizes checking IPLD link first', () => {
153
-
// Direct $link takes precedence
154
165
const directLink = { $link: TEST_CID }
155
166
expect(extractBlobCid(directLink)).toBe(TEST_CID)
156
167
})
···
167
178
expect(extractBlobCid(blobRef)).toBe(cidV1)
168
179
})
169
180
})
181
+
182
+
const TEST_CID_BASE = 'bafkreid7ybejd5s2vv2j7d4aajjlmdgazguemcnuliiyfn6coxpwp2mi6y'
183
+
184
+
function createMockBlobRef(cidSuffix: string = '', size: number = 100, mimeType: string = 'text/plain'): BlobRef {
185
+
const cidString = TEST_CID_BASE
186
+
return new BlobRef(CID.parse(cidString), mimeType, size)
187
+
}
188
+
189
+
function createFsFile(
190
+
name: string,
191
+
options: { mimeType?: string; size?: number; encoding?: 'gzip'; base64?: boolean } = {}
192
+
): FsEntry {
193
+
const { mimeType = 'text/plain', size = 100, encoding, base64 } = options
194
+
const file: $Typed<FsFile, 'place.wisp.fs#file'> = {
195
+
$type: 'place.wisp.fs#file',
196
+
type: 'file',
197
+
blob: createMockBlobRef(name.replace(/[^a-z0-9]/gi, ''), size, mimeType),
198
+
...(encoding && { encoding }),
199
+
...(mimeType && { mimeType }),
200
+
...(base64 && { base64 }),
201
+
}
202
+
return { name, node: file }
203
+
}
204
+
205
+
function createFsDirectory(name: string, entries: FsEntry[]): FsEntry {
206
+
const dir: $Typed<FsDirectory, 'place.wisp.fs#directory'> = {
207
+
$type: 'place.wisp.fs#directory',
208
+
type: 'directory',
209
+
entries,
210
+
}
211
+
return { name, node: dir }
212
+
}
213
+
214
+
function createFsSubfs(name: string, subject: string, flat: boolean = true): FsEntry {
215
+
const subfs: $Typed<FsSubfs, 'place.wisp.fs#subfs'> = {
216
+
$type: 'place.wisp.fs#subfs',
217
+
type: 'subfs',
218
+
subject,
219
+
flat,
220
+
}
221
+
return { name, node: subfs }
222
+
}
223
+
224
+
function createFsRootDirectory(entries: FsEntry[]): FsDirectory {
225
+
return {
226
+
$type: 'place.wisp.fs#directory',
227
+
type: 'directory',
228
+
entries,
229
+
}
230
+
}
231
+
232
+
function createFsRecord(site: string, entries: FsEntry[], fileCount?: number): WispFsRecord {
233
+
return {
234
+
$type: 'place.wisp.fs',
235
+
site,
236
+
root: createFsRootDirectory(entries),
237
+
...(fileCount !== undefined && { fileCount }),
238
+
createdAt: new Date().toISOString(),
239
+
}
240
+
}
241
+
242
+
function createSubfsFile(
243
+
name: string,
244
+
options: { mimeType?: string; size?: number; encoding?: 'gzip'; base64?: boolean } = {}
245
+
): SubfsEntry {
246
+
const { mimeType = 'text/plain', size = 100, encoding, base64 } = options
247
+
const file: $Typed<SubfsFile, 'place.wisp.subfs#file'> = {
248
+
$type: 'place.wisp.subfs#file',
249
+
type: 'file',
250
+
blob: createMockBlobRef(name.replace(/[^a-z0-9]/gi, ''), size, mimeType),
251
+
...(encoding && { encoding }),
252
+
...(mimeType && { mimeType }),
253
+
...(base64 && { base64 }),
254
+
}
255
+
return { name, node: file }
256
+
}
257
+
258
+
function createSubfsDirectory(name: string, entries: SubfsEntry[]): SubfsEntry {
259
+
const dir: $Typed<SubfsDirectory, 'place.wisp.subfs#directory'> = {
260
+
$type: 'place.wisp.subfs#directory',
261
+
type: 'directory',
262
+
entries,
263
+
}
264
+
return { name, node: dir }
265
+
}
266
+
267
+
function createSubfsSubfs(name: string, subject: string): SubfsEntry {
268
+
const subfs: $Typed<SubfsSubfs, 'place.wisp.subfs#subfs'> = {
269
+
$type: 'place.wisp.subfs#subfs',
270
+
type: 'subfs',
271
+
subject,
272
+
}
273
+
return { name, node: subfs }
274
+
}
275
+
276
+
function createSubfsRootDirectory(entries: SubfsEntry[]): SubfsDirectory {
277
+
return {
278
+
$type: 'place.wisp.subfs#directory',
279
+
type: 'directory',
280
+
entries,
281
+
}
282
+
}
283
+
284
+
function createSubfsRecord(entries: SubfsEntry[], fileCount?: number): SubfsRecord {
285
+
return {
286
+
$type: 'place.wisp.subfs',
287
+
root: createSubfsRootDirectory(entries),
288
+
...(fileCount !== undefined && { fileCount }),
289
+
createdAt: new Date().toISOString(),
290
+
}
291
+
}
292
+
293
+
describe('extractSubfsUris', () => {
294
+
test('extracts subfs URIs from flat directory structure', () => {
295
+
const subfsUri = 'at://did:plc:test/place.wisp.subfs/a'
296
+
const dir = createFsRootDirectory([
297
+
createFsSubfs('a', subfsUri),
298
+
createFsFile('file.txt'),
299
+
])
300
+
301
+
const uris = extractSubfsUris(dir)
302
+
303
+
expect(uris).toHaveLength(1)
304
+
expect(uris[0]).toEqual({ uri: subfsUri, path: 'a' })
305
+
})
306
+
307
+
test('extracts subfs URIs from nested directory structure', () => {
308
+
const subfsAUri = 'at://did:plc:test/place.wisp.subfs/a'
309
+
const subfsBUri = 'at://did:plc:test/place.wisp.subfs/b'
310
+
311
+
const dir = createFsRootDirectory([
312
+
createFsSubfs('a', subfsAUri),
313
+
createFsDirectory('nested', [
314
+
createFsSubfs('b', subfsBUri),
315
+
createFsFile('file.txt'),
316
+
]),
317
+
])
318
+
319
+
const uris = extractSubfsUris(dir)
320
+
321
+
expect(uris).toHaveLength(2)
322
+
expect(uris).toContainEqual({ uri: subfsAUri, path: 'a' })
323
+
expect(uris).toContainEqual({ uri: subfsBUri, path: 'nested/b' })
324
+
})
325
+
326
+
test('returns empty array when no subfs nodes exist', () => {
327
+
const dir = createFsRootDirectory([
328
+
createFsFile('file1.txt'),
329
+
createFsDirectory('dir', [createFsFile('file2.txt')]),
330
+
])
331
+
332
+
const uris = extractSubfsUris(dir)
333
+
expect(uris).toHaveLength(0)
334
+
})
335
+
336
+
test('handles deeply nested subfs', () => {
337
+
const subfsUri = 'at://did:plc:test/place.wisp.subfs/deep'
338
+
const dir = createFsRootDirectory([
339
+
createFsDirectory('a', [
340
+
createFsDirectory('b', [
341
+
createFsDirectory('c', [
342
+
createFsSubfs('deep', subfsUri),
343
+
]),
344
+
]),
345
+
]),
346
+
])
347
+
348
+
const uris = extractSubfsUris(dir)
349
+
350
+
expect(uris).toHaveLength(1)
351
+
expect(uris[0]).toEqual({ uri: subfsUri, path: 'a/b/c/deep' })
352
+
})
353
+
})
354
+
355
+
describe('expandSubfsNodes caching', () => {
356
+
test('cache map is populated after expansion', async () => {
357
+
const subfsCache = new Map<string, SubfsRecord | null>()
358
+
const dir = createFsRootDirectory([createFsFile('file.txt')])
359
+
360
+
const result = await expandSubfsNodes(dir, 'https://pds.example.com', 0, subfsCache)
361
+
362
+
expect(subfsCache.size).toBe(0)
363
+
expect(result.entries).toHaveLength(1)
364
+
expect(result.entries[0]?.name).toBe('file.txt')
365
+
})
366
+
367
+
test('cache is passed through recursion depths', async () => {
368
+
const subfsCache = new Map<string, SubfsRecord | null>()
369
+
const mockSubfsUri = 'at://did:plc:test/place.wisp.subfs/cached'
370
+
const mockRecord = createSubfsRecord([createSubfsFile('cached-file.txt')])
371
+
subfsCache.set(mockSubfsUri, mockRecord)
372
+
373
+
const dir = createFsRootDirectory([createFsSubfs('cached', mockSubfsUri)])
374
+
const result = await expandSubfsNodes(dir, 'https://pds.example.com', 0, subfsCache)
375
+
376
+
expect(subfsCache.has(mockSubfsUri)).toBe(true)
377
+
expect(result.entries).toHaveLength(1)
378
+
expect(result.entries[0]?.name).toBe('cached-file.txt')
379
+
})
380
+
381
+
test('pre-populated cache prevents re-fetching', async () => {
382
+
const subfsCache = new Map<string, SubfsRecord | null>()
383
+
const subfsAUri = 'at://did:plc:test/place.wisp.subfs/a'
384
+
const subfsBUri = 'at://did:plc:test/place.wisp.subfs/b'
385
+
386
+
subfsCache.set(subfsAUri, createSubfsRecord([createSubfsSubfs('b', subfsBUri)]))
387
+
subfsCache.set(subfsBUri, createSubfsRecord([createSubfsFile('final.txt')]))
388
+
389
+
const dir = createFsRootDirectory([createFsSubfs('a', subfsAUri)])
390
+
const result = await expandSubfsNodes(dir, 'https://pds.example.com', 0, subfsCache)
391
+
392
+
expect(result.entries).toHaveLength(1)
393
+
expect(result.entries[0]?.name).toBe('final.txt')
394
+
})
395
+
396
+
test('diamond dependency uses cache for shared reference', async () => {
397
+
const subfsCache = new Map<string, SubfsRecord | null>()
398
+
const subfsAUri = 'at://did:plc:test/place.wisp.subfs/a'
399
+
const subfsBUri = 'at://did:plc:test/place.wisp.subfs/b'
400
+
const subfsCUri = 'at://did:plc:test/place.wisp.subfs/c'
401
+
402
+
subfsCache.set(subfsAUri, createSubfsRecord([createSubfsSubfs('c', subfsCUri)]))
403
+
subfsCache.set(subfsBUri, createSubfsRecord([createSubfsSubfs('c', subfsCUri)]))
404
+
subfsCache.set(subfsCUri, createSubfsRecord([createSubfsFile('shared.txt')]))
405
+
406
+
const dir = createFsRootDirectory([
407
+
createFsSubfs('a', subfsAUri),
408
+
createFsSubfs('b', subfsBUri),
409
+
])
410
+
const result = await expandSubfsNodes(dir, 'https://pds.example.com', 0, subfsCache)
411
+
412
+
expect(result.entries.filter(e => e.name === 'shared.txt')).toHaveLength(2)
413
+
})
414
+
415
+
test('handles null records in cache gracefully', async () => {
416
+
const subfsCache = new Map<string, SubfsRecord | null>()
417
+
const subfsUri = 'at://did:plc:test/place.wisp.subfs/missing'
418
+
subfsCache.set(subfsUri, null)
419
+
420
+
const dir = createFsRootDirectory([
421
+
createFsFile('file.txt'),
422
+
createFsSubfs('missing', subfsUri),
423
+
])
424
+
const result = await expandSubfsNodes(dir, 'https://pds.example.com', 0, subfsCache)
425
+
426
+
expect(result.entries.some(e => e.name === 'file.txt')).toBe(true)
427
+
expect(result.entries.some(e => e.name === 'missing')).toBe(true)
428
+
})
429
+
430
+
test('non-flat subfs merge creates directory instead of hoisting', async () => {
431
+
const subfsCache = new Map<string, SubfsRecord | null>()
432
+
const subfsUri = 'at://did:plc:test/place.wisp.subfs/nested'
433
+
subfsCache.set(subfsUri, createSubfsRecord([createSubfsFile('nested-file.txt')]))
434
+
435
+
const dir = createFsRootDirectory([
436
+
createFsFile('root.txt'),
437
+
createFsSubfs('subdir', subfsUri, false),
438
+
])
439
+
const result = await expandSubfsNodes(dir, 'https://pds.example.com', 0, subfsCache)
440
+
441
+
expect(result.entries).toHaveLength(2)
442
+
443
+
const rootFile = result.entries.find(e => e.name === 'root.txt')
444
+
expect(rootFile).toBeDefined()
445
+
446
+
const subdir = result.entries.find(e => e.name === 'subdir')
447
+
expect(subdir).toBeDefined()
448
+
449
+
if (subdir && 'entries' in subdir.node) {
450
+
expect(subdir.node.type).toBe('directory')
451
+
expect(subdir.node.entries).toHaveLength(1)
452
+
expect(subdir.node.entries[0]?.name).toBe('nested-file.txt')
453
+
}
454
+
})
455
+
})
456
+
457
+
describe('WispFsRecord mock builders', () => {
458
+
test('createFsRecord creates valid record structure', () => {
459
+
const record = createFsRecord('my-site', [
460
+
createFsFile('index.html', { mimeType: 'text/html' }),
461
+
createFsDirectory('assets', [
462
+
createFsFile('style.css', { mimeType: 'text/css' }),
463
+
]),
464
+
])
465
+
466
+
expect(record.$type).toBe('place.wisp.fs')
467
+
expect(record.site).toBe('my-site')
468
+
expect(record.root.type).toBe('directory')
469
+
expect(record.root.entries).toHaveLength(2)
470
+
expect(record.createdAt).toBeDefined()
471
+
})
472
+
473
+
test('createFsFile creates valid file entry', () => {
474
+
const entry = createFsFile('test.html', { mimeType: 'text/html', size: 500 })
475
+
476
+
expect(entry.name).toBe('test.html')
477
+
478
+
const file = entry.node
479
+
if ('blob' in file) {
480
+
expect(file.$type).toBe('place.wisp.fs#file')
481
+
expect(file.type).toBe('file')
482
+
expect(file.blob).toBeDefined()
483
+
expect(file.mimeType).toBe('text/html')
484
+
}
485
+
})
486
+
487
+
test('createFsFile with gzip encoding', () => {
488
+
const entry = createFsFile('bundle.js', { mimeType: 'application/javascript', encoding: 'gzip' })
489
+
490
+
const file = entry.node
491
+
if ('encoding' in file) {
492
+
expect(file.encoding).toBe('gzip')
493
+
}
494
+
})
495
+
496
+
test('createFsFile with base64 flag', () => {
497
+
const entry = createFsFile('data.bin', { base64: true })
498
+
499
+
const file = entry.node
500
+
if ('base64' in file) {
501
+
expect(file.base64).toBe(true)
502
+
}
503
+
})
504
+
505
+
test('createFsDirectory creates valid directory entry', () => {
506
+
const entry = createFsDirectory('assets', [
507
+
createFsFile('file1.txt'),
508
+
createFsFile('file2.txt'),
509
+
])
510
+
511
+
expect(entry.name).toBe('assets')
512
+
513
+
const dir = entry.node
514
+
if ('entries' in dir) {
515
+
expect(dir.$type).toBe('place.wisp.fs#directory')
516
+
expect(dir.type).toBe('directory')
517
+
expect(dir.entries).toHaveLength(2)
518
+
}
519
+
})
520
+
521
+
test('createFsSubfs creates valid subfs entry with flat=true', () => {
522
+
const entry = createFsSubfs('external', 'at://did:plc:test/place.wisp.subfs/ext')
523
+
524
+
expect(entry.name).toBe('external')
525
+
526
+
const subfs = entry.node
527
+
if ('subject' in subfs) {
528
+
expect(subfs.$type).toBe('place.wisp.fs#subfs')
529
+
expect(subfs.type).toBe('subfs')
530
+
expect(subfs.subject).toBe('at://did:plc:test/place.wisp.subfs/ext')
531
+
expect(subfs.flat).toBe(true)
532
+
}
533
+
})
534
+
535
+
test('createFsSubfs creates valid subfs entry with flat=false', () => {
536
+
const entry = createFsSubfs('external', 'at://did:plc:test/place.wisp.subfs/ext', false)
537
+
538
+
const subfs = entry.node
539
+
if ('subject' in subfs) {
540
+
expect(subfs.flat).toBe(false)
541
+
}
542
+
})
543
+
544
+
test('createFsRecord with fileCount', () => {
545
+
const record = createFsRecord('my-site', [createFsFile('index.html')], 1)
546
+
expect(record.fileCount).toBe(1)
547
+
})
548
+
})
549
+
550
+
describe('SubfsRecord mock builders', () => {
551
+
test('createSubfsRecord creates valid record structure', () => {
552
+
const record = createSubfsRecord([
553
+
createSubfsFile('file1.txt'),
554
+
createSubfsDirectory('nested', [
555
+
createSubfsFile('file2.txt'),
556
+
]),
557
+
])
558
+
559
+
expect(record.$type).toBe('place.wisp.subfs')
560
+
expect(record.root.type).toBe('directory')
561
+
expect(record.root.entries).toHaveLength(2)
562
+
expect(record.createdAt).toBeDefined()
563
+
})
564
+
565
+
test('createSubfsFile creates valid file entry', () => {
566
+
const entry = createSubfsFile('data.json', { mimeType: 'application/json', size: 1024 })
567
+
568
+
expect(entry.name).toBe('data.json')
569
+
570
+
const file = entry.node
571
+
if ('blob' in file) {
572
+
expect(file.$type).toBe('place.wisp.subfs#file')
573
+
expect(file.type).toBe('file')
574
+
expect(file.blob).toBeDefined()
575
+
expect(file.mimeType).toBe('application/json')
576
+
}
577
+
})
578
+
579
+
test('createSubfsDirectory creates valid directory entry', () => {
580
+
const entry = createSubfsDirectory('subdir', [createSubfsFile('inner.txt')])
581
+
582
+
expect(entry.name).toBe('subdir')
583
+
584
+
const dir = entry.node
585
+
if ('entries' in dir) {
586
+
expect(dir.$type).toBe('place.wisp.subfs#directory')
587
+
expect(dir.type).toBe('directory')
588
+
expect(dir.entries).toHaveLength(1)
589
+
}
590
+
})
591
+
592
+
test('createSubfsSubfs creates valid nested subfs entry', () => {
593
+
const entry = createSubfsSubfs('deeper', 'at://did:plc:test/place.wisp.subfs/deeper')
594
+
595
+
expect(entry.name).toBe('deeper')
596
+
597
+
const subfs = entry.node
598
+
if ('subject' in subfs) {
599
+
expect(subfs.$type).toBe('place.wisp.subfs#subfs')
600
+
expect(subfs.type).toBe('subfs')
601
+
expect(subfs.subject).toBe('at://did:plc:test/place.wisp.subfs/deeper')
602
+
expect('flat' in subfs).toBe(false)
603
+
}
604
+
})
605
+
606
+
test('createSubfsRecord with fileCount', () => {
607
+
const record = createSubfsRecord([createSubfsFile('file.txt')], 1)
608
+
expect(record.fileCount).toBe(1)
609
+
})
610
+
})
611
+
612
+
describe('extractBlobCid with typed mock data', () => {
613
+
test('extracts CID from FsFile blob', () => {
614
+
const entry = createFsFile('test.txt')
615
+
const file = entry.node
616
+
617
+
if ('blob' in file) {
618
+
const cid = extractBlobCid(file.blob)
619
+
expect(cid).toBeDefined()
620
+
expect(cid).toContain('bafkrei')
621
+
}
622
+
})
623
+
624
+
test('extracts CID from SubfsFile blob', () => {
625
+
const entry = createSubfsFile('test.txt')
626
+
const file = entry.node
627
+
628
+
if ('blob' in file) {
629
+
const cid = extractBlobCid(file.blob)
630
+
expect(cid).toBeDefined()
631
+
expect(cid).toContain('bafkrei')
632
+
}
633
+
})
634
+
})
+128
-167
apps/hosting-service/src/lib/utils.ts
+128
-167
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 };
···
90
92
export async function fetchSiteRecord(did: string, rkey: string): Promise<{ record: WispFsRecord; cid: string } | null> {
91
93
try {
92
94
const pdsEndpoint = await getPdsForDid(did);
93
-
if (!pdsEndpoint) return null;
95
+
if (!pdsEndpoint) {
96
+
console.error('[hosting-service] Failed to get PDS endpoint for DID', { did, rkey });
97
+
return null;
98
+
}
94
99
95
100
const url = `${pdsEndpoint}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(did)}&collection=place.wisp.fs&rkey=${encodeURIComponent(rkey)}`;
96
101
const data = await safeFetchJson(url);
···
100
105
cid: data.cid || ''
101
106
};
102
107
} catch (err) {
103
-
console.error('Failed to fetch site record', did, rkey, err);
108
+
const errorCode = (err as any)?.code;
109
+
const errorMsg = err instanceof Error ? err.message : String(err);
110
+
111
+
// Better error logging to distinguish between network errors and 404s
112
+
if (errorMsg.includes('HTTP 404') || errorMsg.includes('Not Found')) {
113
+
console.log('[hosting-service] Site record not found', { did, rkey });
114
+
} else if (errorCode && ['ECONNRESET', 'ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR', 'ETIMEDOUT'].includes(errorCode)) {
115
+
console.error('[hosting-service] Network/SSL error fetching site record (after retries)', {
116
+
did,
117
+
rkey,
118
+
error: errorMsg,
119
+
code: errorCode
120
+
});
121
+
} else {
122
+
console.error('[hosting-service] Failed to fetch site record', {
123
+
did,
124
+
rkey,
125
+
error: errorMsg,
126
+
code: errorCode
127
+
});
128
+
}
129
+
104
130
return null;
105
131
}
106
132
}
···
149
175
/**
150
176
* Extract all subfs URIs from a directory tree with their mount paths
151
177
*/
152
-
function extractSubfsUris(directory: Directory, currentPath: string = ''): Array<{ uri: string; path: string }> {
178
+
export function extractSubfsUris(directory: Directory, currentPath: string = ''): Array<{ uri: string; path: string }> {
153
179
const uris: Array<{ uri: string; path: string }> = [];
154
180
155
181
for (const entry of directory.entries) {
···
209
235
* Replace subfs nodes in a directory tree with their actual content
210
236
* Subfs entries are "merged" - their root entries are hoisted into the parent directory
211
237
* This function is recursive - it will keep expanding until no subfs nodes remain
238
+
* Uses a cache to avoid re-fetching the same subfs records across recursion depths
212
239
*/
213
-
async function expandSubfsNodes(directory: Directory, pdsEndpoint: string, depth: number = 0): Promise<Directory> {
240
+
export async function expandSubfsNodes(
241
+
directory: Directory,
242
+
pdsEndpoint: string,
243
+
depth: number = 0,
244
+
subfsCache: Map<string, SubfsRecord | null> = new Map()
245
+
): Promise<Directory> {
214
246
const MAX_DEPTH = 10; // Prevent infinite loops
215
247
216
248
if (depth >= MAX_DEPTH) {
···
226
258
return directory;
227
259
}
228
260
229
-
console.log(`[Depth ${depth}] Found ${subfsUris.length} subfs records, fetching...`);
261
+
// Filter to only URIs we haven't fetched yet
262
+
const uncachedUris = subfsUris.filter(({ uri }) => !subfsCache.has(uri));
230
263
231
-
// Fetch all subfs records in parallel
232
-
const subfsRecords = await Promise.all(
233
-
subfsUris.map(async ({ uri, path }) => {
234
-
const record = await fetchSubfsRecord(uri, pdsEndpoint);
235
-
return { record, path };
236
-
})
237
-
);
264
+
if (uncachedUris.length > 0) {
265
+
console.log(`[Depth ${depth}] Found ${subfsUris.length} subfs references, fetching ${uncachedUris.length} new records (${subfsUris.length - uncachedUris.length} cached)...`);
238
266
239
-
// Build a map of path -> root entries to merge
267
+
// Fetch only uncached subfs records in parallel
268
+
const fetchedRecords = await Promise.all(
269
+
uncachedUris.map(async ({ uri }) => {
270
+
const record = await fetchSubfsRecord(uri, pdsEndpoint);
271
+
return { uri, record };
272
+
})
273
+
);
274
+
275
+
// Add fetched records to cache
276
+
for (const { uri, record } of fetchedRecords) {
277
+
subfsCache.set(uri, record);
278
+
}
279
+
} else {
280
+
console.log(`[Depth ${depth}] Found ${subfsUris.length} subfs references, all cached`);
281
+
}
282
+
283
+
// Build a map of path -> root entries to merge using the cache
240
284
// Note: SubFS entries are compatible with FS entries at runtime
241
285
const subfsMap = new Map<string, Entry[]>();
242
-
for (const { record, path } of subfsRecords) {
286
+
for (const { uri, path } of subfsUris) {
287
+
const record = subfsCache.get(uri);
243
288
if (record && record.root && record.root.entries) {
244
289
subfsMap.set(path, record.root.entries as unknown as Entry[]);
245
290
}
···
307
352
};
308
353
309
354
// Recursively expand any remaining subfs nodes (e.g., nested subfs inside parent subfs)
310
-
return expandSubfsNodes(partiallyExpanded, pdsEndpoint, depth + 1);
355
+
// Pass the cache to avoid re-fetching records
356
+
return expandSubfsNodes(partiallyExpanded, pdsEndpoint, depth + 1, subfsCache);
311
357
}
312
358
313
359
···
351
397
const existingMetadata = await getCacheMetadata(did, rkey);
352
398
const existingFileCids = existingMetadata?.fileCids || {};
353
399
354
-
// Use a temporary directory with timestamp to avoid collisions
355
-
const tempSuffix = `.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
356
-
const tempDir = `${CACHE_DIR}/${did}/${rkey}${tempSuffix}`;
357
-
const finalDir = `${CACHE_DIR}/${did}/${rkey}`;
358
-
359
-
try {
360
-
// Collect file CIDs from the new record (using expanded root)
361
-
const newFileCids: Record<string, string> = {};
362
-
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);
363
403
364
-
// Fetch site settings (optional)
365
-
const settings = await fetchSiteSettings(did, rkey);
404
+
// Fetch site settings (optional)
405
+
const settings = await fetchSiteSettings(did, rkey);
366
406
367
-
// Download/copy files to temporary directory (with incremental logic, using expanded root)
368
-
await cacheFiles(did, rkey, expandedRoot.entries, pdsEndpoint, '', tempSuffix, existingFileCids, finalDir);
369
-
await saveCacheMetadata(did, rkey, recordCid, tempSuffix, newFileCids, settings);
370
-
371
-
// Atomically replace old cache with new cache
372
-
// On POSIX systems (Linux/macOS), rename is atomic
373
-
if (existsSync(finalDir)) {
374
-
// Rename old directory to backup
375
-
const backupDir = `${finalDir}.old-${Date.now()}`;
376
-
await rename(finalDir, backupDir);
377
-
378
-
try {
379
-
// Rename new directory to final location
380
-
await rename(tempDir, finalDir);
381
-
382
-
// Clean up old backup
383
-
rmSync(backupDir, { recursive: true, force: true });
384
-
} catch (err) {
385
-
// If rename failed, restore backup
386
-
if (existsSync(backupDir) && !existsSync(finalDir)) {
387
-
await rename(backupDir, finalDir);
388
-
}
389
-
throw err;
390
-
}
391
-
} else {
392
-
// No existing cache, just rename temp to final
393
-
await rename(tempDir, finalDir);
394
-
}
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);
395
410
396
-
console.log('Successfully cached site atomically', did, rkey);
397
-
} catch (err) {
398
-
// Clean up temp directory on failure
399
-
if (existsSync(tempDir)) {
400
-
rmSync(tempDir, { recursive: true, force: true });
401
-
}
402
-
throw err;
403
-
}
411
+
console.log('Successfully cached site', did, rkey);
404
412
}
405
413
406
414
···
410
418
entries: Entry[],
411
419
pdsEndpoint: string,
412
420
pathPrefix: string,
413
-
dirSuffix: string = '',
414
-
existingFileCids: Record<string, string> = {},
415
-
existingCacheDir?: string
421
+
existingFileCids: Record<string, string> = {}
416
422
): Promise<void> {
417
-
// Collect file tasks, separating unchanged files from new/changed files
423
+
// Collect file download tasks (skip unchanged files)
418
424
const downloadTasks: Array<() => Promise<void>> = [];
419
-
const copyTasks: Array<() => Promise<void>> = [];
420
425
421
426
function collectFileTasks(
422
427
entries: Entry[],
···
433
438
const cid = extractBlobCid(fileNode.blob);
434
439
435
440
// Check if file is unchanged (same CID as existing cache)
436
-
if (cid && existingFileCids[currentPath] === cid && existingCacheDir) {
437
-
// File unchanged - copy from existing cache instead of downloading
438
-
copyTasks.push(() => copyExistingFile(
439
-
did,
440
-
site,
441
-
currentPath,
442
-
dirSuffix,
443
-
existingCacheDir
444
-
));
441
+
if (cid && existingFileCids[currentPath] === cid) {
442
+
// File unchanged - skip download (already in tiered storage)
443
+
console.log(`Skipping unchanged file: ${currentPath}`);
445
444
} else {
446
445
// File new or changed - download it
447
446
downloadTasks.push(() => cacheFileBlob(
···
452
451
pdsEndpoint,
453
452
fileNode.encoding,
454
453
fileNode.mimeType,
455
-
fileNode.base64,
456
-
dirSuffix
454
+
fileNode.base64
457
455
));
458
456
}
459
457
}
···
462
460
463
461
collectFileTasks(entries, pathPrefix);
464
462
465
-
console.log(`[Incremental Update] Files to copy: ${copyTasks.length}, Files to download: ${downloadTasks.length}`);
463
+
console.log(`[Incremental Update] Files to download: ${downloadTasks.length}`);
466
464
467
-
// Copy unchanged files in parallel (fast local operations) - increased limit for better performance
468
-
const copyLimit = 50;
469
-
for (let i = 0; i < copyTasks.length; i += copyLimit) {
470
-
const batch = copyTasks.slice(i, i + copyLimit);
471
-
await Promise.all(batch.map(task => task()));
472
-
if (copyTasks.length > copyLimit) {
473
-
console.log(`[Cache Progress] Copied ${Math.min(i + copyLimit, copyTasks.length)}/${copyTasks.length} unchanged files`);
474
-
}
475
-
}
476
-
477
-
// Download new/changed files concurrently - increased from 3 to 20 for much better performance
465
+
// Download new/changed files concurrently
478
466
const downloadLimit = 20;
479
467
let successCount = 0;
480
468
let failureCount = 0;
···
503
491
}
504
492
}
505
493
506
-
/**
507
-
* Copy an unchanged file from existing cache to new cache location
508
-
*/
509
-
async function copyExistingFile(
510
-
did: string,
511
-
site: string,
512
-
filePath: string,
513
-
dirSuffix: string,
514
-
existingCacheDir: string
515
-
): Promise<void> {
516
-
const { copyFile } = await import('fs/promises');
517
-
518
-
const sourceFile = `${existingCacheDir}/${filePath}`;
519
-
const destFile = `${CACHE_DIR}/${did}/${site}${dirSuffix}/${filePath}`;
520
-
const destDir = destFile.substring(0, destFile.lastIndexOf('/'));
521
-
522
-
// Create destination directory if needed
523
-
if (destDir && !existsSync(destDir)) {
524
-
mkdirSync(destDir, { recursive: true });
525
-
}
526
-
527
-
try {
528
-
// Copy the file
529
-
await copyFile(sourceFile, destFile);
530
-
531
-
// Copy metadata file if it exists
532
-
const sourceMetaFile = `${sourceFile}.meta`;
533
-
const destMetaFile = `${destFile}.meta`;
534
-
if (existsSync(sourceMetaFile)) {
535
-
await copyFile(sourceMetaFile, destMetaFile);
536
-
}
537
-
} catch (err) {
538
-
console.error(`Failed to copy cached file ${filePath}, will attempt download:`, err);
539
-
throw err;
540
-
}
541
-
}
542
-
543
494
async function cacheFileBlob(
544
495
did: string,
545
496
site: string,
···
548
499
pdsEndpoint: string,
549
500
encoding?: 'gzip',
550
501
mimeType?: string,
551
-
base64?: boolean,
552
-
dirSuffix: string = ''
502
+
base64?: boolean
553
503
): Promise<void> {
554
504
const cid = extractBlobCid(blobRef);
555
505
if (!cid) {
···
572
522
content = Buffer.from(base64String, 'base64');
573
523
}
574
524
575
-
const cacheFile = `${CACHE_DIR}/${did}/${site}${dirSuffix}/${filePath}`;
576
-
const fileDir = cacheFile.substring(0, cacheFile.lastIndexOf('/'));
577
-
578
-
if (fileDir && !existsSync(fileDir)) {
579
-
mkdirSync(fileDir, { recursive: true });
580
-
}
581
-
582
525
// Use the shared function to determine if this should remain compressed
583
526
const shouldStayCompressed = shouldCompressMimeType(mimeType);
584
527
···
596
539
}
597
540
}
598
541
599
-
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;
600
550
601
-
// Store metadata only if file is still compressed
551
+
await storage.setStream(key, stream, {
552
+
size: content.length,
553
+
skipTiers: ['hot'], // Don't put in memory on ingest, only on access
554
+
metadata: customMetadata,
555
+
});
556
+
557
+
// Log completion
602
558
if (encoding === 'gzip' && mimeType) {
603
-
const metaFile = `${cacheFile}.meta`;
604
-
await writeFile(metaFile, JSON.stringify({ encoding, mimeType }));
605
559
console.log('Cached file', filePath, content.length, 'bytes (gzipped,', mimeType + ')');
606
560
} else {
607
561
console.log('Cached file', filePath, content.length, 'bytes');
···
614
568
return `${CACHE_DIR}/${did}/${site}/${sanitizedPath}`;
615
569
}
616
570
617
-
export function isCached(did: string, site: string): boolean {
618
-
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);
619
580
}
620
581
621
-
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> {
622
583
const metadata: CacheMetadata = {
623
584
recordCid,
624
585
cachedAt: Date.now(),
···
628
589
settings: settings || undefined
629
590
};
630
591
631
-
const metadataPath = `${CACHE_DIR}/${did}/${rkey}${dirSuffix}/.metadata.json`;
632
-
const metadataDir = metadataPath.substring(0, metadataPath.lastIndexOf('/'));
633
-
634
-
if (!existsSync(metadataDir)) {
635
-
mkdirSync(metadataDir, { recursive: true });
636
-
}
637
-
638
-
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);
639
596
}
640
597
641
598
async function getCacheMetadata(did: string, rkey: string): Promise<CacheMetadata | null> {
642
599
try {
643
-
const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`;
644
-
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);
645
603
646
-
const content = await readFile(metadataPath, 'utf-8');
647
-
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;
648
609
} catch (err) {
649
610
console.error('Failed to read cache metadata', err);
650
611
return null;
···
678
639
}
679
640
680
641
export async function updateCacheMetadataSettings(did: string, rkey: string, settings: WispSettings | null): Promise<void> {
681
-
const metadataPath = `${CACHE_DIR}/${did}/${rkey}/.metadata.json`;
682
-
683
-
if (!existsSync(metadataPath)) {
684
-
console.warn('Metadata file does not exist, cannot update settings', { did, rkey });
685
-
return;
686
-
}
687
-
688
642
try {
689
-
// Read existing metadata
690
-
const content = await readFile(metadataPath, 'utf-8');
691
-
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
+
}
692
650
693
651
// Update settings field
694
652
// Store null explicitly to cache "no settings" state and avoid repeated fetches
695
653
metadata.settings = settings ?? null;
696
654
697
-
// Write back to disk
698
-
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);
699
660
console.log('Updated metadata settings', { did, rkey, hasSettings: !!settings });
700
661
} catch (err) {
701
662
console.error('Failed to update metadata settings', err);
+4
-1
apps/hosting-service/src/server.ts
+4
-1
apps/hosting-service/src/server.ts
···
80
80
return c.text('Invalid identifier', 400);
81
81
}
82
82
83
+
console.log(`[Server] sites.wisp.place request: identifier=${identifier}, site=${site}, filePath=${filePath}`);
84
+
83
85
// Check if site is currently being cached - return updating response early
84
86
if (isSiteBeingCached(did, site)) {
85
87
return siteUpdatingResponse();
···
93
95
94
96
// Serve with HTML path rewriting to handle absolute paths
95
97
const basePath = `/${identifier}/${site}/`;
98
+
console.log(`[Server] Serving with basePath: ${basePath}`);
96
99
const headers = extractHeaders(c.req.raw.headers);
97
100
return serveFromCacheWithRewrite(did, site, filePath, basePath, c.req.url, headers);
98
101
}
···
227
230
228
231
app.get('/__internal__/observability/cache', async (c) => {
229
232
const { getCacheStats } = await import('./lib/cache');
230
-
const stats = getCacheStats();
233
+
const stats = await getCacheStats();
231
234
return c.json({ cache: stats });
232
235
});
233
236
+7
-6
apps/main-app/package.json
+7
-6
apps/main-app/package.json
···
11
11
"screenshot": "bun run scripts/screenshot-sites.ts"
12
12
},
13
13
"dependencies": {
14
-
"@atproto/api": "^0.17.3",
15
-
"@atproto/common-web": "^0.4.5",
14
+
"@atproto-labs/did-resolver": "^0.2.4",
15
+
"@atproto/api": "^0.17.7",
16
+
"@atproto/common-web": "^0.4.6",
16
17
"@atproto/jwk-jose": "^0.1.11",
17
-
"@atproto/lex-cli": "^0.9.5",
18
-
"@atproto/oauth-client-node": "^0.3.9",
19
-
"@atproto/xrpc-server": "^0.9.5",
18
+
"@atproto/lex-cli": "^0.9.7",
19
+
"@atproto/oauth-client-node": "^0.3.12",
20
+
"@atproto/xrpc-server": "^0.9.6",
20
21
"@elysiajs/cors": "^1.4.0",
21
22
"@elysiajs/eden": "^1.4.3",
22
23
"@elysiajs/openapi": "^1.4.11",
···
40
41
"bun-plugin-tailwind": "^0.1.2",
41
42
"class-variance-authority": "^0.7.1",
42
43
"clsx": "^2.1.1",
43
-
"elysia": "latest",
44
+
"elysia": "^1.4.18",
44
45
"ignore": "^7.0.5",
45
46
"iron-session": "^8.0.4",
46
47
"lucide-react": "^0.546.0",
+4
-4
apps/main-app/public/acceptable-use/acceptable-use.tsx
+4
-4
apps/main-app/public/acceptable-use/acceptable-use.tsx
···
6
6
7
7
function AcceptableUsePage() {
8
8
return (
9
-
<div className="min-h-screen bg-background">
9
+
<div className="w-full min-h-screen bg-background flex flex-col">
10
10
{/* Header */}
11
-
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
12
-
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
11
+
<header className="w-full border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
12
+
<div className="max-w-6xl w-full mx-auto px-4 h-16 flex items-center justify-between">
13
13
<div className="flex items-center gap-2">
14
14
<img src="/transparent-full-size-ico.png" alt="wisp.place" className="w-8 h-8" />
15
15
<span className="text-xl font-semibold text-foreground">
···
326
326
</div>
327
327
328
328
{/* Footer */}
329
-
<footer className="border-t border-border/40 bg-muted/20 mt-12">
329
+
<footer className="border-t border-border/40 bg-muted/20 mt-auto">
330
330
<div className="container mx-auto px-4 py-8">
331
331
<div className="text-center text-sm text-muted-foreground">
332
332
<p>
+1
-1
apps/main-app/public/components/ui/checkbox.tsx
+1
-1
apps/main-app/public/components/ui/checkbox.tsx
···
12
12
<CheckboxPrimitive.Root
13
13
data-slot="checkbox"
14
14
className={cn(
15
-
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
15
+
"peer border-border bg-background dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
16
16
className
17
17
)}
18
18
{...props}
+6
-6
apps/main-app/public/editor/editor.tsx
+6
-6
apps/main-app/public/editor/editor.tsx
···
302
302
return (
303
303
<div className="w-full min-h-screen bg-background">
304
304
{/* Header Skeleton */}
305
-
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
306
-
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
305
+
<header className="w-full border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
306
+
<div className="max-w-6xl w-full mx-auto px-4 h-16 flex items-center justify-between">
307
307
<div className="flex items-center gap-2">
308
308
<img src="/transparent-full-size-ico.png" alt="wisp.place" className="w-8 h-8" />
309
309
<span className="text-xl font-semibold text-foreground">
···
366
366
}
367
367
368
368
return (
369
-
<div className="w-full min-h-screen bg-background">
369
+
<div className="w-full min-h-screen bg-background flex flex-col">
370
370
{/* Header */}
371
-
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
372
-
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
371
+
<header className="w-full border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
372
+
<div className="max-w-6xl w-full mx-auto px-4 h-16 flex items-center justify-between">
373
373
<div className="flex items-center gap-2">
374
374
<img src="/transparent-full-size-ico.png" alt="wisp.place" className="w-8 h-8" />
375
375
<span className="text-xl font-semibold text-foreground">
···
454
454
</div>
455
455
456
456
{/* Footer */}
457
-
<footer className="border-t border-border/40 bg-muted/20 mt-12">
457
+
<footer className="border-t border-border/40 bg-muted/20 mt-auto">
458
458
<div className="container mx-auto px-4 py-8">
459
459
<div className="text-center text-sm text-muted-foreground">
460
460
<p>
+74
-66
apps/main-app/public/index.tsx
+74
-66
apps/main-app/public/index.tsx
···
88
88
89
89
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
90
90
const navigationKeys = ['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp', 'Enter', 'Escape']
91
-
91
+
92
92
// Mark that we should preserve the index for navigation keys
93
93
if (navigationKeys.includes(e.key)) {
94
94
preserveIndexRef.current = true
···
142
142
setIndex(-1)
143
143
setIsOpen(false)
144
144
onSelect?.(handle)
145
-
145
+
146
146
// Auto-submit the form if enabled
147
147
if (autoSubmit && inputRef.current) {
148
148
const form = inputRef.current.closest('form')
···
236
236
height: 'calc(1.5rem + 12px)',
237
237
borderRadius: '4px',
238
238
cursor: 'pointer',
239
-
backgroundColor: i === index ? 'hsl(var(--accent) / 0.5)' : 'transparent',
239
+
backgroundColor: i === index ? 'color-mix(in oklch, var(--accent) 50%, transparent)' : 'transparent',
240
240
transition: 'background-color 0.1s'
241
241
}}
242
242
onMouseEnter={() => setIndex(i)}
···
246
246
width: '1.5rem',
247
247
height: '1.5rem',
248
248
borderRadius: '50%',
249
-
backgroundColor: 'hsl(var(--muted))',
249
+
backgroundColor: 'var(--muted)',
250
250
overflow: 'hidden',
251
251
flexShrink: 0
252
252
}}
···
255
255
<img
256
256
src={actor.avatar}
257
257
alt=""
258
+
loading="lazy"
258
259
style={{
259
260
display: 'block',
260
261
width: '100%',
···
359
360
360
361
return (
361
362
<>
362
-
<div className="min-h-screen">
363
+
<div className="w-full min-h-screen flex flex-col">
363
364
{/* Header */}
364
-
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
365
-
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
365
+
<header className="w-full border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
366
+
<div className="max-w-6xl w-full mx-auto px-4 h-16 flex items-center justify-between">
366
367
<div className="flex items-center gap-2">
367
368
<img src="/transparent-full-size-ico.png" alt="wisp.place" className="w-8 h-8" />
368
-
<span className="text-xl font-semibold text-foreground">
369
+
<span className="text-lg font-semibold text-foreground">
369
370
wisp.place
370
371
</span>
371
372
</div>
372
-
<div className="flex items-center gap-3">
373
+
<div className="flex items-center gap-4">
374
+
<a
375
+
href="https://docs.wisp.place"
376
+
target="_blank"
377
+
rel="noopener noreferrer"
378
+
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
379
+
>
380
+
Read the Docs
381
+
</a>
373
382
<Button
374
-
variant="ghost"
383
+
variant="outline"
375
384
size="sm"
385
+
className="btn-hover-lift"
376
386
onClick={() => setShowForm(true)}
377
387
>
378
388
Sign In
379
389
</Button>
380
-
<Button
381
-
size="sm"
382
-
className="bg-accent text-accent-foreground hover:bg-accent/90"
383
-
asChild
384
-
>
385
-
<a href="https://docs.wisp.place" target="_blank" rel="noopener noreferrer">
386
-
Read the Docs
387
-
</a>
388
-
</Button>
389
390
</div>
390
391
</div>
391
392
</header>
392
393
393
394
{/* Hero Section */}
394
-
<section className="container mx-auto px-4 py-20 md:py-32">
395
+
<section className="container mx-auto px-4 py-24 md:py-36">
395
396
<div className="max-w-4xl mx-auto text-center">
396
-
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-accent/10 border border-accent/20 mb-8">
397
-
<span className="w-2 h-2 bg-accent rounded-full animate-pulse"></span>
398
-
<span className="text-sm text-foreground">
399
-
Built on AT Protocol
400
-
</span>
401
-
</div>
402
-
403
-
<h1 className="text-5xl md:text-7xl font-bold text-balance mb-6 leading-tight">
404
-
Your Website.Your Control. Lightning Fast.
397
+
{/* Main Headline */}
398
+
<h1 className="animate-fade-in-up animate-delay-100 text-5xl md:text-7xl font-bold mb-2 leading-tight tracking-tight">
399
+
Deploy Anywhere.
400
+
</h1>
401
+
<h1 className="animate-fade-in-up animate-delay-200 text-5xl md:text-7xl font-bold mb-8 leading-tight tracking-tight text-gradient-animate">
402
+
For Free. Forever.
405
403
</h1>
406
404
407
-
<p className="text-xl md:text-2xl text-muted-foreground text-balance mb-10 leading-relaxed max-w-3xl mx-auto">
408
-
Host static sites in your AT Protocol account. You
409
-
keep ownership and control. We just serve them fast
410
-
through our CDN.
405
+
{/* Subheadline */}
406
+
<p className="animate-fade-in-up animate-delay-300 text-lg md:text-xl text-muted-foreground mb-12 leading-relaxed max-w-2xl mx-auto">
407
+
The easiest way to deploy and orchestrate static sites.
408
+
Push updates instantly. Host on our infrastructure or yours.
409
+
All powered by AT Protocol.
411
410
</p>
412
411
413
-
<div className="max-w-md mx-auto relative">
412
+
{/* CTA Buttons */}
413
+
<div className="animate-fade-in-up animate-delay-400 max-w-lg mx-auto relative">
414
414
<div
415
-
className={`transition-all duration-500 ease-in-out ${
416
-
showForm
417
-
? 'opacity-0 -translate-y-5 pointer-events-none'
418
-
: 'opacity-100 translate-y-0'
419
-
}`}
415
+
className={`transition-all duration-500 ease-in-out ${showForm
416
+
? 'opacity-0 -translate-y-5 pointer-events-none absolute inset-0'
417
+
: 'opacity-100 translate-y-0'
418
+
}`}
420
419
>
421
-
<Button
422
-
size="lg"
423
-
className="bg-primary text-primary-foreground hover:bg-primary/90 text-lg px-8 py-6 w-full"
424
-
onClick={() => setShowForm(true)}
425
-
>
426
-
Log in with AT Proto
427
-
<ArrowRight className="ml-2 w-5 h-5" />
428
-
</Button>
420
+
<div className="flex flex-col sm:flex-row gap-3 justify-center">
421
+
<Button
422
+
size="lg"
423
+
className="bg-foreground text-background hover:bg-foreground/90 text-base px-6 py-5 btn-hover-lift"
424
+
onClick={() => setShowForm(true)}
425
+
>
426
+
<span className="mr-2 font-bold">@</span>
427
+
Deploy with AT
428
+
</Button>
429
+
<Button
430
+
variant="outline"
431
+
size="lg"
432
+
className="text-base px-6 py-5 btn-hover-lift"
433
+
asChild
434
+
>
435
+
<a href="https://docs.wisp.place/cli/" target="_blank" rel="noopener noreferrer">
436
+
<span className="font-mono mr-2 text-muted-foreground">>_</span>
437
+
Install wisp-cli
438
+
</a>
439
+
</Button>
440
+
</div>
429
441
</div>
430
442
431
443
<div
432
-
className={`transition-all duration-500 ease-in-out absolute inset-0 ${
433
-
showForm
434
-
? 'opacity-100 translate-y-0'
435
-
: 'opacity-0 translate-y-5 pointer-events-none'
436
-
}`}
444
+
className={`transition-all duration-500 ease-in-out ${showForm
445
+
? 'opacity-100 translate-y-0'
446
+
: 'opacity-0 translate-y-5 pointer-events-none absolute inset-0'
447
+
}`}
437
448
>
438
449
<form
439
450
onSubmit={async (e) => {
···
494
505
</ActorTypeahead>
495
506
<button
496
507
type="submit"
497
-
className="w-full bg-accent hover:bg-accent/90 text-accent-foreground font-semibold py-4 px-6 text-lg rounded-lg inline-flex items-center justify-center transition-colors"
508
+
className="w-full bg-foreground text-background hover:bg-foreground/90 font-semibold py-4 px-6 text-lg rounded-lg inline-flex items-center justify-center transition-colors btn-hover-lift"
498
509
>
499
510
Continue
500
511
<ArrowRight className="ml-2 w-5 h-5" />
···
518
529
</div>
519
530
<div>
520
531
<h3 className="text-xl font-semibold mb-2">
521
-
Upload your static site
532
+
Drop in your files
522
533
</h3>
523
534
<p className="text-muted-foreground">
524
-
Your HTML, CSS, and JavaScript files are
525
-
stored in your AT Protocol account as
526
-
gzipped blobs and a manifest record.
535
+
Upload your site through our dashboard or push with the CLI.
536
+
Everything gets stored directly in your AT Protocol account.
527
537
</p>
528
538
</div>
529
539
</div>
···
533
543
</div>
534
544
<div>
535
545
<h3 className="text-xl font-semibold mb-2">
536
-
We serve it globally
546
+
We handle the rest
537
547
</h3>
538
548
<p className="text-muted-foreground">
539
-
Wisp.place reads your site from your
540
-
account and delivers it through our CDN
541
-
for fast loading anywhere.
549
+
Your site goes live instantly on our global CDN.
550
+
Custom domains, HTTPS, cachingโall automatic.
542
551
</p>
543
552
</div>
544
553
</div>
···
548
557
</div>
549
558
<div>
550
559
<h3 className="text-xl font-semibold mb-2">
551
-
You stay in control
560
+
Push updates instantly
552
561
</h3>
553
562
<p className="text-muted-foreground">
554
-
Update or remove your site anytime
555
-
through your AT Protocol account. No
556
-
lock-in, no middleman ownership.
563
+
Ship changes in seconds. Update through the dashboard,
564
+
run wisp-cli deploy, or wire up your CI/CD pipeline.
557
565
</p>
558
566
</div>
559
567
</div>
···
686
694
</section>
687
695
688
696
{/* Footer */}
689
-
<footer className="border-t border-border/40 bg-muted/20">
697
+
<footer className="border-t border-border/40 bg-muted/20 mt-auto">
690
698
<div className="container mx-auto px-4 py-8">
691
699
<div className="text-center text-sm text-muted-foreground">
692
700
<p>
+16
-19
apps/main-app/public/onboarding/onboarding.tsx
+16
-19
apps/main-app/public/onboarding/onboarding.tsx
···
161
161
return (
162
162
<div className="w-full min-h-screen bg-background">
163
163
{/* Header */}
164
-
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
165
-
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
164
+
<header className="w-full border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
165
+
<div className="max-w-6xl w-full mx-auto px-4 h-16 flex items-center justify-between">
166
166
<div className="flex items-center gap-2">
167
167
<div className="w-8 h-8 bg-primary rounded-lg flex items-center justify-center">
168
168
<Globe className="w-5 h-5 text-primary-foreground" />
···
179
179
<div className="mb-8">
180
180
<div className="flex items-center justify-center gap-2 mb-4">
181
181
<div
182
-
className={`w-8 h-8 rounded-full flex items-center justify-center ${
183
-
step === 'domain'
184
-
? 'bg-primary text-primary-foreground'
185
-
: 'bg-green-500 text-white'
186
-
}`}
182
+
className={`w-8 h-8 rounded-full flex items-center justify-center ${step === 'domain'
183
+
? 'bg-primary text-primary-foreground'
184
+
: 'bg-green-500 text-white'
185
+
}`}
187
186
>
188
187
{step === 'domain' ? (
189
188
'1'
···
193
192
</div>
194
193
<div className="w-16 h-0.5 bg-border"></div>
195
194
<div
196
-
className={`w-8 h-8 rounded-full flex items-center justify-center ${
197
-
step === 'upload'
198
-
? 'bg-primary text-primary-foreground'
199
-
: step === 'domain'
200
-
? 'bg-muted text-muted-foreground'
201
-
: 'bg-green-500 text-white'
202
-
}`}
195
+
className={`w-8 h-8 rounded-full flex items-center justify-center ${step === 'upload'
196
+
? 'bg-primary text-primary-foreground'
197
+
: step === 'domain'
198
+
? 'bg-muted text-muted-foreground'
199
+
: 'bg-green-500 text-white'
200
+
}`}
203
201
>
204
202
{step === 'complete' ? (
205
203
<CheckCircle2 className="w-5 h-5" />
···
258
256
{!isCheckingAvailability &&
259
257
isAvailable !== null && (
260
258
<div
261
-
className={`absolute right-3 top-1/2 -translate-y-1/2 ${
262
-
isAvailable
263
-
? 'text-green-500'
264
-
: 'text-red-500'
265
-
}`}
259
+
className={`absolute right-3 top-1/2 -translate-y-1/2 ${isAvailable
260
+
? 'text-green-500'
261
+
: 'text-red-500'
262
+
}`}
266
263
>
267
264
{isAvailable ? 'โ' : 'โ'}
268
265
</div>
+212
-39
apps/main-app/public/styles/global.css
+212
-39
apps/main-app/public/styles/global.css
···
6
6
:root {
7
7
color-scheme: light;
8
8
9
-
/* Warm beige background inspired by Sunset design #E9DDD8 */
10
-
--background: oklch(0.90 0.012 35);
11
-
/* Very dark brown text for strong contrast #2A2420 */
12
-
--foreground: oklch(0.18 0.01 30);
9
+
/* Warm beige background inspired by Sunset design */
10
+
--background: oklch(0.92 0.012 35);
11
+
/* Very dark brown text for strong contrast */
12
+
--foreground: oklch(0.15 0.015 30);
13
13
14
-
/* Slightly lighter card background */
15
-
--card: oklch(0.93 0.01 35);
16
-
--card-foreground: oklch(0.18 0.01 30);
14
+
/* Slightly lighter card background for elevation */
15
+
--card: oklch(0.95 0.008 35);
16
+
--card-foreground: oklch(0.15 0.015 30);
17
17
18
-
--popover: oklch(0.93 0.01 35);
19
-
--popover-foreground: oklch(0.18 0.01 30);
18
+
--popover: oklch(0.96 0.006 35);
19
+
--popover-foreground: oklch(0.15 0.015 30);
20
20
21
-
/* Dark brown primary inspired by #645343 */
22
-
--primary: oklch(0.35 0.02 35);
23
-
--primary-foreground: oklch(0.95 0.01 35);
21
+
/* Dark brown primary - darker for better contrast */
22
+
--primary: oklch(0.30 0.025 35);
23
+
--primary-foreground: oklch(0.96 0.008 35);
24
24
25
-
/* Bright pink accent for links #FFAAD2 */
26
-
--accent: oklch(0.78 0.15 345);
27
-
--accent-foreground: oklch(0.18 0.01 30);
25
+
/* Deeper pink accent for better visibility */
26
+
--accent: oklch(0.65 0.18 345);
27
+
--accent-foreground: oklch(0.15 0.015 30);
28
28
29
-
/* Medium taupe secondary inspired by #867D76 */
30
-
--secondary: oklch(0.52 0.015 30);
31
-
--secondary-foreground: oklch(0.95 0.01 35);
29
+
/* Darker taupe secondary for better contrast */
30
+
--secondary: oklch(0.85 0.012 30);
31
+
--secondary-foreground: oklch(0.25 0.02 30);
32
32
33
-
/* Light warm muted background */
33
+
/* Muted areas with better distinction */
34
34
--muted: oklch(0.88 0.01 35);
35
-
--muted-foreground: oklch(0.42 0.015 30);
35
+
--muted-foreground: oklch(0.35 0.02 30);
36
36
37
-
--border: oklch(0.75 0.015 30);
38
-
--input: oklch(0.92 0.01 35);
39
-
--ring: oklch(0.72 0.08 15);
37
+
/* Significantly darker border for visibility */
38
+
--border: oklch(0.65 0.02 30);
39
+
/* Input backgrounds lighter than cards */
40
+
--input: oklch(0.97 0.005 35);
41
+
--ring: oklch(0.55 0.12 345);
40
42
41
-
--destructive: oklch(0.577 0.245 27.325);
42
-
--destructive-foreground: oklch(0.985 0 0);
43
+
--destructive: oklch(0.50 0.20 25);
44
+
--destructive-foreground: oklch(0.98 0 0);
43
45
44
-
--chart-1: oklch(0.78 0.15 345);
46
+
--chart-1: oklch(0.65 0.18 345);
45
47
--chart-2: oklch(0.32 0.04 285);
46
-
--chart-3: oklch(0.56 0.08 220);
47
-
--chart-4: oklch(0.85 0.02 130);
48
-
--chart-5: oklch(0.93 0.03 85);
48
+
--chart-3: oklch(0.50 0.10 220);
49
+
--chart-4: oklch(0.70 0.08 130);
50
+
--chart-5: oklch(0.75 0.06 85);
49
51
50
52
--radius: 0.75rem;
51
-
--sidebar: oklch(0.985 0 0);
52
-
--sidebar-foreground: oklch(0.145 0 0);
53
-
--sidebar-primary: oklch(0.205 0 0);
54
-
--sidebar-primary-foreground: oklch(0.985 0 0);
55
-
--sidebar-accent: oklch(0.97 0 0);
56
-
--sidebar-accent-foreground: oklch(0.205 0 0);
57
-
--sidebar-border: oklch(0.922 0 0);
58
-
--sidebar-ring: oklch(0.708 0 0);
53
+
--sidebar: oklch(0.94 0.008 35);
54
+
--sidebar-foreground: oklch(0.15 0.015 30);
55
+
--sidebar-primary: oklch(0.30 0.025 35);
56
+
--sidebar-primary-foreground: oklch(0.96 0.008 35);
57
+
--sidebar-accent: oklch(0.90 0.01 35);
58
+
--sidebar-accent-foreground: oklch(0.20 0.02 30);
59
+
--sidebar-border: oklch(0.65 0.02 30);
60
+
--sidebar-ring: oklch(0.55 0.12 345);
59
61
}
60
62
61
63
.dark {
···
160
162
* {
161
163
@apply border-border outline-ring/50;
162
164
}
165
+
166
+
html {
167
+
scrollbar-gutter: stable;
168
+
}
169
+
163
170
body {
164
171
@apply bg-background text-foreground;
165
172
}
166
173
}
167
174
168
175
@keyframes arrow-bounce {
169
-
0%, 100% {
176
+
177
+
0%,
178
+
100% {
170
179
transform: translateX(0);
171
180
}
181
+
172
182
50% {
173
183
transform: translateX(4px);
174
184
}
···
189
199
border-radius: 0.5rem;
190
200
padding: 1rem;
191
201
overflow-x: auto;
192
-
border: 1px solid hsl(var(--border));
202
+
border: 1px solid var(--border);
193
203
}
194
204
195
205
.shiki-wrapper pre {
196
206
margin: 0 !important;
197
207
padding: 0 !important;
198
208
}
209
+
210
+
/* ========== Landing Page Animations ========== */
211
+
212
+
/* Animated gradient for headline text */
213
+
@keyframes gradient-shift {
214
+
215
+
0%,
216
+
100% {
217
+
background-position: 0% 50%;
218
+
}
219
+
220
+
50% {
221
+
background-position: 100% 50%;
222
+
}
223
+
}
224
+
225
+
.text-gradient-animate {
226
+
background: linear-gradient(90deg,
227
+
oklch(0.55 0.22 350),
228
+
oklch(0.60 0.24 10),
229
+
oklch(0.55 0.22 350));
230
+
background-size: 200% auto;
231
+
-webkit-background-clip: text;
232
+
background-clip: text;
233
+
-webkit-text-fill-color: transparent;
234
+
animation: gradient-shift 4s ease-in-out infinite;
235
+
}
236
+
237
+
.dark .text-gradient-animate {
238
+
background: linear-gradient(90deg,
239
+
oklch(0.75 0.12 295),
240
+
oklch(0.85 0.10 5),
241
+
oklch(0.75 0.12 295));
242
+
background-size: 200% auto;
243
+
-webkit-background-clip: text;
244
+
background-clip: text;
245
+
-webkit-text-fill-color: transparent;
246
+
}
247
+
248
+
/* Floating/breathing animation for hero elements */
249
+
@keyframes float {
250
+
251
+
0%,
252
+
100% {
253
+
transform: translateY(0);
254
+
}
255
+
256
+
50% {
257
+
transform: translateY(-8px);
258
+
}
259
+
}
260
+
261
+
.animate-float {
262
+
animation: float 3s ease-in-out infinite;
263
+
}
264
+
265
+
.animate-float-delayed {
266
+
animation: float 3s ease-in-out infinite;
267
+
animation-delay: 0.5s;
268
+
}
269
+
270
+
/* Staggered fade-in animation */
271
+
@keyframes fade-in-up {
272
+
from {
273
+
opacity: 0;
274
+
transform: translateY(20px);
275
+
}
276
+
277
+
to {
278
+
opacity: 1;
279
+
transform: translateY(0);
280
+
}
281
+
}
282
+
283
+
.animate-fade-in-up {
284
+
animation: fade-in-up 0.6s ease-out forwards;
285
+
opacity: 0;
286
+
}
287
+
288
+
.animate-delay-100 {
289
+
animation-delay: 0.1s;
290
+
}
291
+
292
+
.animate-delay-200 {
293
+
animation-delay: 0.2s;
294
+
}
295
+
296
+
.animate-delay-300 {
297
+
animation-delay: 0.3s;
298
+
}
299
+
300
+
.animate-delay-400 {
301
+
animation-delay: 0.4s;
302
+
}
303
+
304
+
.animate-delay-500 {
305
+
animation-delay: 0.5s;
306
+
}
307
+
308
+
.animate-delay-600 {
309
+
animation-delay: 0.6s;
310
+
}
311
+
312
+
/* Terminal cursor blink */
313
+
@keyframes cursor-blink {
314
+
315
+
0%,
316
+
50% {
317
+
opacity: 1;
318
+
}
319
+
320
+
51%,
321
+
100% {
322
+
opacity: 0;
323
+
}
324
+
}
325
+
326
+
.animate-cursor-blink {
327
+
animation: cursor-blink 1s step-end infinite;
328
+
}
329
+
330
+
/* Button hover scale effect */
331
+
.btn-hover-lift {
332
+
transition: all 0.2s ease-out;
333
+
}
334
+
335
+
.btn-hover-lift:hover {
336
+
transform: translateY(-2px);
337
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
338
+
}
339
+
340
+
.btn-hover-lift:active {
341
+
transform: translateY(0);
342
+
}
343
+
344
+
/* Subtle pulse for feature dots */
345
+
@keyframes dot-pulse {
346
+
347
+
0%,
348
+
100% {
349
+
transform: scale(1);
350
+
opacity: 1;
351
+
}
352
+
353
+
50% {
354
+
transform: scale(1.2);
355
+
opacity: 0.8;
356
+
}
357
+
}
358
+
359
+
.animate-dot-pulse {
360
+
animation: dot-pulse 2s ease-in-out infinite;
361
+
}
362
+
363
+
.animate-dot-pulse-delayed-1 {
364
+
animation: dot-pulse 2s ease-in-out infinite;
365
+
animation-delay: 0.3s;
366
+
}
367
+
368
+
.animate-dot-pulse-delayed-2 {
369
+
animation: dot-pulse 2s ease-in-out infinite;
370
+
animation-delay: 0.6s;
371
+
}
+30
-4
apps/main-app/src/index.ts
+30
-4
apps/main-app/src/index.ts
···
12
12
cleanupExpiredSessions,
13
13
rotateKeysIfNeeded
14
14
} from './lib/oauth-client'
15
-
import { getCookieSecret } from './lib/db'
15
+
import { getCookieSecret, closeDatabase } from './lib/db'
16
16
import { authRoutes } from './routes/auth'
17
17
import { wispRoutes } from './routes/wisp'
18
18
import { domainRoutes } from './routes/domain'
···
20
20
import { siteRoutes } from './routes/site'
21
21
import { csrfProtection } from './lib/csrf'
22
22
import { DNSVerificationWorker } from './lib/dns-verification-worker'
23
-
import { createLogger, logCollector } from '@wisp/observability'
23
+
import { createLogger, logCollector, initializeGrafanaExporters } from '@wisp/observability'
24
24
import { observabilityMiddleware } from '@wisp/observability/middleware/elysia'
25
25
import { promptAdminSetup } from './lib/admin-auth'
26
26
import { adminRoutes } from './routes/admin'
27
+
28
+
// Initialize Grafana exporters if configured
29
+
initializeGrafanaExporters({
30
+
serviceName: 'main-app',
31
+
serviceVersion: '1.0.50'
32
+
})
27
33
28
34
const logger = createLogger('main-app')
29
35
···
55
61
setInterval(runMaintenance, 60 * 60 * 1000)
56
62
57
63
// Start DNS verification worker (runs every 10 minutes)
64
+
// Can be disabled via DISABLE_DNS_WORKER=true environment variable
58
65
const dnsVerifier = new DNSVerificationWorker(
59
66
10 * 60 * 1000, // 10 minutes
60
67
(msg, data) => {
···
62
69
}
63
70
)
64
71
65
-
dnsVerifier.start()
66
-
logger.info('DNS Verifier Started - checking custom domains every 10 minutes')
72
+
if (Bun.env.DISABLE_DNS_WORKER !== 'true') {
73
+
dnsVerifier.start()
74
+
logger.info('DNS Verifier Started - checking custom domains every 10 minutes')
75
+
} else {
76
+
logger.info('DNS Verifier disabled via DISABLE_DNS_WORKER environment variable')
77
+
}
67
78
68
79
export const app = new Elysia({
69
80
serve: {
···
194
205
console.log(
195
206
`๐ฆ Elysia is running at ${app.server?.hostname}:${app.server?.port}`
196
207
)
208
+
209
+
// Graceful shutdown
210
+
process.on('SIGINT', async () => {
211
+
console.log('\n๐ Shutting down...')
212
+
dnsVerifier.stop()
213
+
await closeDatabase()
214
+
process.exit(0)
215
+
})
216
+
217
+
process.on('SIGTERM', async () => {
218
+
console.log('\n๐ Shutting down...')
219
+
dnsVerifier.stop()
220
+
await closeDatabase()
221
+
process.exit(0)
222
+
})
+13
apps/main-app/src/lib/db.ts
+13
apps/main-app/src/lib/db.ts
···
526
526
console.log('[CookieSecret] Generated new cookie signing secret');
527
527
return secret;
528
528
};
529
+
530
+
/**
531
+
* Close database connection
532
+
* Call this during graceful shutdown
533
+
*/
534
+
export const closeDatabase = async (): Promise<void> => {
535
+
try {
536
+
await db.end();
537
+
console.log('[DB] Database connection closed');
538
+
} catch (err) {
539
+
console.error('[DB] Error closing database connection:', err);
540
+
}
541
+
};
+5
-4
apps/main-app/src/lib/oauth-client.ts
+5
-4
apps/main-app/src/lib/oauth-client.ts
···
4
4
import { logger } from "./logger";
5
5
import { SlingshotHandleResolver } from "./slingshot-handle-resolver";
6
6
7
+
// OAuth scope for all client types
8
+
const OAUTH_SCOPE = 'atproto repo:place.wisp.fs repo:place.wisp.domain repo:place.wisp.subfs repo:place.wisp.settings blob:*/*';
7
9
// Session timeout configuration (30 days in seconds)
8
10
const SESSION_TIMEOUT = 30 * 24 * 60 * 60; // 2592000 seconds
9
11
// OAuth state timeout (1 hour in seconds)
···
110
112
// Loopback client for local development
111
113
// For loopback, scopes and redirect_uri must be in client_id query string
112
114
const redirectUri = 'http://127.0.0.1:8000/api/auth/callback';
113
-
const scope = 'atproto repo:place.wisp.fs repo:place.wisp.domain repo:place.wisp.subfs repo:place.wisp.settings blob:*/* rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app#bsky_appview';
114
115
const params = new URLSearchParams();
115
116
params.append('redirect_uri', redirectUri);
116
-
params.append('scope', scope);
117
+
params.append('scope', OAUTH_SCOPE);
117
118
118
119
return {
119
120
client_id: `http://localhost?${params.toString()}`,
···
124
125
response_types: ['code'],
125
126
application_type: 'web',
126
127
token_endpoint_auth_method: 'none',
127
-
scope: scope,
128
+
scope: OAUTH_SCOPE,
128
129
dpop_bound_access_tokens: false,
129
130
subject_type: 'public',
130
131
authorization_signed_response_alg: 'ES256'
···
145
146
application_type: 'web',
146
147
token_endpoint_auth_method: 'private_key_jwt',
147
148
token_endpoint_auth_signing_alg: "ES256",
148
-
scope: "atproto repo:place.wisp.fs repo:place.wisp.domain repo:place.wisp.subfs repo:place.wisp.settings blob:*/* rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app#bsky_appview",
149
+
scope: OAUTH_SCOPE,
149
150
dpop_bound_access_tokens: true,
150
151
jwks_uri: `${config.domain}/jwks.json`,
151
152
subject_type: 'public',
+10
-12
apps/main-app/src/routes/user.ts
+10
-12
apps/main-app/src/routes/user.ts
···
1
1
import { Elysia, t } from 'elysia'
2
2
import { requireAuth } from '../lib/wisp-auth'
3
3
import { NodeOAuthClient } from '@atproto/oauth-client-node'
4
-
import { Agent } from '@atproto/api'
5
4
import { getSitesByDid, getDomainByDid, getCustomDomainsByDid, getWispDomainInfo, getDomainsBySite, getAllWispDomains } from '../lib/db'
6
5
import { syncSitesFromPDS } from '../lib/sync-sites'
7
6
import { createLogger } from '@wisp/observability'
7
+
import { createDidResolver, extractAtprotoData } from '@atproto-labs/did-resolver'
8
8
9
9
const logger = createLogger('main-app')
10
+
const didResolver = createDidResolver({})
10
11
11
12
export const userRoutes = (client: NodeOAuthClient, cookieSecret: string) =>
12
13
new Elysia({
···
42
43
})
43
44
.get('/info', async ({ auth }) => {
44
45
try {
45
-
// Get user's handle from AT Protocol
46
-
const agent = new Agent(auth.session)
47
-
48
46
let handle = 'unknown'
49
47
try {
50
-
console.log('[User] Attempting to fetch profile for DID:', auth.did)
51
-
const profile = await agent.getProfile({ actor: auth.did })
52
-
console.log('[User] Profile fetched successfully:', profile.data.handle)
53
-
handle = profile.data.handle
48
+
const didDoc = await didResolver.resolve(auth.did)
49
+
const atprotoData = extractAtprotoData(didDoc)
50
+
51
+
if (atprotoData.aka) {
52
+
handle = atprotoData.aka
53
+
}
54
54
} catch (err) {
55
-
console.error('[User] Failed to fetch profile - Full error:', err)
56
-
console.error('[User] Error message:', err instanceof Error ? err.message : String(err))
57
-
console.error('[User] Error stack:', err instanceof Error ? err.stack : 'No stack')
58
-
logger.error('[User] Failed to fetch profile', err)
55
+
56
+
logger.error('[User] Failed to resolve DID', err)
59
57
}
60
58
61
59
return {
+10
-16
apps/main-app/src/routes/wisp.ts
+10
-16
apps/main-app/src/routes/wisp.ts
···
39
39
40
40
const logger = createLogger('main-app')
41
41
42
-
function isValidSiteName(siteName: string): boolean {
42
+
export function isValidSiteName(siteName: string): boolean {
43
43
if (!siteName || typeof siteName !== 'string') return false;
44
44
45
45
// Length check (AT Protocol rkey limit)
···
183
183
continue;
184
184
}
185
185
186
-
console.log(`Processing file ${i + 1}/${fileArray.length}:`, file.name, file.size, 'bytes');
186
+
// Use webkitRelativePath when available (directory uploads), fallback to name for regular file uploads
187
+
const webkitPath = 'webkitRelativePath' in file ? String(file.webkitRelativePath) : '';
188
+
const filePath = webkitPath || file.name;
189
+
187
190
updateJobProgress(jobId, {
188
191
filesProcessed: i + 1,
189
-
currentFile: file.name
192
+
currentFile: filePath
190
193
});
191
194
192
195
// Skip files that match ignore patterns
193
-
const normalizedPath = file.name.replace(/^[^\/]*\//, '');
196
+
const normalizedPath = filePath.replace(/^[^\/]*\//, '');
194
197
195
198
if (shouldIgnore(ignoreMatcher, normalizedPath)) {
196
-
console.log(`Skipping ignored file: ${file.name}`);
197
199
skippedFiles.push({
198
-
name: file.name,
200
+
name: filePath,
199
201
reason: 'matched ignore pattern'
200
202
});
201
203
continue;
···
205
207
const maxSize = MAX_FILE_SIZE;
206
208
if (file.size > maxSize) {
207
209
skippedFiles.push({
208
-
name: file.name,
210
+
name: filePath,
209
211
reason: `file too large (${(file.size / 1024 / 1024).toFixed(2)}MB, max 100MB)`
210
212
});
211
213
continue;
···
238
240
// Text files: compress AND base64 encode
239
241
finalContent = Buffer.from(compressedContent.toString('base64'), 'binary');
240
242
base64Encoded = true;
241
-
const compressionRatio = (compressedContent.length / originalContent.length * 100).toFixed(1);
242
-
console.log(`Compressing+base64 ${file.name}: ${originalContent.length} -> ${compressedContent.length} bytes (${compressionRatio}%), base64: ${finalContent.length} bytes`);
243
-
logger.info(`Compressing+base64 ${file.name}: ${originalContent.length} -> ${compressedContent.length} bytes (${compressionRatio}%), base64: ${finalContent.length} bytes`);
244
243
} else {
245
244
// Audio files: just compress, no base64
246
245
finalContent = compressedContent;
247
-
const compressionRatio = (compressedContent.length / originalContent.length * 100).toFixed(1);
248
-
console.log(`Compressing ${file.name}: ${originalContent.length} -> ${compressedContent.length} bytes (${compressionRatio}%)`);
249
-
logger.info(`Compressing ${file.name}: ${originalContent.length} -> ${compressedContent.length} bytes (${compressionRatio}%)`);
250
246
}
251
247
} else {
252
248
// Binary files: upload directly
253
249
finalContent = originalContent;
254
-
console.log(`Uploading ${file.name} directly: ${originalContent.length} bytes (no compression)`);
255
-
logger.info(`Uploading ${file.name} directly: ${originalContent.length} bytes (binary)`);
256
250
}
257
251
258
252
uploadedFiles.push({
259
-
name: file.name,
253
+
name: filePath,
260
254
content: finalContent,
261
255
mimeType: originalMimeType,
262
256
size: finalContent.length,
+59
backup.nix
+59
backup.nix
···
1
+
{
2
+
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
3
+
inputs.nci.url = "github:90-008/nix-cargo-integration";
4
+
inputs.nci.inputs.nixpkgs.follows = "nixpkgs";
5
+
inputs.parts.url = "github:hercules-ci/flake-parts";
6
+
inputs.parts.inputs.nixpkgs-lib.follows = "nixpkgs";
7
+
inputs.fenix = {
8
+
url = "github:nix-community/fenix";
9
+
inputs.nixpkgs.follows = "nixpkgs";
10
+
};
11
+
12
+
outputs = inputs @ {
13
+
parts,
14
+
nci,
15
+
...
16
+
}:
17
+
parts.lib.mkFlake {inherit inputs;} {
18
+
systems = ["x86_64-linux" "aarch64-darwin"];
19
+
imports = [
20
+
nci.flakeModule
21
+
./crates.nix
22
+
];
23
+
perSystem = {
24
+
pkgs,
25
+
config,
26
+
...
27
+
}: let
28
+
crateOutputs = config.nci.outputs."wisp-cli";
29
+
mkRenamedPackage = name: pkg: isWindows: pkgs.runCommand name {} ''
30
+
mkdir -p $out/bin
31
+
if [ -f ${pkg}/bin/wisp-cli.exe ]; then
32
+
cp ${pkg}/bin/wisp-cli.exe $out/bin/${name}
33
+
elif [ -f ${pkg}/bin/wisp-cli ]; then
34
+
cp ${pkg}/bin/wisp-cli $out/bin/${name}
35
+
else
36
+
echo "Error: Could not find wisp-cli binary in ${pkg}/bin/"
37
+
ls -la ${pkg}/bin/ || true
38
+
exit 1
39
+
fi
40
+
'';
41
+
in {
42
+
devShells.default = crateOutputs.devShell;
43
+
packages.default = crateOutputs.packages.release;
44
+
packages.wisp-cli-x86_64-linux = mkRenamedPackage "wisp-cli-x86_64-linux" crateOutputs.packages.release false;
45
+
packages.wisp-cli-aarch64-linux = mkRenamedPackage "wisp-cli-aarch64-linux" crateOutputs.allTargets."aarch64-unknown-linux-gnu".packages.release false;
46
+
packages.wisp-cli-x86_64-windows = mkRenamedPackage "wisp-cli-x86_64-windows.exe" crateOutputs.allTargets."x86_64-pc-windows-gnu".packages.release true;
47
+
packages.wisp-cli-aarch64-darwin = mkRenamedPackage "wisp-cli-aarch64-darwin" crateOutputs.allTargets."aarch64-apple-darwin".packages.release false;
48
+
packages.all = pkgs.symlinkJoin {
49
+
name = "wisp-cli-all";
50
+
paths = [
51
+
config.packages.wisp-cli-x86_64-linux
52
+
config.packages.wisp-cli-aarch64-linux
53
+
config.packages.wisp-cli-x86_64-windows
54
+
config.packages.wisp-cli-aarch64-darwin
55
+
];
56
+
};
57
+
};
58
+
};
59
+
}
+773
-405
bun.lock
+773
-405
bun.lock
···
3
3
"configVersion": 1,
4
4
"workspaces": {
5
5
"": {
6
-
"name": "elysia-static",
6
+
"name": "@wisp/monorepo",
7
7
"dependencies": {
8
8
"@tailwindcss/cli": "^4.1.17",
9
9
"atproto-ui": "^0.12.0",
10
10
"bun-plugin-tailwind": "^0.1.2",
11
+
"elysia": "^1.4.18",
11
12
"tailwindcss": "^4.1.17",
12
13
},
14
+
"devDependencies": {
15
+
"@types/bun": "^1.3.5",
16
+
},
13
17
},
14
18
"apps/hosting-service": {
15
19
"name": "wisp-hosting-service",
···
32
36
"mime-types": "^2.1.35",
33
37
"multiformats": "^13.4.1",
34
38
"postgres": "^3.4.5",
39
+
"tiered-storage": "1.0.3",
35
40
},
36
41
"devDependencies": {
37
42
"@types/bun": "^1.3.1",
···
45
50
"name": "@wisp/main-app",
46
51
"version": "1.0.50",
47
52
"dependencies": {
48
-
"@atproto/api": "^0.17.3",
49
-
"@atproto/common-web": "^0.4.5",
53
+
"@atproto-labs/did-resolver": "^0.2.4",
54
+
"@atproto/api": "^0.17.7",
55
+
"@atproto/common-web": "^0.4.6",
50
56
"@atproto/jwk-jose": "^0.1.11",
51
-
"@atproto/lex-cli": "^0.9.5",
52
-
"@atproto/oauth-client-node": "^0.3.9",
53
-
"@atproto/xrpc-server": "^0.9.5",
57
+
"@atproto/lex-cli": "^0.9.7",
58
+
"@atproto/oauth-client-node": "^0.3.12",
59
+
"@atproto/xrpc-server": "^0.9.6",
54
60
"@elysiajs/cors": "^1.4.0",
55
61
"@elysiajs/eden": "^1.4.3",
56
62
"@elysiajs/openapi": "^1.4.11",
···
74
80
"bun-plugin-tailwind": "^0.1.2",
75
81
"class-variance-authority": "^0.7.1",
76
82
"clsx": "^2.1.1",
77
-
"elysia": "latest",
83
+
"elysia": "^1.4.18",
78
84
"ignore": "^7.0.5",
79
85
"iron-session": "^8.0.4",
80
86
"lucide-react": "^0.546.0",
···
144
150
"packages/@wisp/observability": {
145
151
"name": "@wisp/observability",
146
152
"version": "1.0.0",
153
+
"dependencies": {
154
+
"@opentelemetry/api": "^1.9.0",
155
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.56.0",
156
+
"@opentelemetry/resources": "^1.29.0",
157
+
"@opentelemetry/sdk-metrics": "^1.29.0",
158
+
"@opentelemetry/semantic-conventions": "^1.29.0",
159
+
},
160
+
"devDependencies": {
161
+
"@hono/node-server": "^1.19.6",
162
+
"bun-types": "^1.3.3",
163
+
"typescript": "^5.9.3",
164
+
},
147
165
"peerDependencies": {
148
-
"hono": "^4.0.0",
166
+
"hono": "^4.10.7",
149
167
},
150
168
"optionalPeers": [
151
169
"hono",
···
181
199
182
200
"@atcute/util-fetch": ["@atcute/util-fetch@1.0.4", "", { "dependencies": { "@badrap/valita": "^0.4.6" } }, "sha512-sIU9Qk0dE8PLEXSfhy+gIJV+HpiiknMytCI2SqLlqd0vgZUtEKI/EQfP+23LHWvP+CLCzVDOa6cpH045OlmNBg=="],
183
201
184
-
"@atproto-labs/did-resolver": ["@atproto-labs/did-resolver@0.2.2", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.1", "zod": "^3.23.8" } }, ""],
202
+
"@atproto-labs/did-resolver": ["@atproto-labs/did-resolver@0.2.4", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.3", "zod": "^3.23.8" } }, "sha512-sbXxBnAJWsKv/FEGG6a/WLz7zQYUr1vA2TXvNnPwwJQJCjPwEJMOh1vM22wBr185Phy7D2GD88PcRokn7eUVyw=="],
185
203
186
-
"@atproto-labs/fetch": ["@atproto-labs/fetch@0.2.3", "", { "dependencies": { "@atproto-labs/pipe": "0.1.1" } }, ""],
204
+
"@atproto-labs/fetch": ["@atproto-labs/fetch@0.2.3", "", { "dependencies": { "@atproto-labs/pipe": "0.1.1" } }, "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw=="],
187
205
188
-
"@atproto-labs/fetch-node": ["@atproto-labs/fetch-node@0.2.0", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "ipaddr.js": "^2.1.0", "undici": "^6.14.1" } }, ""],
206
+
"@atproto-labs/fetch-node": ["@atproto-labs/fetch-node@0.2.0", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "ipaddr.js": "^2.1.0", "undici": "^6.14.1" } }, "sha512-Krq09nH/aeoiU2s9xdHA0FjTEFWG9B5FFenipv1iRixCcPc7V3DhTNDawxG9gI8Ny0k4dBVS9WTRN/IDzBx86Q=="],
189
207
190
208
"@atproto-labs/handle-resolver": ["@atproto-labs/handle-resolver@0.3.4", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.3", "zod": "^3.23.8" } }, "sha512-wsNopfzfgO3uPvfnFDgNeXgDufXxSXhjBjp2WEiSzEiLrMy0Jodnqggw4OzD9MJKf0a4Iu2/ydd537qdy91LrQ=="],
191
209
192
-
"@atproto-labs/handle-resolver-node": ["@atproto-labs/handle-resolver-node@0.1.21", "", { "dependencies": { "@atproto-labs/fetch-node": "0.2.0", "@atproto-labs/handle-resolver": "0.3.2", "@atproto/did": "0.2.1" } }, ""],
210
+
"@atproto-labs/handle-resolver-node": ["@atproto-labs/handle-resolver-node@0.1.23", "", { "dependencies": { "@atproto-labs/fetch-node": "0.2.0", "@atproto-labs/handle-resolver": "0.3.4", "@atproto/did": "0.2.3" } }, "sha512-tBRr2LCgzn3klk+DL0xrTFv4zg5tEszdeW6vSIFVebBYSb3MLdfhievmSqZdIQ4c9UCC4hN7YXTlZCXj8+2YmQ=="],
193
211
194
-
"@atproto-labs/identity-resolver": ["@atproto-labs/identity-resolver@0.3.2", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.2", "@atproto-labs/handle-resolver": "0.3.2" } }, ""],
212
+
"@atproto-labs/identity-resolver": ["@atproto-labs/identity-resolver@0.3.4", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.4", "@atproto-labs/handle-resolver": "0.3.4" } }, "sha512-HNUEFQIo2ws6iATxmgHd5D5rAsWYupgxZucgwolVHPiMjE1SY+EmxEsfbEN1wDEzM8/u9AKUg/jrxxPEwsgbew=="],
195
213
196
-
"@atproto-labs/pipe": ["@atproto-labs/pipe@0.1.1", "", {}, ""],
214
+
"@atproto-labs/pipe": ["@atproto-labs/pipe@0.1.1", "", {}, "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg=="],
197
215
198
-
"@atproto-labs/simple-store": ["@atproto-labs/simple-store@0.3.0", "", {}, ""],
216
+
"@atproto-labs/simple-store": ["@atproto-labs/simple-store@0.3.0", "", {}, "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ=="],
199
217
200
-
"@atproto-labs/simple-store-memory": ["@atproto-labs/simple-store-memory@0.1.4", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "lru-cache": "^10.2.0" } }, ""],
218
+
"@atproto-labs/simple-store-memory": ["@atproto-labs/simple-store-memory@0.1.4", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "lru-cache": "^10.2.0" } }, "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw=="],
201
219
202
220
"@atproto/api": ["@atproto/api@0.14.22", "", { "dependencies": { "@atproto/common-web": "^0.4.1", "@atproto/lexicon": "^0.4.10", "@atproto/syntax": "^0.4.0", "@atproto/xrpc": "^0.6.12", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-ziXPau+sUdFovObSnsoN7JbOmUw1C5e5L28/yXf3P8vbEnSS3HVVGD1jYcscBYY34xQqi4bVDpwMYx/4yRsTuQ=="],
203
221
204
-
"@atproto/common": ["@atproto/common@0.4.12", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@ipld/dag-cbor": "^7.0.3", "cbor-x": "^1.5.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, ""],
222
+
"@atproto/common": ["@atproto/common@0.4.12", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@ipld/dag-cbor": "^7.0.3", "cbor-x": "^1.5.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-NC+TULLQiqs6MvNymhQS5WDms3SlbIKGLf4n33tpftRJcalh507rI+snbcUb7TLIkKw7VO17qMqxEXtIdd5auQ=="],
205
223
206
224
"@atproto/common-web": ["@atproto/common-web@0.4.6", "", { "dependencies": { "@atproto/lex-data": "0.0.2", "@atproto/lex-json": "0.0.2", "zod": "^3.23.8" } }, "sha512-+2mG/1oBcB/ZmYIU1ltrFMIiuy9aByKAkb2Fos/0eTdczcLBaH17k0KoxMGvhfsujN2r62XlanOAMzysa7lv1g=="],
207
225
208
-
"@atproto/crypto": ["@atproto/crypto@0.4.4", "", { "dependencies": { "@noble/curves": "^1.7.0", "@noble/hashes": "^1.6.1", "uint8arrays": "3.0.0" } }, ""],
226
+
"@atproto/crypto": ["@atproto/crypto@0.4.5", "", { "dependencies": { "@noble/curves": "^1.7.0", "@noble/hashes": "^1.6.1", "uint8arrays": "3.0.0" } }, "sha512-n40aKkMoCatP0u9Yvhrdk6fXyOHFDDbkdm4h4HCyWW+KlKl8iXfD5iV+ECq+w5BM+QH25aIpt3/j6EUNerhLxw=="],
209
227
210
228
"@atproto/did": ["@atproto/did@0.2.3", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-VI8JJkSizvM2cHYJa37WlbzeCm5tWpojyc1/Zy8q8OOjyoy6X4S4BEfoP941oJcpxpMTObamibQIXQDo7tnIjg=="],
211
229
212
230
"@atproto/identity": ["@atproto/identity@0.4.10", "", { "dependencies": { "@atproto/common-web": "^0.4.4", "@atproto/crypto": "^0.4.4" } }, "sha512-nQbzDLXOhM8p/wo0cTh5DfMSOSHzj6jizpodX37LJ4S1TZzumSxAjHEZa5Rev3JaoD5uSWMVE0MmKEGWkPPvfQ=="],
213
231
214
-
"@atproto/jwk": ["@atproto/jwk@0.6.0", "", { "dependencies": { "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
232
+
"@atproto/jwk": ["@atproto/jwk@0.6.0", "", { "dependencies": { "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw=="],
215
233
216
-
"@atproto/jwk-jose": ["@atproto/jwk-jose@0.1.11", "", { "dependencies": { "@atproto/jwk": "0.6.0", "jose": "^5.2.0" } }, ""],
234
+
"@atproto/jwk-jose": ["@atproto/jwk-jose@0.1.11", "", { "dependencies": { "@atproto/jwk": "0.6.0", "jose": "^5.2.0" } }, "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q=="],
217
235
218
-
"@atproto/jwk-webcrypto": ["@atproto/jwk-webcrypto@0.2.0", "", { "dependencies": { "@atproto/jwk": "0.6.0", "@atproto/jwk-jose": "0.1.11", "zod": "^3.23.8" } }, ""],
236
+
"@atproto/jwk-webcrypto": ["@atproto/jwk-webcrypto@0.2.0", "", { "dependencies": { "@atproto/jwk": "0.6.0", "@atproto/jwk-jose": "0.1.11", "zod": "^3.23.8" } }, "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg=="],
219
237
220
238
"@atproto/lex-cbor": ["@atproto/lex-cbor@0.0.2", "", { "dependencies": { "@atproto/lex-data": "0.0.2", "multiformats": "^9.9.0", "tslib": "^2.8.1" } }, "sha512-sTr3UCL2SgxEoYVpzJGgWTnNl4TpngP5tMcRyaOvi21Se4m3oR4RDsoVDPz8AS6XphiteRwzwPstquN7aWWMbA=="],
221
239
222
-
"@atproto/lex-cli": ["@atproto/lex-cli@0.9.6", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "@atproto/syntax": "^0.4.1", "chalk": "^4.1.2", "commander": "^9.4.0", "prettier": "^3.2.5", "ts-morph": "^24.0.0", "yesno": "^0.4.0", "zod": "^3.23.8" }, "bin": { "lex": "dist/index.js" } }, ""],
240
+
"@atproto/lex-cli": ["@atproto/lex-cli@0.9.7", "", { "dependencies": { "@atproto/lexicon": "^0.5.2", "@atproto/syntax": "^0.4.1", "chalk": "^4.1.2", "commander": "^9.4.0", "prettier": "^3.2.5", "ts-morph": "^24.0.0", "yesno": "^0.4.0", "zod": "^3.23.8" }, "bin": { "lex": "dist/index.js" } }, "sha512-UZVf0pK0mB4qiuwbnrxmV0mC9/Vk2v7W3u9pd4wc4GFojzAyGP76MF2TiwWFya5mgzC7723/r5Jb4ADg0rtfng=="],
223
241
224
242
"@atproto/lex-data": ["@atproto/lex-data@0.0.2", "", { "dependencies": { "@atproto/syntax": "0.4.2", "multiformats": "^9.9.0", "tslib": "^2.8.1", "uint8arrays": "3.0.0", "unicode-segmenter": "^0.14.0" } }, "sha512-euV2rDGi+coH8qvZOU+ieUOEbwPwff9ca6IiXIqjZJ76AvlIpj7vtAyIRCxHUW2BoU6h9yqyJgn9MKD2a7oIwg=="],
225
243
···
227
245
228
246
"@atproto/lexicon": ["@atproto/lexicon@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.4", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-lRmJgMA8f5j7VB5Iu5cp188ald5FuI4FlmZ7nn6EBrk1dgOstWVrI5Ft6K3z2vjyLZRG6nzknlsw+tDP63p7bQ=="],
229
247
230
-
"@atproto/oauth-client": ["@atproto/oauth-client@0.5.8", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.2", "@atproto-labs/fetch": "0.2.3", "@atproto-labs/handle-resolver": "0.3.2", "@atproto-labs/identity-resolver": "0.3.2", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.1", "@atproto/jwk": "0.6.0", "@atproto/oauth-types": "0.5.0", "@atproto/xrpc": "0.7.5", "core-js": "^3", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
248
+
"@atproto/oauth-client": ["@atproto/oauth-client@0.5.10", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.4", "@atproto-labs/fetch": "0.2.3", "@atproto-labs/handle-resolver": "0.3.4", "@atproto-labs/identity-resolver": "0.3.4", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.3", "@atproto/jwk": "0.6.0", "@atproto/oauth-types": "0.5.2", "@atproto/xrpc": "0.7.6", "core-js": "^3", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-2mdJFyYbaOw3e/1KMBOQ2/J9p+MfWW8kE6FKdExWrJ7JPJpTJw2ZF2EmdGHCVeXw386dQgXbLkr+w4vbgSqfMQ=="],
231
249
232
-
"@atproto/oauth-client-node": ["@atproto/oauth-client-node@0.3.10", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.2", "@atproto-labs/handle-resolver-node": "0.1.21", "@atproto-labs/simple-store": "0.3.0", "@atproto/did": "0.2.1", "@atproto/jwk": "0.6.0", "@atproto/jwk-jose": "0.1.11", "@atproto/jwk-webcrypto": "0.2.0", "@atproto/oauth-client": "0.5.8", "@atproto/oauth-types": "0.5.0" } }, ""],
250
+
"@atproto/oauth-client-node": ["@atproto/oauth-client-node@0.3.12", "", { "dependencies": { "@atproto-labs/did-resolver": "0.2.4", "@atproto-labs/handle-resolver-node": "0.1.23", "@atproto-labs/simple-store": "0.3.0", "@atproto/did": "0.2.3", "@atproto/jwk": "0.6.0", "@atproto/jwk-jose": "0.1.11", "@atproto/jwk-webcrypto": "0.2.0", "@atproto/oauth-client": "0.5.10", "@atproto/oauth-types": "0.5.2" } }, "sha512-9ejfO1H8qo3EbiAJgxKcdcR5Ay/9hgaC5OdxtTN63bcOrkIhvBN0xpVPGZYLL1iJQyNeK1T5m/LDrv4gUS1B+g=="],
233
251
234
-
"@atproto/oauth-types": ["@atproto/oauth-types@0.5.0", "", { "dependencies": { "@atproto/did": "0.2.1", "@atproto/jwk": "0.6.0", "zod": "^3.23.8" } }, ""],
252
+
"@atproto/oauth-types": ["@atproto/oauth-types@0.5.2", "", { "dependencies": { "@atproto/did": "0.2.3", "@atproto/jwk": "0.6.0", "zod": "^3.23.8" } }, "sha512-9DCDvtvCanTwAaU5UakYDO0hzcOITS3RutK5zfLytE5Y9unj0REmTDdN8Xd8YCfUJl7T/9pYpf04Uyq7bFTASg=="],
235
253
236
254
"@atproto/repo": ["@atproto/repo@0.8.11", "", { "dependencies": { "@atproto/common": "^0.5.0", "@atproto/common-web": "^0.4.4", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.2", "@ipld/dag-cbor": "^7.0.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "varint": "^6.0.0", "zod": "^3.23.8" } }, "sha512-b/WCu5ITws4ILHoXiZz0XXB5U9C08fUVzkBQDwpnme62GXv8gUaAPL/ttG61OusW09ARwMMQm4vxoP0hTFg+zA=="],
237
255
···
239
257
240
258
"@atproto/syntax": ["@atproto/syntax@0.4.2", "", {}, "sha512-X9XSRPinBy/0VQ677j8VXlBsYSsUXaiqxWVpGGxJYsAhugdQRb0jqaVKJFtm6RskeNkV6y9xclSUi9UYG/COrA=="],
241
259
242
-
"@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=="],
260
+
"@atproto/ws-client": ["@atproto/ws-client@0.0.2", "", { "dependencies": { "@atproto/common": "^0.4.12", "ws": "^8.12.0" } }, "sha512-yb11WtI9cZfx/00MTgZRabB97Quf/TerMmtzIm2H2YirIq2oW++NPoufXYCuXuQGR4ep4fvCyzz0/GX95jCONQ=="],
243
261
244
262
"@atproto/xrpc": ["@atproto/xrpc@0.7.6", "", { "dependencies": { "@atproto/lexicon": "^0.5.2", "zod": "^3.23.8" } }, "sha512-RvCf4j0JnKYWuz3QzsYCntJi3VuiAAybQsMIUw2wLWcHhchO9F7UaBZINLL2z0qc/cYWPv5NSwcVydMseoCZLA=="],
245
263
246
-
"@atproto/xrpc-server": ["@atproto/xrpc-server@0.9.5", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@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" } }, ""],
264
+
"@atproto/xrpc-server": ["@atproto/xrpc-server@0.9.6", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@atproto/ws-client": "^0.0.2", "@atproto/xrpc": "^0.7.5", "cbor-x": "^1.5.1", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "uint8arrays": "3.0.0", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-N/wPK0VEk8lZLkVsfG1wlkINQnBLO2fzWT+xclOjYl5lJwDi5xgiiyEQJAyZN49d6cmbsONu0SuOVw9pa5xLCw=="],
265
+
266
+
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
267
+
268
+
"@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="],
269
+
270
+
"@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="],
271
+
272
+
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
273
+
274
+
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
275
+
276
+
"@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
277
+
278
+
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
279
+
280
+
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.962.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/credential-provider-node": "3.962.0", "@aws-sdk/middleware-bucket-endpoint": "3.957.0", "@aws-sdk/middleware-expect-continue": "3.957.0", "@aws-sdk/middleware-flexible-checksums": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-location-constraint": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-sdk-s3": "3.957.0", "@aws-sdk/middleware-ssec": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/signature-v4-multi-region": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/eventstream-serde-browser": "^4.2.7", "@smithy/eventstream-serde-config-resolver": "^4.3.7", "@smithy/eventstream-serde-node": "^4.2.7", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-blob-browser": "^4.2.8", "@smithy/hash-node": "^4.2.7", "@smithy/hash-stream-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/md5-js": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-I2/1McBZCcM3PfM4ck8D6gnZR3K7+yl1fGkwTq/3ThEn9tdLjNwcdgTbPfxfX6LoecLrH9Ekoo+D9nmQ0T261w=="],
281
+
282
+
"@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.958.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6qNCIeaMzKzfqasy2nNRuYnMuaMebCcCPP4J2CVGkA8QYMbIVKPlkn9bpB20Vxe6H/r3jtCCLQaOJjVTx/6dXg=="],
283
+
284
+
"@aws-sdk/core": ["@aws-sdk/core@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/xml-builder": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrZgDnF1lQZv75a52nFWs6MExihJF2GZB6ETZRqr6jMwhrk2kbJPUtvgbifwcL7AYmVqHQDJBrR/MqkwwFCpiw=="],
285
+
286
+
"@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-qSwSfI+qBU9HDsd6/4fM9faCxYJx2yDuHtj+NVOQ6XYDWQzFab/hUdwuKZ77Pi6goLF1pBZhJ2azaC2w7LbnTA=="],
287
+
288
+
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-475mkhGaWCr+Z52fOOVb/q2VHuNvqEDixlYIkeaO6xJ6t9qR0wpLt4hOQaR6zR1wfZV0SlE7d8RErdYq/PByog=="],
289
+
290
+
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-8dS55QHRxXgJlHkEYaCGZIhieCs9NU1HU1BcqQ4RfUdSsfRdxxktqUKgCnBnOOn0oD3PPA8cQOCAVgIyRb3Rfw=="],
291
+
292
+
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.962.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/credential-provider-env": "3.957.0", "@aws-sdk/credential-provider-http": "3.957.0", "@aws-sdk/credential-provider-login": "3.962.0", "@aws-sdk/credential-provider-process": "3.957.0", "@aws-sdk/credential-provider-sso": "3.958.0", "@aws-sdk/credential-provider-web-identity": "3.958.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-h0kVnXLW2d3nxbcrR/Pfg3W/+YoCguasWz7/3nYzVqmdKarGrpJzaFdoZtLgvDSZ8VgWUC4lWOTcsDMV0UNqUQ=="],
293
+
294
+
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.962.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-kHYH6Av2UifG3mPkpPUNRh/PuX6adaAcpmsclJdHdxlixMCRdh8GNeEihq480DC0GmfqdpoSf1w2CLmLLPIS6w=="],
295
+
296
+
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.962.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.957.0", "@aws-sdk/credential-provider-http": "3.957.0", "@aws-sdk/credential-provider-ini": "3.962.0", "@aws-sdk/credential-provider-process": "3.957.0", "@aws-sdk/credential-provider-sso": "3.958.0", "@aws-sdk/credential-provider-web-identity": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-CS78NsWRxLa+nWqeWBEYMZTLacMFIXs1C5WJuM9kD05LLiWL32ksljoPsvNN24Bc7rCSQIIMx/U3KGvkDVZMVg=="],
297
+
298
+
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/KIz9kadwbeLy6SKvT79W81Y+hb/8LMDyeloA2zhouE28hmne+hLn0wNCQXAAupFFlYOAtZR2NTBs7HBAReJlg=="],
299
+
300
+
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.958.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.958.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/token-providers": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-CBYHJ5ufp8HC4q+o7IJejCUctJXWaksgpmoFpXerbjAso7/Fg7LLUu9inXVOxlHKLlvYekDXjIUBXDJS2WYdgg=="],
301
+
302
+
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.958.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-dgnvwjMq5Y66WozzUzxNkCFap+umHUtqMMKlr8z/vl9NYMLem/WUbWNpFFOVFWquXikc+ewtpBMR4KEDXfZ+KA=="],
303
+
304
+
"@aws-sdk/lib-storage": ["@aws-sdk/lib-storage@3.962.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/smithy-client": "^4.10.2", "buffer": "5.6.0", "events": "3.3.0", "stream-browserify": "3.0.0", "tslib": "^2.6.2" }, "peerDependencies": { "@aws-sdk/client-s3": "^3.962.0" } }, "sha512-Ai5gWRQkzsUMQ6NPoZZoiLXoQ6/yPRcR4oracIVjyWcu48TfBpsRgbqY/5zNOM55ag1wPX9TtJJGOhK3TNk45g=="],
305
+
306
+
"@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws-sdk/util-arn-parser": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iczcn/QRIBSpvsdAS/rbzmoBpleX1JBjXvCynMbDceVLBIcVrwT1hXECrhtIC2cjh4HaLo9ClAbiOiWuqt+6MA=="],
307
+
308
+
"@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-AlbK3OeVNwZZil0wlClgeI/ISlOt/SPUxBsIns876IFaVu/Pj3DgImnYhpcJuFRek4r4XM51xzIaGQXM6GDHGg=="],
309
+
310
+
"@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.957.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/crc64-nvme": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iJpeVR5V8se1hl2pt+k8bF/e9JO4KWgPCMjg8BtRspNtKIUGy7j6msYvbDixaKZaF2Veg9+HoYcOhwnZumjXSA=="],
311
+
312
+
"@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA=="],
313
+
314
+
"@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-y8/W7TOQpmDJg/fPYlqAhwA4+I15LrS7TwgUEoxogtkD8gfur9wFMRLT8LCyc9o4NMEcAnK50hSb4+wB0qv6tQ=="],
315
+
316
+
"@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ=="],
317
+
318
+
"@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA=="],
319
+
320
+
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-arn-parser": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-5B2qY2nR2LYpxoQP0xUum5A1UNvH2JQpLHDH1nWFNF/XetV7ipFHksMxPNhtJJ6ARaWhQIDXfOUj0jcnkJxXUg=="],
321
+
322
+
"@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-qwkmrK0lizdjNt5qxl4tHYfASh8DFpHXM1iDVo+qHe+zuslfMqQEGRkzxS8tJq/I+8F0c6v3IKOveKJAfIvfqQ=="],
323
+
324
+
"@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.957.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-50vcHu96XakQnIvlKJ1UoltrFODjsq2KvtTgHiPFteUS884lQnK5VC/8xd1Msz/1ONpLMzdCVproCQqhDTtMPQ=="],
325
+
326
+
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.958.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.957.0", "@aws-sdk/middleware-host-header": "3.957.0", "@aws-sdk/middleware-logger": "3.957.0", "@aws-sdk/middleware-recursion-detection": "3.957.0", "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/region-config-resolver": "3.957.0", "@aws-sdk/types": "3.957.0", "@aws-sdk/util-endpoints": "3.957.0", "@aws-sdk/util-user-agent-browser": "3.957.0", "@aws-sdk/util-user-agent-node": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-/KuCcS8b5TpQXkYOrPLYytrgxBhv81+5pChkOlhegbeHttjM69pyUpQVJqyfDM/A7wPLnDrzCAnk4zaAOkY0Nw=="],
327
+
328
+
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A=="],
329
+
330
+
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.957.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-t6UfP1xMUigMMzHcb7vaZcjv7dA2DQkk9C/OAP1dKyrE0vb4lFGDaTApi17GN6Km9zFxJthEMUbBc7DL0hq1Bg=="],
331
+
332
+
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.958.0", "", { "dependencies": { "@aws-sdk/core": "3.957.0", "@aws-sdk/nested-clients": "3.958.0", "@aws-sdk/types": "3.957.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-UCj7lQXODduD1myNJQkV+LYcGYJ9iiMggR8ow8Hva1g3A/Na5imNXzz6O67k7DAee0TYpy+gkNw+SizC6min8Q=="],
333
+
334
+
"@aws-sdk/types": ["@aws-sdk/types@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg=="],
335
+
336
+
"@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.957.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Aj6m+AyrhWyg8YQ4LDPg2/gIfGHCEcoQdBt5DeSFogN5k9mmJPOJ+IAmNSWmWRjpOxEy6eY813RNDI6qS97M0g=="],
337
+
338
+
"@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw=="],
339
+
340
+
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.957.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nhmgKHnNV9K+i9daumaIz8JTLsIIML9PE/HUks5liyrjUzenjW/aHoc7WJ9/Td/gPZtayxFnXQSJRb/fDlBuJw=="],
341
+
342
+
"@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.957.0", "", { "dependencies": { "@aws-sdk/types": "3.957.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw=="],
343
+
344
+
"@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.957.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.957.0", "@aws-sdk/types": "3.957.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-ycbYCwqXk4gJGp0Oxkzf2KBeeGBdTxz559D41NJP8FlzSej1Gh7Rk40Zo6AyTfsNWkrl/kVi1t937OIzC5t+9Q=="],
345
+
346
+
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.957.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA=="],
347
+
348
+
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="],
247
349
248
350
"@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="],
249
351
250
-
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, ""],
352
+
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="],
251
353
252
-
"@cbor-extract/cbor-extract-darwin-arm64": ["@cbor-extract/cbor-extract-darwin-arm64@2.2.0", "", { "os": "darwin", "cpu": "arm64" }, ""],
354
+
"@cbor-extract/cbor-extract-darwin-arm64": ["@cbor-extract/cbor-extract-darwin-arm64@2.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w=="],
253
355
254
-
"@elysiajs/cors": ["@elysiajs/cors@1.4.0", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, ""],
356
+
"@cbor-extract/cbor-extract-darwin-x64": ["@cbor-extract/cbor-extract-darwin-x64@2.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w=="],
255
357
256
-
"@elysiajs/eden": ["@elysiajs/eden@1.4.4", "", { "peerDependencies": { "elysia": ">= 1.4.0-exp.0" } }, ""],
358
+
"@cbor-extract/cbor-extract-linux-arm": ["@cbor-extract/cbor-extract-linux-arm@2.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q=="],
257
359
258
-
"@elysiajs/openapi": ["@elysiajs/openapi@1.4.11", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, ""],
360
+
"@cbor-extract/cbor-extract-linux-arm64": ["@cbor-extract/cbor-extract-linux-arm64@2.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ=="],
259
361
260
-
"@elysiajs/opentelemetry": ["@elysiajs/opentelemetry@1.4.6", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/instrumentation": "^0.200.0", "@opentelemetry/sdk-node": "^0.200.0" }, "peerDependencies": { "elysia": ">= 1.4.0" } }, ""],
362
+
"@cbor-extract/cbor-extract-linux-x64": ["@cbor-extract/cbor-extract-linux-x64@2.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw=="],
261
363
262
-
"@elysiajs/static": ["@elysiajs/static@1.4.6", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, ""],
364
+
"@cbor-extract/cbor-extract-win32-x64": ["@cbor-extract/cbor-extract-win32-x64@2.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w=="],
365
+
366
+
"@elysiajs/cors": ["@elysiajs/cors@1.4.0", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-pb0SCzBfFbFSYA/U40HHO7R+YrcXBJXOWgL20eSViK33ol1e20ru2/KUaZYo5IMUn63yaTJI/bQERuQ+77ND8g=="],
367
+
368
+
"@elysiajs/eden": ["@elysiajs/eden@1.4.5", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-hIOeH+S5NU/84A7+t8yB1JjxqjmzRkBF9fnLn6y+AH8EcF39KumOAnciMhIOkhhThVZvXZ3d+GsizRc+Fxoi8g=="],
369
+
370
+
"@elysiajs/openapi": ["@elysiajs/openapi@1.4.11", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-d75bMxYJpN6qSDi/z9L1S7SLk1S/8Px+cTb3W2lrYzU8uQ5E0kXdy1oOMJEfTyVsz3OA19NP9KNxE7ztSbLBLg=="],
371
+
372
+
"@elysiajs/opentelemetry": ["@elysiajs/opentelemetry@1.4.8", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/instrumentation": "^0.200.0", "@opentelemetry/sdk-node": "^0.200.0" }, "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-c9unbcdXfehExCv1GsiTCfos5SyIAyDwP7apcMeXmUMBaJZiAYMfiEH8RFFFIfIHJHC/xlNJzUPodkcUaaoJJQ=="],
373
+
374
+
"@elysiajs/static": ["@elysiajs/static@1.4.7", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-Go4kIXZ0G3iWfkAld07HmLglqIDMVXdyRKBQK/sVEjtpDdjHNb+rUIje73aDTWpZYg4PEVHUpi9v4AlNEwrQug=="],
263
375
264
376
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.26.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-hj0sKNCQOOo2fgyII3clmJXP28VhgDfU5iy3GNHlWO76KG6N7x4D9ezH5lJtQTG+1J6MFDAJXC1qsI+W+LvZoA=="],
265
377
···
313
425
314
426
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.26.0", "", { "os": "win32", "cpu": "x64" }, "sha512-WAckBKaVnmFqbEhbymrPK7M086DQMpL1XoRbpmN0iW8k5JSXjDRQBhcZNa0VweItknLq9eAeCL34jK7/CDcw7A=="],
315
427
316
-
"@grpc/grpc-js": ["@grpc/grpc-js@1.14.1", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, ""],
428
+
"@grpc/grpc-js": ["@grpc/grpc-js@1.14.2", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-QzVUtEFyu05UNx2xr0fCQmStUO17uVQhGNowtxs00IgTZT6/W2PBLfUkj30s0FKJ29VtTa3ArVNIhNP6akQhqA=="],
317
429
318
-
"@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, ""],
430
+
"@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="],
319
431
320
432
"@hono/node-server": ["@hono/node-server@1.19.6", "", { "peerDependencies": { "hono": "^4" } }, "sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw=="],
321
433
322
-
"@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, ""],
434
+
"@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="],
323
435
324
436
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
325
437
···
331
443
332
444
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
333
445
334
-
"@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, ""],
446
+
"@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="],
447
+
448
+
"@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
449
+
450
+
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
451
+
452
+
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
453
+
454
+
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q=="],
455
+
456
+
"@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.0.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-IEkJGzK1A9v3/EHjXh3s2IiFc6L4jfK+lNgKVgUjeUJQRRhnVFMIO3TAvKwonm9O1HebCuoOt98v8bZW7oVQHA=="],
457
+
458
+
"@opentelemetry/core": ["@opentelemetry/core@1.29.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-gmT7vAreXl0DTHD2rVZcw3+l2g84+5XiHIqdBUxXbExymPCvSsGOpiwMmn8nkiJur28STV31wnhIDrzWDPzjfA=="],
459
+
460
+
"@opentelemetry/exporter-logs-otlp-grpc": ["@opentelemetry/exporter-logs-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+3MDfa5YQPGM3WXxW9kqGD85Q7s9wlEMVNhXXG7tYFLnIeaseUt9YtCeFhEDFzfEktacdFpOtXmJuNW8cHbU5A=="],
461
+
462
+
"@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-KfWw49htbGGp9s8N4KI8EQ9XuqKJ0VG+yVYVYFiCYSjEV32qpQ5qZ9UZBzOZ6xRb+E16SXOSCT3RkqBVSABZ+g=="],
463
+
464
+
"@opentelemetry/exporter-logs-otlp-proto": ["@opentelemetry/exporter-logs-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-GmahpUU/55hxfH4TP77ChOfftADsCq/nuri73I/AVLe2s4NIglvTsaACkFVZAVmnXXyPS00Fk3x27WS3yO07zA=="],
335
465
336
-
"@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, ""],
466
+
"@opentelemetry/exporter-metrics-otlp-grpc": ["@opentelemetry/exporter-metrics-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-uHawPRvKIrhqH09GloTuYeq2BjyieYHIpiklOvxm9zhrCL2eRsnI/6g9v2BZTVtGp8tEgIa7rCQ6Ltxw6NBgew=="],
337
467
338
-
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, ""],
468
+
"@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.56.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/otlp-exporter-base": "0.56.0", "@opentelemetry/otlp-transformer": "0.56.0", "@opentelemetry/resources": "1.29.0", "@opentelemetry/sdk-metrics": "1.29.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-GD5QuCT6js+mDpb5OBO6OSyCH+k2Gy3xPHJV9BnjV8W6kpSuY8y2Samzs5vl23UcGMq6sHLAbs+Eq/VYsLMiVw=="],
339
469
340
-
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, ""],
470
+
"@opentelemetry/exporter-metrics-otlp-proto": ["@opentelemetry/exporter-metrics-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-E+uPj0yyvz81U9pvLZp3oHtFrEzNSqKGVkIViTQY1rH3TOobeJPSpLnTVXACnCwkPR5XeTvPnK3pZ2Kni8AFMg=="],
341
471
342
-
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
472
+
"@opentelemetry/exporter-prometheus": ["@opentelemetry/exporter-prometheus@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ZYdlU9r0USuuYppiDyU2VFRA0kFl855ylnb3N/2aOlXrbA4PMCznen7gmPbetGQu7pz8Jbaf4fwvrDnVdQQXSw=="],
473
+
474
+
"@opentelemetry/exporter-trace-otlp-grpc": ["@opentelemetry/exporter-trace-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-hmeZrUkFl1YMsgukSuHCFPYeF9df0hHoKeHUthRKFCxiURs+GwF1VuabuHmBMZnjTbsuvNjOB+JSs37Csem/5Q=="],
475
+
476
+
"@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Goi//m/7ZHeUedxTGVmEzH19NgqJY+Bzr6zXo1Rni1+hwqaksEyJ44gdlEMREu6dzX1DlAaH/qSykSVzdrdafA=="],
343
477
344
-
"@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.0.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, ""],
478
+
"@opentelemetry/exporter-trace-otlp-proto": ["@opentelemetry/exporter-trace-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-V9TDSD3PjK1OREw2iT9TUTzNYEVWJk4Nhodzhp9eiz4onDMYmPy3LaGbPv81yIR6dUb/hNp/SIhpiCHwFUq2Vg=="],
345
479
346
-
"@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, ""],
480
+
"@opentelemetry/exporter-zipkin": ["@opentelemetry/exporter-zipkin@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" } }, "sha512-icxaKZ+jZL/NHXX8Aru4HGsrdhK0MLcuRXkX5G5IRmCgoRLw+Br6I/nMVozX2xjGGwV7hw2g+4Slj8K7s4HbVg=="],
347
481
348
-
"@opentelemetry/exporter-logs-otlp-grpc": ["@opentelemetry/exporter-logs-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
482
+
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-pmPlzfJd+vvgaZd/reMsC8RWgTXn2WY1OWT5RT42m3aOn5532TozwXNDhg1vzqJ+jnvmkREcdLr27ebJEQt0Jg=="],
349
483
350
-
"@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
484
+
"@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.56.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/otlp-transformer": "0.56.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-eURvv0fcmBE+KE1McUeRo+u0n18ZnUeSc7lDlW/dzlqFYasEbsztTK4v0Qf8C4vEY+aMTjPKUxBG0NX2Te3Pmw=="],
351
485
352
-
"@opentelemetry/exporter-logs-otlp-proto": ["@opentelemetry/exporter-logs-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
486
+
"@opentelemetry/otlp-grpc-exporter-base": ["@opentelemetry/otlp-grpc-exporter-base@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CK2S+bFgOZ66Bsu5hlDeOX6cvW5FVtVjFFbWuaJP0ELxJKBB6HlbLZQ2phqz/uLj1cWap5xJr/PsR3iGoB7Vqw=="],
353
487
354
-
"@opentelemetry/exporter-metrics-otlp-grpc": ["@opentelemetry/exporter-metrics-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
488
+
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.56.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.56.0", "@opentelemetry/core": "1.29.0", "@opentelemetry/resources": "1.29.0", "@opentelemetry/sdk-logs": "0.56.0", "@opentelemetry/sdk-metrics": "1.29.0", "@opentelemetry/sdk-trace-base": "1.29.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-kVkH/W2W7EpgWWpyU5VnnjIdSD7Y7FljQYObAQSKdRcejiwMj2glypZtUdfq1LTJcv4ht0jyTrw1D3CCxssNtQ=="],
355
489
356
-
"@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
490
+
"@opentelemetry/propagator-b3": ["@opentelemetry/propagator-b3@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-blx9S2EI49Ycuw6VZq+bkpaIoiJFhsDuvFGhBIoH3vJ5oYjJ2U0s3fAM5jYft99xVIAv6HqoPtlP9gpVA2IZtA=="],
357
491
358
-
"@opentelemetry/exporter-metrics-otlp-proto": ["@opentelemetry/exporter-metrics-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
492
+
"@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Mbm/LSFyAtQKP0AQah4AfGgsD+vsZcyreZoQ5okFBk33hU7AquU4TltgyL9dvaO8/Zkoud8/0gEvwfOZ5d7EPA=="],
359
493
360
-
"@opentelemetry/exporter-prometheus": ["@opentelemetry/exporter-prometheus@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
494
+
"@opentelemetry/resources": ["@opentelemetry/resources@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA=="],
361
495
362
-
"@opentelemetry/exporter-trace-otlp-grpc": ["@opentelemetry/exporter-trace-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
496
+
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-VZG870063NLfObmQQNtCVcdXXLzI3vOjjrRENmU37HYiPFa0ZXpXVDsTD02Nh3AT3xYJzQaWKl2X2lQ2l7TWJA=="],
363
497
364
-
"@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
498
+
"@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@1.30.1", "", { "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog=="],
365
499
366
-
"@opentelemetry/exporter-trace-otlp-proto": ["@opentelemetry/exporter-trace-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
500
+
"@opentelemetry/sdk-node": ["@opentelemetry/sdk-node@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-logs-otlp-grpc": "0.200.0", "@opentelemetry/exporter-logs-otlp-http": "0.200.0", "@opentelemetry/exporter-logs-otlp-proto": "0.200.0", "@opentelemetry/exporter-metrics-otlp-grpc": "0.200.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/exporter-metrics-otlp-proto": "0.200.0", "@opentelemetry/exporter-prometheus": "0.200.0", "@opentelemetry/exporter-trace-otlp-grpc": "0.200.0", "@opentelemetry/exporter-trace-otlp-http": "0.200.0", "@opentelemetry/exporter-trace-otlp-proto": "0.200.0", "@opentelemetry/exporter-zipkin": "2.0.0", "@opentelemetry/instrumentation": "0.200.0", "@opentelemetry/propagator-b3": "2.0.0", "@opentelemetry/propagator-jaeger": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/sdk-trace-node": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-S/YSy9GIswnhYoDor1RusNkmRughipvTCOQrlF1dzI70yQaf68qgf5WMnzUxdlCl3/et/pvaO75xfPfuEmCK5A=="],
367
501
368
-
"@opentelemetry/exporter-zipkin": ["@opentelemetry/exporter-zipkin@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" } }, ""],
502
+
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw=="],
369
503
370
-
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
504
+
"@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.0.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.0.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-omdilCZozUjQwY3uZRBwbaRMJ3p09l4t187Lsdf0dGMye9WKD4NGcpgZRvqhI1dwcH6og+YXQEtoO9Wx3ykilg=="],
371
505
372
-
"@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
506
+
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.38.0", "", {}, "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg=="],
373
507
374
-
"@opentelemetry/otlp-grpc-exporter-base": ["@opentelemetry/otlp-grpc-exporter-base@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
508
+
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eJopQrUk0WR7jViYDC29+Rp50xGvs4GtWOXBeqCoFMzutkkO3CZvHehA4JqnjfWMTSS8toqvRhCSOpOz62Wf9w=="],
375
509
376
-
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, ""],
510
+
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-xGDePueVFrNgkS+iN0QdEFeRrx2MQ5hQ9ipRFu7N73rgoSSJsFlOKKt2uGZzunczedViIfjYl0ii0K4E9aZ0Ow=="],
377
511
378
-
"@opentelemetry/propagator-b3": ["@opentelemetry/propagator-b3@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, ""],
512
+
"@oven/bun-darwin-x64-baseline": ["@oven/bun-darwin-x64-baseline@1.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ij4wQ9ECLFf1XFry+IFUN+28if40ozDqq6+QtuyOhIwraKzXOlAUbILhRMGvM3ED3yBex2mTwlKpA4Vja/V2g=="],
379
513
380
-
"@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, ""],
514
+
"@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-DabZ3Mt1XcJneWdEEug8l7bCPVvDBRBpjUIpNnRnMFWFnzr8KBEpMcaWTwYOghjXyJdhB4MPKb19MwqyQ+FHAw=="],
381
515
382
-
"@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" } }, ""],
516
+
"@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-XWQ3tV/gtZj0wn2AdSUq/tEOKWT4OY+Uww70EbODgrrq00jxuTfq5nnYP6rkLD0M/T5BHJdQRSfQYdIni9vldw=="],
383
517
384
-
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, ""],
518
+
"@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-7eIARtKZKZDtah1aCpQUj/1/zT/zHRR063J6oAxZP9AuA547j5B9OM2D/vi/F4En7Gjk9FPjgPGTSYeqpQDzJw=="],
385
519
386
-
"@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, ""],
520
+
"@oven/bun-linux-x64-baseline": ["@oven/bun-linux-x64-baseline@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-IU8pxhIf845psOv55LqJyL+tSUc6HHMfs6FGhuJcAnyi92j+B1HjOhnFQh9MW4vjoo7do5F8AerXlvk59RGH2w=="],
387
521
388
-
"@opentelemetry/sdk-node": ["@opentelemetry/sdk-node@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-logs-otlp-grpc": "0.200.0", "@opentelemetry/exporter-logs-otlp-http": "0.200.0", "@opentelemetry/exporter-logs-otlp-proto": "0.200.0", "@opentelemetry/exporter-metrics-otlp-grpc": "0.200.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/exporter-metrics-otlp-proto": "0.200.0", "@opentelemetry/exporter-prometheus": "0.200.0", "@opentelemetry/exporter-trace-otlp-grpc": "0.200.0", "@opentelemetry/exporter-trace-otlp-http": "0.200.0", "@opentelemetry/exporter-trace-otlp-proto": "0.200.0", "@opentelemetry/exporter-zipkin": "2.0.0", "@opentelemetry/instrumentation": "0.200.0", "@opentelemetry/propagator-b3": "2.0.0", "@opentelemetry/propagator-jaeger": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/sdk-trace-node": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, ""],
522
+
"@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-xNSDRPn1yyObKteS8fyQogwsS4eCECswHHgaKM+/d4wy/omZQrXn8ZyGm/ZF9B73UfQytUfbhE7nEnrFq03f0w=="],
389
523
390
-
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, ""],
524
+
"@oven/bun-linux-x64-musl-baseline": ["@oven/bun-linux-x64-musl-baseline@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-JoRTPdAXRkNYouUlJqEncMWUKn/3DiWP03A7weBbtbsKr787gcdNna2YeyQKCb1lIXE4v1k18RM3gaOpQobGIQ=="],
391
525
392
-
"@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.0.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.0.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, ""],
526
+
"@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-kWqa1LKvDdAIzyfHxo3zGz3HFWbFHDlrNK77hKjUN42ycikvZJ+SHSX76+1OW4G8wmLETX4Jj+4BM1y01DQRIQ=="],
393
527
394
-
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.38.0", "", {}, ""],
528
+
"@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-u5eZHKq6TPJSE282KyBOicGQ2trkFml0RoUfqkPOJVo7TXGrsGYYzdsugZRnVQY/WEmnxGtBy4T3PAaPqgQViA=="],
395
529
396
530
"@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="],
397
531
···
421
555
422
556
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
423
557
424
-
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, ""],
558
+
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
559
+
560
+
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
561
+
562
+
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
563
+
564
+
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
565
+
566
+
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
567
+
568
+
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
569
+
570
+
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
571
+
572
+
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
573
+
574
+
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
575
+
576
+
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
577
+
578
+
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
579
+
580
+
"@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
581
+
582
+
"@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
583
+
584
+
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
585
+
586
+
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
587
+
588
+
"@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
589
+
590
+
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
591
+
592
+
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
593
+
594
+
"@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
595
+
596
+
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
597
+
598
+
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
599
+
600
+
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
601
+
602
+
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
603
+
604
+
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
605
+
606
+
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
607
+
608
+
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
609
+
610
+
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
611
+
612
+
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="],
613
+
614
+
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="],
615
+
616
+
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
617
+
618
+
"@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
619
+
620
+
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
621
+
622
+
"@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
623
+
624
+
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
625
+
626
+
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
627
+
628
+
"@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
629
+
630
+
"@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="],
631
+
632
+
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="],
633
+
634
+
"@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA=="],
635
+
636
+
"@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.1", "", { "dependencies": { "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ=="],
637
+
638
+
"@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="],
639
+
640
+
"@smithy/core": ["@smithy/core@3.20.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ=="],
641
+
642
+
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA=="],
643
+
644
+
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="],
645
+
646
+
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ujzPk8seYoDBmABDE5YqlhQZAXLOrtxtJLrbhHMKjBoG5b4dK4i6/mEU+6/7yXIAkqOO8sJ6YxZl+h0QQ1IJ7g=="],
647
+
648
+
"@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-x7BtAiIPSaNaWuzm24Q/mtSkv+BrISO/fmheiJ39PKRNH3RmH2Hph/bUKSOBOBC9unqfIYDhKTHwpyZycLGPVQ=="],
649
+
650
+
"@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-roySCtHC5+pQq5lK4be1fZ/WR6s/AxnPaLfCODIPArtN2du8s5Ot4mKVK3pPtijL/L654ws592JHJ1PbZFF6+A=="],
651
+
652
+
"@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.7", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-QVD+g3+icFkThoy4r8wVFZMsIP08taHVKjE6Jpmz8h5CgX/kk6pTODq5cht0OMtcapUx+xrPzUTQdA+TmO0m1g=="],
653
+
654
+
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="],
655
+
656
+
"@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.8", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.0", "@smithy/chunked-blob-reader-native": "^4.2.1", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-07InZontqsM1ggTCPSRgI7d8DirqRrnpL7nIACT4PW0AWrgDiHhjGZzbAE5UtRSiU0NISGUYe7/rri9ZeWyDpw=="],
425
657
426
-
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, ""],
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=="],
427
659
428
-
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, ""],
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=="],
429
661
430
-
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, ""],
662
+
"@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="],
431
663
432
-
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, ""],
664
+
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
433
665
434
-
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, ""],
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=="],
435
667
436
-
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, ""],
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=="],
437
669
438
-
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, ""],
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=="],
439
671
440
-
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, ""],
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=="],
441
673
442
-
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, ""],
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=="],
443
675
444
-
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, ""],
676
+
"@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="],
445
677
446
-
"@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
447
679
448
-
"@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
449
681
450
-
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
682
+
"@smithy/property-provider": ["@smithy/property-provider@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA=="],
451
683
452
-
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
684
+
"@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="],
453
685
454
-
"@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
455
687
456
-
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
688
+
"@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="],
457
689
458
-
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
459
691
460
-
"@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
461
693
462
-
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
463
695
464
-
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
465
697
466
-
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
698
+
"@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="],
467
699
468
-
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
469
701
470
-
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
471
703
472
-
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
704
+
"@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
473
705
474
-
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
706
+
"@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
475
707
476
-
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
477
709
478
-
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
710
+
"@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
479
711
480
-
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
481
713
482
-
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
483
715
484
-
"@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
485
717
486
-
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
487
719
488
-
"@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
489
721
490
-
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
491
723
492
-
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
493
725
494
-
"@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
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=="],
495
727
496
-
"@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, ""],
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=="],
497
733
498
734
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
499
735
···
527
763
528
764
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.17", "", { "os": "win32", "cpu": "x64" }, "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw=="],
529
765
530
-
"@tanstack/query-core": ["@tanstack/query-core@5.90.7", "", {}, ""],
766
+
"@tanstack/query-core": ["@tanstack/query-core@5.90.12", "", {}, "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg=="],
531
767
532
-
"@tanstack/react-query": ["@tanstack/react-query@5.90.7", "", { "dependencies": { "@tanstack/query-core": "5.90.7" }, "peerDependencies": { "react": "^18 || ^19" } }, ""],
768
+
"@tanstack/react-query": ["@tanstack/react-query@5.90.12", "", { "dependencies": { "@tanstack/query-core": "5.90.12" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg=="],
533
769
534
-
"@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, ""],
770
+
"@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="],
535
771
536
-
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, ""],
772
+
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
537
773
538
-
"@ts-morph/common": ["@ts-morph/common@0.25.0", "", { "dependencies": { "minimatch": "^9.0.4", "path-browserify": "^1.0.1", "tinyglobby": "^0.2.9" } }, ""],
774
+
"@ts-morph/common": ["@ts-morph/common@0.25.0", "", { "dependencies": { "minimatch": "^9.0.4", "path-browserify": "^1.0.1", "tinyglobby": "^0.2.9" } }, "sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg=="],
539
775
540
-
"@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="],
776
+
"@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
541
777
542
778
"@types/mime-types": ["@types/mime-types@2.1.4", "", {}, "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w=="],
543
779
544
780
"@types/node": ["@types/node@22.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ=="],
545
781
546
-
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, ""],
782
+
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
547
783
548
-
"@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, ""],
784
+
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
549
785
550
-
"@types/shimmer": ["@types/shimmer@1.2.0", "", {}, ""],
786
+
"@types/shimmer": ["@types/shimmer@1.2.0", "", {}, "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg=="],
551
787
552
788
"@wisp/atproto-utils": ["@wisp/atproto-utils@workspace:packages/@wisp/atproto-utils"],
553
789
···
565
801
566
802
"@wisp/safe-fetch": ["@wisp/safe-fetch@workspace:packages/@wisp/safe-fetch"],
567
803
568
-
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, ""],
804
+
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
569
805
570
-
"accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, ""],
806
+
"accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
571
807
572
-
"acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, ""],
808
+
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
573
809
574
-
"acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, ""],
810
+
"acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="],
575
811
576
812
"actor-typeahead": ["actor-typeahead@0.1.2", "", {}, "sha512-I97YqqNl7Kar0J/bIJvgY/KmHpssHcDElhfwVTLP7wRFlkxso2ZLBqiS2zol5A8UVUJbQK2JXYaqNpZXz8Uk2A=="],
577
813
578
-
"ansi-regex": ["ansi-regex@5.0.1", "", {}, ""],
814
+
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
579
815
580
-
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, ""],
816
+
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
581
817
582
-
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, ""],
818
+
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
583
819
584
-
"array-flatten": ["array-flatten@1.1.1", "", {}, ""],
820
+
"array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="],
585
821
586
-
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, ""],
822
+
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
587
823
588
824
"atproto-ui": ["atproto-ui@0.12.0", "", { "dependencies": { "@atcute/atproto": "^3.1.7", "@atcute/bluesky": "^3.2.3", "@atcute/client": "^4.0.3", "@atcute/identity-resolver": "^1.1.3", "@atcute/tangled": "^1.0.10" }, "peerDependencies": { "react": "^18.2.0 || ^19.0.0", "react-dom": "^18.2.0 || ^19.0.0" }, "optionalPeers": ["react-dom"] }, "sha512-vdJmKNyuGWspuIIvySD601dL8wLJafgxfS/6NGBvbBFectoiaZ92Cua2JdDuSD/uRxUnRJ3AvMg7eL0M39DZ3Q=="],
589
825
590
-
"await-lock": ["await-lock@2.2.2", "", {}, ""],
826
+
"await-lock": ["await-lock@2.2.2", "", {}, "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="],
591
827
592
-
"balanced-match": ["balanced-match@1.0.2", "", {}, ""],
828
+
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
829
+
830
+
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
593
831
594
-
"base64-js": ["base64-js@1.5.1", "", {}, ""],
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=="],
595
833
596
-
"body-parser": ["body-parser@1.20.3", "", { "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.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, ""],
834
+
"bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="],
597
835
598
-
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, ""],
836
+
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
599
837
600
838
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
601
839
602
-
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, ""],
840
+
"buffer": ["buffer@5.6.0", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw=="],
603
841
604
-
"bun": ["bun@1.3.2", "", { "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, ""],
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=="],
605
843
606
-
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.1.2", "", { "peerDependencies": { "bun": ">=1.0.0" } }, ""],
844
+
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.1.2", "", { "peerDependencies": { "bun": ">=1.0.0" } }, "sha512-41jNC1tZRSK3s1o7pTNrLuQG8kL/0vR/JgiTmZAJ1eHwe0w5j6HFPKeqEk0WAD13jfrUC7+ULuewFBBCoADPpg=="],
607
845
608
-
"bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="],
846
+
"bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="],
609
847
610
-
"bytes": ["bytes@3.1.2", "", {}, ""],
848
+
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
611
849
612
-
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, ""],
850
+
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
613
851
614
-
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, ""],
852
+
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
615
853
616
-
"cbor-extract": ["cbor-extract@2.2.0", "", { "dependencies": { "node-gyp-build-optional-packages": "5.1.1" }, "optionalDependencies": { "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0" }, "bin": { "download-cbor-prebuilds": "bin/download-prebuilds.js" } }, ""],
854
+
"cbor-extract": ["cbor-extract@2.2.0", "", { "dependencies": { "node-gyp-build-optional-packages": "5.1.1" }, "optionalDependencies": { "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0", "@cbor-extract/cbor-extract-darwin-x64": "2.2.0", "@cbor-extract/cbor-extract-linux-arm": "2.2.0", "@cbor-extract/cbor-extract-linux-arm64": "2.2.0", "@cbor-extract/cbor-extract-linux-x64": "2.2.0", "@cbor-extract/cbor-extract-win32-x64": "2.2.0" }, "bin": { "download-cbor-prebuilds": "bin/download-prebuilds.js" } }, "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA=="],
617
855
618
-
"cbor-x": ["cbor-x@1.6.0", "", { "optionalDependencies": { "cbor-extract": "^2.2.0" } }, ""],
856
+
"cbor-x": ["cbor-x@1.6.0", "", { "optionalDependencies": { "cbor-extract": "^2.2.0" } }, "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg=="],
619
857
620
-
"cborg": ["cborg@1.10.2", "", { "bin": "cli.js" }, ""],
858
+
"cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="],
621
859
622
-
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, ""],
860
+
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
623
861
624
-
"cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, ""],
862
+
"cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="],
625
863
626
-
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, ""],
864
+
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
627
865
628
-
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, ""],
866
+
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
629
867
630
-
"clsx": ["clsx@2.1.1", "", {}, ""],
868
+
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
631
869
632
-
"code-block-writer": ["code-block-writer@13.0.3", "", {}, ""],
870
+
"code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="],
633
871
634
-
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, ""],
872
+
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
635
873
636
-
"color-name": ["color-name@1.1.4", "", {}, ""],
874
+
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
637
875
638
-
"commander": ["commander@9.5.0", "", {}, ""],
876
+
"commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="],
639
877
640
-
"content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, ""],
878
+
"content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="],
641
879
642
-
"content-type": ["content-type@1.0.5", "", {}, ""],
880
+
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
643
881
644
882
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
645
883
646
-
"cookie-signature": ["cookie-signature@1.0.6", "", {}, ""],
884
+
"cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="],
647
885
648
-
"core-js": ["core-js@3.46.0", "", {}, ""],
886
+
"core-js": ["core-js@3.47.0", "", {}, "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg=="],
649
887
650
-
"csstype": ["csstype@3.1.3", "", {}, ""],
888
+
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
651
889
652
-
"debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, ""],
890
+
"debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
653
891
654
-
"depd": ["depd@2.0.0", "", {}, ""],
892
+
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
655
893
656
-
"destroy": ["destroy@1.2.0", "", {}, ""],
894
+
"destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="],
657
895
658
896
"detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
659
897
660
-
"detect-node-es": ["detect-node-es@1.1.0", "", {}, ""],
898
+
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
661
899
662
-
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, ""],
900
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
663
901
664
-
"ee-first": ["ee-first@1.1.1", "", {}, ""],
902
+
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
665
903
666
904
"elysia": ["elysia@1.4.18", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "0.2.5", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-A6BhlipmSvgCy69SBgWADYZSdDIj3fT2gk8/9iMAC8iD+aGcnCr0fitziX0xr36MFDs/fsvVp8dWqxeq1VCgKg=="],
667
905
668
-
"emoji-regex": ["emoji-regex@8.0.0", "", {}, ""],
906
+
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
669
907
670
-
"encodeurl": ["encodeurl@2.0.0", "", {}, ""],
908
+
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
671
909
672
910
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
673
911
674
-
"es-define-property": ["es-define-property@1.0.1", "", {}, ""],
912
+
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
675
913
676
-
"es-errors": ["es-errors@1.3.0", "", {}, ""],
914
+
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
677
915
678
-
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, ""],
916
+
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
679
917
680
-
"esbuild": ["esbuild@0.26.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.26.0", "@esbuild/android-arm": "0.26.0", "@esbuild/android-arm64": "0.26.0", "@esbuild/android-x64": "0.26.0", "@esbuild/darwin-arm64": "0.26.0", "@esbuild/darwin-x64": "0.26.0", "@esbuild/freebsd-arm64": "0.26.0", "@esbuild/freebsd-x64": "0.26.0", "@esbuild/linux-arm": "0.26.0", "@esbuild/linux-arm64": "0.26.0", "@esbuild/linux-ia32": "0.26.0", "@esbuild/linux-loong64": "0.26.0", "@esbuild/linux-mips64el": "0.26.0", "@esbuild/linux-ppc64": "0.26.0", "@esbuild/linux-riscv64": "0.26.0", "@esbuild/linux-s390x": "0.26.0", "@esbuild/linux-x64": "0.26.0", "@esbuild/netbsd-arm64": "0.26.0", "@esbuild/netbsd-x64": "0.26.0", "@esbuild/openbsd-arm64": "0.26.0", "@esbuild/openbsd-x64": "0.26.0", "@esbuild/openharmony-arm64": "0.26.0", "@esbuild/sunos-x64": "0.26.0", "@esbuild/win32-arm64": "0.26.0", "@esbuild/win32-ia32": "0.26.0", "@esbuild/win32-x64": "0.26.0" }, "bin": "bin/esbuild" }, "sha512-3Hq7jri+tRrVWha+ZeIVhl4qJRha/XjRNSopvTsOaCvfPHrflTYTcUFcEjMKdxofsXXsdc4zjg5NOTnL4Gl57Q=="],
918
+
"esbuild": ["esbuild@0.26.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.26.0", "@esbuild/android-arm": "0.26.0", "@esbuild/android-arm64": "0.26.0", "@esbuild/android-x64": "0.26.0", "@esbuild/darwin-arm64": "0.26.0", "@esbuild/darwin-x64": "0.26.0", "@esbuild/freebsd-arm64": "0.26.0", "@esbuild/freebsd-x64": "0.26.0", "@esbuild/linux-arm": "0.26.0", "@esbuild/linux-arm64": "0.26.0", "@esbuild/linux-ia32": "0.26.0", "@esbuild/linux-loong64": "0.26.0", "@esbuild/linux-mips64el": "0.26.0", "@esbuild/linux-ppc64": "0.26.0", "@esbuild/linux-riscv64": "0.26.0", "@esbuild/linux-s390x": "0.26.0", "@esbuild/linux-x64": "0.26.0", "@esbuild/netbsd-arm64": "0.26.0", "@esbuild/netbsd-x64": "0.26.0", "@esbuild/openbsd-arm64": "0.26.0", "@esbuild/openbsd-x64": "0.26.0", "@esbuild/openharmony-arm64": "0.26.0", "@esbuild/sunos-x64": "0.26.0", "@esbuild/win32-arm64": "0.26.0", "@esbuild/win32-ia32": "0.26.0", "@esbuild/win32-x64": "0.26.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-3Hq7jri+tRrVWha+ZeIVhl4qJRha/XjRNSopvTsOaCvfPHrflTYTcUFcEjMKdxofsXXsdc4zjg5NOTnL4Gl57Q=="],
681
919
682
-
"escalade": ["escalade@3.2.0", "", {}, ""],
920
+
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
683
921
684
-
"escape-html": ["escape-html@1.0.3", "", {}, ""],
922
+
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
685
923
686
924
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
687
925
688
-
"etag": ["etag@1.8.1", "", {}, ""],
926
+
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
689
927
690
-
"event-target-shim": ["event-target-shim@5.0.1", "", {}, ""],
928
+
"event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
691
929
692
930
"eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
693
931
694
-
"events": ["events@3.3.0", "", {}, ""],
932
+
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
695
933
696
934
"exact-mirror": ["exact-mirror@0.2.5", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-u8Wu2lO8nio5lKSJubOydsdNtQmH8ENba5m0nbQYmTvsjksXKYIS1nSShdDlO8Uem+kbo+N6eD5I03cpZ+QsRQ=="],
697
935
698
-
"express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, ""],
936
+
"express": ["express@4.22.1", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.3", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="],
699
937
700
-
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, ""],
938
+
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
701
939
702
-
"fast-redact": ["fast-redact@3.5.0", "", {}, ""],
940
+
"fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="],
703
941
704
-
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, ""],
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=="],
705
943
706
-
"fflate": ["fflate@0.8.2", "", {}, ""],
944
+
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
707
945
708
-
"file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, ""],
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=="],
709
947
710
948
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
711
949
712
-
"finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, ""],
950
+
"finalhandler": ["finalhandler@1.3.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="],
713
951
714
-
"forwarded": ["forwarded@0.2.0", "", {}, ""],
952
+
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
715
953
716
-
"fresh": ["fresh@0.5.2", "", {}, ""],
954
+
"fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
717
955
718
956
"fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
719
957
720
-
"function-bind": ["function-bind@1.1.2", "", {}, ""],
958
+
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
721
959
722
-
"get-caller-file": ["get-caller-file@2.0.5", "", {}, ""],
960
+
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
723
961
724
-
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, ""],
962
+
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
725
963
726
-
"get-nonce": ["get-nonce@1.0.1", "", {}, ""],
964
+
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
727
965
728
-
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, ""],
966
+
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
729
967
730
968
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
731
969
732
-
"gopd": ["gopd@1.2.0", "", {}, ""],
970
+
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
733
971
734
972
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
735
973
736
-
"graphemer": ["graphemer@1.4.0", "", {}, ""],
974
+
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
737
975
738
-
"has-flag": ["has-flag@4.0.0", "", {}, ""],
976
+
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
739
977
740
-
"has-symbols": ["has-symbols@1.1.0", "", {}, ""],
741
-
742
-
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, ""],
978
+
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
743
979
744
980
"hono": ["hono@4.10.7", "", {}, "sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw=="],
745
981
746
-
"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" } }, ""],
982
+
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
747
983
748
-
"iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, ""],
984
+
"iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
749
985
750
-
"ieee754": ["ieee754@1.2.1", "", {}, ""],
986
+
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
751
987
752
988
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
753
989
754
-
"import-in-the-middle": ["import-in-the-middle@1.15.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, ""],
990
+
"import-in-the-middle": ["import-in-the-middle@1.15.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA=="],
755
991
756
-
"inherits": ["inherits@2.0.4", "", {}, ""],
992
+
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
757
993
758
-
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, ""],
994
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
759
995
760
-
"iron-session": ["iron-session@8.0.4", "", { "dependencies": { "cookie": "^0.7.2", "iron-webcrypto": "^1.2.1", "uncrypto": "^0.1.3" } }, ""],
996
+
"iron-session": ["iron-session@8.0.4", "", { "dependencies": { "cookie": "^0.7.2", "iron-webcrypto": "^1.2.1", "uncrypto": "^0.1.3" } }, "sha512-9ivNnaKOd08osD0lJ3i6If23GFS2LsxyMU8Gf/uBUEgm8/8CC1hrrCHFDpMo3IFbpBgwoo/eairRsaD3c5itxA=="],
761
997
762
-
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, ""],
998
+
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
763
999
764
-
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, ""],
1000
+
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
765
1001
766
1002
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
767
1003
768
-
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, ""],
1004
+
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
769
1005
770
1006
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
771
1007
772
1008
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
773
1009
774
-
"iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, ""],
1010
+
"iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="],
775
1011
776
1012
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
777
1013
778
-
"jose": ["jose@5.10.0", "", {}, ""],
1014
+
"jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
779
1015
780
1016
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
781
1017
···
801
1037
802
1038
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
803
1039
804
-
"lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, ""],
1040
+
"lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
805
1041
806
-
"long": ["long@5.3.2", "", {}, ""],
1042
+
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
807
1043
808
-
"lru-cache": ["lru-cache@10.4.3", "", {}, ""],
1044
+
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
809
1045
810
-
"lucide-react": ["lucide-react@0.546.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, ""],
1046
+
"lucide-react": ["lucide-react@0.546.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ=="],
811
1047
812
1048
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
813
1049
814
-
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, ""],
1050
+
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
815
1051
816
-
"media-typer": ["media-typer@0.3.0", "", {}, ""],
1052
+
"media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="],
817
1053
818
-
"memoirist": ["memoirist@0.4.0", "", {}, ""],
1054
+
"memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
819
1055
820
-
"merge-descriptors": ["merge-descriptors@1.0.3", "", {}, ""],
1056
+
"merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="],
821
1057
822
-
"methods": ["methods@1.1.2", "", {}, ""],
1058
+
"methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="],
823
1059
824
1060
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
825
1061
826
-
"mime": ["mime@1.6.0", "", { "bin": "cli.js" }, ""],
1062
+
"mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
827
1063
828
-
"mime-db": ["mime-db@1.52.0", "", {}, ""],
1064
+
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
829
1065
830
-
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, ""],
1066
+
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
831
1067
832
-
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, ""],
1068
+
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
833
1069
834
-
"module-details-from-path": ["module-details-from-path@1.0.4", "", {}, ""],
1070
+
"module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="],
835
1071
836
1072
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
837
1073
838
-
"ms": ["ms@2.0.0", "", {}, ""],
1074
+
"ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
839
1075
840
-
"multiformats": ["multiformats@13.4.1", "", {}, ""],
1076
+
"multiformats": ["multiformats@13.4.1", "", {}, "sha512-VqO6OSvLrFVAYYjgsr8tyv62/rCQhPgsZUXLTqoFLSgdkgiUYKYeArbt1uWLlEpkjxQe+P0+sHlbPEte1Bi06Q=="],
841
1077
842
-
"negotiator": ["negotiator@0.6.3", "", {}, ""],
1078
+
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
843
1079
844
1080
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
845
1081
846
-
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.1.1", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, ""],
1082
+
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.1.1", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-test": "build-test.js", "node-gyp-build-optional-packages-optional": "optional.js" } }, "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw=="],
847
1083
848
-
"object-inspect": ["object-inspect@1.13.4", "", {}, ""],
1084
+
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
849
1085
850
-
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, ""],
1086
+
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
851
1087
852
-
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, ""],
1088
+
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
853
1089
854
-
"openapi-types": ["openapi-types@12.1.3", "", {}, ""],
1090
+
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
855
1091
856
1092
"p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="],
857
1093
···
859
1095
860
1096
"p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="],
861
1097
862
-
"parseurl": ["parseurl@1.3.3", "", {}, ""],
1098
+
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
863
1099
864
-
"path-browserify": ["path-browserify@1.0.1", "", {}, ""],
1100
+
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
865
1101
866
-
"path-parse": ["path-parse@1.0.7", "", {}, ""],
1102
+
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
867
1103
868
-
"path-to-regexp": ["path-to-regexp@0.1.12", "", {}, ""],
1104
+
"path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="],
869
1105
870
1106
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
871
1107
872
1108
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
873
1109
874
-
"pino": ["pino@8.21.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^1.2.0", "pino-std-serializers": "^6.0.0", "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^3.7.0", "thread-stream": "^2.6.0" }, "bin": "bin.js" }, ""],
1110
+
"pino": ["pino@8.21.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^1.2.0", "pino-std-serializers": "^6.0.0", "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^3.7.0", "thread-stream": "^2.6.0" }, "bin": { "pino": "bin.js" } }, "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q=="],
875
1111
876
-
"pino-abstract-transport": ["pino-abstract-transport@1.2.0", "", { "dependencies": { "readable-stream": "^4.0.0", "split2": "^4.0.0" } }, ""],
1112
+
"pino-abstract-transport": ["pino-abstract-transport@1.2.0", "", { "dependencies": { "readable-stream": "^4.0.0", "split2": "^4.0.0" } }, "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q=="],
877
1113
878
-
"pino-std-serializers": ["pino-std-serializers@6.2.2", "", {}, ""],
1114
+
"pino-std-serializers": ["pino-std-serializers@6.2.2", "", {}, "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA=="],
879
1115
880
1116
"playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="],
881
1117
···
883
1119
884
1120
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
885
1121
886
-
"prettier": ["prettier@3.6.2", "", { "bin": "bin/prettier.cjs" }, ""],
1122
+
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
887
1123
888
1124
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
889
1125
890
-
"process": ["process@0.11.10", "", {}, ""],
1126
+
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
891
1127
892
-
"process-warning": ["process-warning@3.0.0", "", {}, ""],
1128
+
"process-warning": ["process-warning@3.0.0", "", {}, "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ=="],
893
1129
894
-
"protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, ""],
1130
+
"protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
895
1131
896
-
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, ""],
1132
+
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
897
1133
898
-
"qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, ""],
1134
+
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
899
1135
900
-
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, ""],
1136
+
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
901
1137
902
-
"range-parser": ["range-parser@1.2.1", "", {}, ""],
1138
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
903
1139
904
-
"rate-limiter-flexible": ["rate-limiter-flexible@2.4.2", "", {}, ""],
1140
+
"rate-limiter-flexible": ["rate-limiter-flexible@2.4.2", "", {}, "sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw=="],
905
1141
906
-
"raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, ""],
1142
+
"raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="],
907
1143
908
-
"react": ["react@19.2.0", "", {}, ""],
1144
+
"react": ["react@19.2.1", "", {}, "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw=="],
909
1145
910
-
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, ""],
1146
+
"react-dom": ["react-dom@19.2.1", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.1" } }, "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg=="],
911
1147
912
-
"react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, ""],
1148
+
"react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
913
1149
914
-
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, ""],
1150
+
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
915
1151
916
-
"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" } }, ""],
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=="],
917
1153
918
-
"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" } }, ""],
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=="],
919
1155
920
-
"real-require": ["real-require@0.2.0", "", {}, ""],
1156
+
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
921
1157
922
-
"require-directory": ["require-directory@2.1.1", "", {}, ""],
1158
+
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
923
1159
924
-
"require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, ""],
1160
+
"require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="],
925
1161
926
-
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, ""],
1162
+
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
927
1163
928
1164
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
929
1165
930
-
"safe-buffer": ["safe-buffer@5.2.1", "", {}, ""],
1166
+
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
931
1167
932
-
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, ""],
1168
+
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
933
1169
934
-
"safer-buffer": ["safer-buffer@2.1.2", "", {}, ""],
1170
+
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
935
1171
936
-
"scheduler": ["scheduler@0.27.0", "", {}, ""],
1172
+
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
937
1173
938
-
"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" } }, ""],
1174
+
"send": ["send@0.19.1", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "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-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg=="],
939
1175
940
-
"serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, ""],
1176
+
"serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
941
1177
942
-
"setprototypeof": ["setprototypeof@1.2.0", "", {}, ""],
1178
+
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
943
1179
944
-
"shimmer": ["shimmer@1.2.1", "", {}, ""],
1180
+
"shimmer": ["shimmer@1.2.1", "", {}, "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="],
945
1181
946
-
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, ""],
1182
+
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
947
1183
948
-
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, ""],
1184
+
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
949
1185
950
-
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, ""],
1186
+
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
951
1187
952
-
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, ""],
1188
+
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
953
1189
954
-
"sonic-boom": ["sonic-boom@3.8.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, ""],
1190
+
"sonic-boom": ["sonic-boom@3.8.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg=="],
955
1191
956
1192
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
957
1193
958
-
"split2": ["split2@4.2.0", "", {}, ""],
1194
+
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
959
1195
960
-
"statuses": ["statuses@2.0.1", "", {}, ""],
1196
+
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
961
1197
962
-
"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" } }, ""],
1198
+
"stream-browserify": ["stream-browserify@3.0.0", "", { "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" } }, "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA=="],
963
1199
964
-
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, ""],
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=="],
965
1201
966
-
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, ""],
1202
+
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
967
1203
968
-
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, ""],
1204
+
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
969
1205
970
-
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, ""],
1206
+
"strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="],
971
1207
972
-
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, ""],
1208
+
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
973
1209
974
-
"tailwind-merge": ["tailwind-merge@3.3.1", "", {}, ""],
1210
+
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
1211
+
1212
+
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
1213
+
1214
+
"tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="],
975
1215
976
-
"tailwindcss": ["tailwindcss@4.1.17", "", {}, ""],
1216
+
"tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="],
977
1217
978
1218
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
979
1219
980
-
"thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, ""],
1220
+
"thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="],
1221
+
1222
+
"tiered-storage": ["tiered-storage@1.0.3", "", { "dependencies": { "@aws-sdk/client-s3": "^3.500.0", "@aws-sdk/lib-storage": "^3.500.0", "hono": "^4.10.7", "mime-types": "^3.0.2", "tiny-lru": "^11.0.0" } }, "sha512-ntJCsWWYHSQWIDbObMfnJ8xw7cRSJCPzfbrjoY4hu0YIRizCthRWg8kCvJOgsgC+Upt259YHmfNwEr1wLv6Rxw=="],
981
1223
982
-
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, ""],
1224
+
"tiny-lru": ["tiny-lru@11.4.5", "", {}, "sha512-hkcz3FjNJfKXjV4mjQ1OrXSLAehg8Hw+cEZclOVT+5c/cWQWImQ9wolzTjth+dmmDe++p3bme3fTxz6Q4Etsqw=="],
1225
+
1226
+
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
983
1227
984
-
"tlds": ["tlds@1.261.0", "", { "bin": "bin.js" }, ""],
1228
+
"tlds": ["tlds@1.261.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA=="],
985
1229
986
1230
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
987
1231
988
-
"toidentifier": ["toidentifier@1.0.1", "", {}, ""],
1232
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
989
1233
990
-
"token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, ""],
1234
+
"token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="],
991
1235
992
-
"ts-morph": ["ts-morph@24.0.0", "", { "dependencies": { "@ts-morph/common": "~0.25.0", "code-block-writer": "^13.0.3" } }, ""],
1236
+
"ts-morph": ["ts-morph@24.0.0", "", { "dependencies": { "@ts-morph/common": "~0.25.0", "code-block-writer": "^13.0.3" } }, "sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw=="],
993
1237
994
-
"tslib": ["tslib@2.8.1", "", {}, ""],
1238
+
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
995
1239
996
1240
"tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="],
997
1241
998
-
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, ""],
1242
+
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
999
1243
1000
-
"type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, ""],
1244
+
"type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
1001
1245
1002
-
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, ""],
1246
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
1003
1247
1004
-
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, ""],
1248
+
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
1005
1249
1006
-
"uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, ""],
1250
+
"uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="],
1007
1251
1008
-
"uncrypto": ["uncrypto@0.1.3", "", {}, ""],
1252
+
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
1009
1253
1010
-
"undici": ["undici@6.22.0", "", {}, ""],
1254
+
"undici": ["undici@6.22.0", "", {}, "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw=="],
1011
1255
1012
1256
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
1013
1257
1014
1258
"unicode-segmenter": ["unicode-segmenter@0.14.0", "", {}, "sha512-AH4lhPCJANUnSLEKnM4byboctePJzltF4xj8b+NbNiYeAkAXGh7px2K/4NANFp7dnr6+zB3e6HLu8Jj8SKyvYg=="],
1015
1259
1016
-
"unpipe": ["unpipe@1.0.0", "", {}, ""],
1260
+
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
1261
+
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=="],
1017
1263
1018
-
"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" } }, ""],
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=="],
1019
1265
1020
-
"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" } }, ""],
1266
+
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
1021
1267
1022
-
"utils-merge": ["utils-merge@1.0.1", "", {}, ""],
1268
+
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
1023
1269
1024
1270
"varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
1025
1271
1026
-
"vary": ["vary@1.1.2", "", {}, ""],
1272
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
1027
1273
1028
1274
"wisp-hosting-service": ["wisp-hosting-service@workspace:apps/hosting-service"],
1029
1275
1030
-
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, ""],
1276
+
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
1277
+
1278
+
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
1279
+
1280
+
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
1281
+
1282
+
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
1283
+
1284
+
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
1285
+
1286
+
"yesno": ["yesno@0.4.0", "", {}, "sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA=="],
1287
+
1288
+
"zlib": ["zlib@1.0.5", "", {}, "sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w=="],
1289
+
1290
+
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
1291
+
1292
+
"@atproto-labs/fetch-node/ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="],
1293
+
1294
+
"@atproto/api/@atproto/lexicon": ["@atproto/lexicon@0.4.14", "", { "dependencies": { "@atproto/common-web": "^0.4.2", "@atproto/syntax": "^0.4.0", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-jiKpmH1QER3Gvc7JVY5brwrfo+etFoe57tKPQX/SmPwjvUsFnJAow5xLIryuBaJgFAhnTZViXKs41t//pahGHQ=="],
1295
+
1296
+
"@atproto/api/@atproto/xrpc": ["@atproto/xrpc@0.6.12", "", { "dependencies": { "@atproto/lexicon": "^0.4.10", "zod": "^3.23.8" } }, "sha512-Ut3iISNLujlmY9Gu8sNU+SPDJDvqlVzWddU8qUr0Yae5oD4SguaUFjjhireMGhQ3M5E0KljQgDbTmnBo1kIZ3w=="],
1297
+
1298
+
"@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1299
+
1300
+
"@atproto/common/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1301
+
1302
+
"@atproto/jwk/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1303
+
1304
+
"@atproto/lex-cbor/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1305
+
1306
+
"@atproto/lex-data/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1307
+
1308
+
"@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1309
+
1310
+
"@atproto/oauth-client/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1311
+
1312
+
"@atproto/repo/@atproto/common": ["@atproto/common@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.6", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-7KdU8FcIfnwS2kmv7M86pKxtw/fLvPY2bSI1rXpG+AmA8O++IUGlSCujBGzbrPwnQvY/z++f6Le4rdBzu8bFaA=="],
1313
+
1314
+
"@atproto/repo/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1315
+
1316
+
"@atproto/sync/@atproto/common": ["@atproto/common@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.6", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-7KdU8FcIfnwS2kmv7M86pKxtw/fLvPY2bSI1rXpG+AmA8O++IUGlSCujBGzbrPwnQvY/z++f6Le4rdBzu8bFaA=="],
1317
+
1318
+
"@atproto/sync/@atproto/xrpc-server": ["@atproto/xrpc-server@0.10.2", "", { "dependencies": { "@atproto/common": "^0.5.2", "@atproto/crypto": "^0.4.5", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "@atproto/lexicon": "^0.5.2", "@atproto/ws-client": "^0.0.3", "@atproto/xrpc": "^0.7.6", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-5AzN8xoV8K1Omn45z6qKH414+B3Z35D536rrScwF3aQGDEdpObAS+vya9UoSg+Gvm2+oOtVEbVri7riLTBW3Vg=="],
1319
+
1320
+
"@atproto/sync/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1321
+
1322
+
"@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
1323
+
1324
+
"@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
1325
+
1326
+
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
1327
+
1328
+
"@ipld/dag-cbor/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1329
+
1330
+
"@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1331
+
1332
+
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1333
+
1334
+
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1335
+
1336
+
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1337
+
1338
+
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1339
+
1340
+
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1031
1341
1032
-
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, ""],
1342
+
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1033
1343
1034
-
"y18n": ["y18n@5.0.8", "", {}, ""],
1344
+
"@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1035
1345
1036
-
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, ""],
1346
+
"@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1037
1347
1038
-
"yargs-parser": ["yargs-parser@21.1.1", "", {}, ""],
1348
+
"@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1039
1349
1040
-
"yesno": ["yesno@0.4.0", "", {}, ""],
1350
+
"@opentelemetry/exporter-logs-otlp-proto/@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=="],
1041
1351
1042
-
"zlib": ["zlib@1.0.5", "", {}, ""],
1352
+
"@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1043
1353
1044
-
"zod": ["zod@3.25.76", "", {}, ""],
1354
+
"@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw=="],
1045
1355
1046
-
"@atproto-labs/did-resolver/@atproto/did": ["@atproto/did@0.2.1", "", { "dependencies": { "zod": "^3.23.8" } }, ""],
1356
+
"@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1047
1357
1048
-
"@atproto-labs/fetch-node/ipaddr.js": ["ipaddr.js@2.2.0", "", {}, ""],
1358
+
"@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1049
1359
1050
-
"@atproto-labs/handle-resolver-node/@atproto-labs/handle-resolver": ["@atproto-labs/handle-resolver@0.3.2", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.1", "zod": "^3.23.8" } }, ""],
1360
+
"@opentelemetry/exporter-metrics-otlp-grpc/@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=="],
1051
1361
1052
-
"@atproto-labs/handle-resolver-node/@atproto/did": ["@atproto/did@0.2.1", "", { "dependencies": { "zod": "^3.23.8" } }, ""],
1362
+
"@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1053
1363
1054
-
"@atproto-labs/identity-resolver/@atproto-labs/handle-resolver": ["@atproto-labs/handle-resolver@0.3.2", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.1", "zod": "^3.23.8" } }, ""],
1364
+
"@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@1.29.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-s7mLXuHZE7RQr1wwweGcaRp3Q4UJJ0wazeGlc/N5/XSe6UyXfsh1UQGMADYeg7YwD+cEdMtU1yJAUXdnFzYzyQ=="],
1055
1365
1056
-
"@atproto/api/@atproto/lexicon": ["@atproto/lexicon@0.4.14", "", { "dependencies": { "@atproto/common-web": "^0.4.2", "@atproto/syntax": "^0.4.0", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-jiKpmH1QER3Gvc7JVY5brwrfo+etFoe57tKPQX/SmPwjvUsFnJAow5xLIryuBaJgFAhnTZViXKs41t//pahGHQ=="],
1366
+
"@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@1.29.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/resources": "1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-MkVtuzDjXZaUJSuJlHn6BSXjcQlMvHcsDV7LjY4P6AJeffMa4+kIGDjzsCf6DkAh6Vqlwag5EWEam3KZOX5Drw=="],
1367
+
1368
+
"@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1369
+
1370
+
"@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw=="],
1371
+
1372
+
"@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1373
+
1374
+
"@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1375
+
1376
+
"@opentelemetry/exporter-metrics-otlp-proto/@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=="],
1377
+
1378
+
"@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1379
+
1380
+
"@opentelemetry/exporter-prometheus/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1381
+
1382
+
"@opentelemetry/exporter-prometheus/@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=="],
1383
+
1384
+
"@opentelemetry/exporter-prometheus/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1385
+
1386
+
"@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1387
+
1388
+
"@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1389
+
1390
+
"@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1391
+
1392
+
"@opentelemetry/exporter-trace-otlp-grpc/@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=="],
1393
+
1394
+
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1395
+
1396
+
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1397
+
1398
+
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1399
+
1400
+
"@opentelemetry/exporter-trace-otlp-http/@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=="],
1401
+
1402
+
"@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1057
1403
1058
-
"@atproto/api/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, ""],
1404
+
"@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1059
1405
1060
-
"@atproto/api/@atproto/xrpc": ["@atproto/xrpc@0.6.12", "", { "dependencies": { "@atproto/lexicon": "^0.4.10", "zod": "^3.23.8" } }, "sha512-Ut3iISNLujlmY9Gu8sNU+SPDJDvqlVzWddU8qUr0Yae5oD4SguaUFjjhireMGhQ3M5E0KljQgDbTmnBo1kIZ3w=="],
1406
+
"@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1061
1407
1062
-
"@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, ""],
1408
+
"@opentelemetry/exporter-trace-otlp-proto/@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=="],
1063
1409
1064
-
"@atproto/common/@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, ""],
1410
+
"@opentelemetry/exporter-zipkin/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1065
1411
1066
-
"@atproto/common/multiformats": ["multiformats@9.9.0", "", {}, ""],
1412
+
"@opentelemetry/exporter-zipkin/@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=="],
1067
1413
1068
-
"@atproto/jwk/multiformats": ["multiformats@9.9.0", "", {}, ""],
1414
+
"@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1069
1415
1070
-
"@atproto/lex-cbor/multiformats": ["multiformats@9.9.0", "", {}, ""],
1416
+
"@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1071
1417
1072
-
"@atproto/lex-cli/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
1418
+
"@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1073
1419
1074
-
"@atproto/lex-cli/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, ""],
1420
+
"@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.56.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wr39+94UNNG3Ei9nv3pHd4AJ63gq5nSemMRpCd8fPwDL9rN3vK26lzxfH27mw16XzOSO+TpyQwBAMaLxaPWG0g=="],
1075
1421
1076
-
"@atproto/lex-data/multiformats": ["multiformats@9.9.0", "", {}, ""],
1422
+
"@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@1.29.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-s7mLXuHZE7RQr1wwweGcaRp3Q4UJJ0wazeGlc/N5/XSe6UyXfsh1UQGMADYeg7YwD+cEdMtU1yJAUXdnFzYzyQ=="],
1077
1423
1078
-
"@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, ""],
1424
+
"@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.56.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.56.0", "@opentelemetry/core": "1.29.0", "@opentelemetry/resources": "1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-OS0WPBJF++R/cSl+terUjQH5PebloidB1Jbbecgg2rnCmQbTST9xsRes23bLfDQVRvmegmHqDh884h0aRdJyLw=="],
1079
1425
1080
-
"@atproto/oauth-client/@atproto-labs/handle-resolver": ["@atproto-labs/handle-resolver@0.3.2", "", { "dependencies": { "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.1", "zod": "^3.23.8" } }, ""],
1426
+
"@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@1.29.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/resources": "1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-MkVtuzDjXZaUJSuJlHn6BSXjcQlMvHcsDV7LjY4P6AJeffMa4+kIGDjzsCf6DkAh6Vqlwag5EWEam3KZOX5Drw=="],
1081
1427
1082
-
"@atproto/oauth-client/@atproto/did": ["@atproto/did@0.2.1", "", { "dependencies": { "zod": "^3.23.8" } }, ""],
1428
+
"@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@1.29.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0", "@opentelemetry/resources": "1.29.0", "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-hEOpAYLKXF3wGJpXOtWsxEtqBgde0SCv+w+jvr3/UusR4ll3QrENEGnSl1WDCyRrpqOQ5NCNOvZch9UFVa7MnQ=="],
1083
1429
1084
-
"@atproto/oauth-client/@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, ""],
1430
+
"@opentelemetry/propagator-b3/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1085
1431
1086
-
"@atproto/oauth-client/multiformats": ["multiformats@9.9.0", "", {}, ""],
1432
+
"@opentelemetry/propagator-jaeger/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1087
1433
1088
-
"@atproto/oauth-client-node/@atproto/did": ["@atproto/did@0.2.1", "", { "dependencies": { "zod": "^3.23.8" } }, ""],
1434
+
"@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@1.30.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ=="],
1089
1435
1090
-
"@atproto/oauth-types/@atproto/did": ["@atproto/did@0.2.1", "", { "dependencies": { "zod": "^3.23.8" } }, ""],
1436
+
"@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1091
1437
1092
-
"@atproto/repo/@atproto/common": ["@atproto/common@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.6", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-7KdU8FcIfnwS2kmv7M86pKxtw/fLvPY2bSI1rXpG+AmA8O++IUGlSCujBGzbrPwnQvY/z++f6Le4rdBzu8bFaA=="],
1438
+
"@opentelemetry/sdk-logs/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1093
1439
1094
-
"@atproto/repo/@atproto/crypto": ["@atproto/crypto@0.4.5", "", { "dependencies": { "@noble/curves": "^1.7.0", "@noble/hashes": "^1.6.1", "uint8arrays": "3.0.0" } }, "sha512-n40aKkMoCatP0u9Yvhrdk6fXyOHFDDbkdm4h4HCyWW+KlKl8iXfD5iV+ECq+w5BM+QH25aIpt3/j6EUNerhLxw=="],
1440
+
"@opentelemetry/sdk-logs/@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=="],
1095
1441
1096
-
"@atproto/repo/multiformats": ["multiformats@9.9.0", "", {}, ""],
1442
+
"@opentelemetry/sdk-metrics/@opentelemetry/core": ["@opentelemetry/core@1.30.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ=="],
1097
1443
1098
-
"@atproto/sync/@atproto/common": ["@atproto/common@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.6", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-7KdU8FcIfnwS2kmv7M86pKxtw/fLvPY2bSI1rXpG+AmA8O++IUGlSCujBGzbrPwnQvY/z++f6Le4rdBzu8bFaA=="],
1444
+
"@opentelemetry/sdk-node/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1099
1445
1100
-
"@atproto/sync/@atproto/xrpc-server": ["@atproto/xrpc-server@0.10.2", "", { "dependencies": { "@atproto/common": "^0.5.2", "@atproto/crypto": "^0.4.5", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "@atproto/lexicon": "^0.5.2", "@atproto/ws-client": "^0.0.3", "@atproto/xrpc": "^0.7.6", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-5AzN8xoV8K1Omn45z6qKH414+B3Z35D536rrScwF3aQGDEdpObAS+vya9UoSg+Gvm2+oOtVEbVri7riLTBW3Vg=="],
1446
+
"@opentelemetry/sdk-node/@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw=="],
1101
1447
1102
-
"@atproto/sync/multiformats": ["multiformats@9.9.0", "", {}, ""],
1448
+
"@opentelemetry/sdk-node/@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=="],
1103
1449
1104
-
"@atproto/ws-client/@atproto/common": ["@atproto/common@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.6", "@atproto/lex-cbor": "0.0.2", "@atproto/lex-data": "0.0.2", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-7KdU8FcIfnwS2kmv7M86pKxtw/fLvPY2bSI1rXpG+AmA8O++IUGlSCujBGzbrPwnQvY/z++f6Le4rdBzu8bFaA=="],
1450
+
"@opentelemetry/sdk-node/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1105
1451
1106
-
"@atproto/xrpc-server/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
1452
+
"@opentelemetry/sdk-trace-base/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1107
1453
1108
-
"@atproto/xrpc-server/@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, ""],
1454
+
"@opentelemetry/sdk-trace-base/@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=="],
1109
1455
1110
-
"@ipld/dag-cbor/multiformats": ["multiformats@9.9.0", "", {}, ""],
1456
+
"@opentelemetry/sdk-trace-node/@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
1111
1457
1112
-
"@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
1458
+
"@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
1113
1459
1114
-
"@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
1460
+
"@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
1115
1461
1116
-
"@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
1462
+
"@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
1117
1463
1118
-
"@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, ""],
1464
+
"@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
1119
1465
1120
1466
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
1121
1467
···
1127
1473
1128
1474
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
1129
1475
1130
-
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, ""],
1476
+
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
1131
1477
1132
-
"@tokenizer/inflate/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, ""],
1478
+
"@tokenizer/inflate/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
1133
1479
1134
-
"@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" } }, ""],
1480
+
"@types/bun/bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
1135
1481
1136
-
"bun-types/@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, ""],
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=="],
1137
1483
1138
-
"express/cookie": ["cookie@0.7.1", "", {}, ""],
1484
+
"@wisp/observability/bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
1139
1485
1140
-
"fdir/picomatch": ["picomatch@4.0.3", "", {}, ""],
1486
+
"express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
1487
+
1488
+
"iron-session/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
1141
1489
1142
-
"iron-session/cookie": ["cookie@0.7.2", "", {}, ""],
1490
+
"lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
1143
1491
1144
-
"lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, ""],
1492
+
"node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
1493
+
1494
+
"pino-abstract-transport/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
1495
+
1496
+
"require-in-the-middle/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
1145
1497
1146
-
"node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.1.2", "", {}, ""],
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=="],
1147
1499
1148
-
"protobufjs/@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, ""],
1500
+
"send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
1149
1501
1150
-
"require-in-the-middle/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, ""],
1502
+
"send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
1151
1503
1152
-
"send/encodeurl": ["encodeurl@1.0.2", "", {}, ""],
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=="],
1153
1505
1154
-
"send/ms": ["ms@2.1.3", "", {}, ""],
1506
+
"tiered-storage/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
1155
1507
1156
-
"tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, ""],
1508
+
"tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
1157
1509
1158
-
"tsx/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
1510
+
"tsx/esbuild": ["esbuild@0.27.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.1", "@esbuild/android-arm": "0.27.1", "@esbuild/android-arm64": "0.27.1", "@esbuild/android-x64": "0.27.1", "@esbuild/darwin-arm64": "0.27.1", "@esbuild/darwin-x64": "0.27.1", "@esbuild/freebsd-arm64": "0.27.1", "@esbuild/freebsd-x64": "0.27.1", "@esbuild/linux-arm": "0.27.1", "@esbuild/linux-arm64": "0.27.1", "@esbuild/linux-ia32": "0.27.1", "@esbuild/linux-loong64": "0.27.1", "@esbuild/linux-mips64el": "0.27.1", "@esbuild/linux-ppc64": "0.27.1", "@esbuild/linux-riscv64": "0.27.1", "@esbuild/linux-s390x": "0.27.1", "@esbuild/linux-x64": "0.27.1", "@esbuild/netbsd-arm64": "0.27.1", "@esbuild/netbsd-x64": "0.27.1", "@esbuild/openbsd-arm64": "0.27.1", "@esbuild/openbsd-x64": "0.27.1", "@esbuild/openharmony-arm64": "0.27.1", "@esbuild/sunos-x64": "0.27.1", "@esbuild/win32-arm64": "0.27.1", "@esbuild/win32-ia32": "0.27.1", "@esbuild/win32-x64": "0.27.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA=="],
1159
1511
1160
1512
"tsx/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
1161
1513
1162
-
"uint8arrays/multiformats": ["multiformats@9.9.0", "", {}, ""],
1514
+
"uint8arrays/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1163
1515
1164
-
"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" } }, ""],
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=="],
1165
1517
1166
-
"@atproto-labs/identity-resolver/@atproto-labs/handle-resolver/@atproto/did": ["@atproto/did@0.2.1", "", { "dependencies": { "zod": "^3.23.8" } }, ""],
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=="],
1167
1519
1168
-
"@atproto/lex-cli/@atproto/lexicon/@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, ""],
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=="],
1169
1521
1170
-
"@atproto/lex-cli/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, ""],
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=="],
1171
1523
1172
-
"@atproto/oauth-client/@atproto/xrpc/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
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=="],
1173
1525
1174
-
"@atproto/sync/@atproto/xrpc-server/@atproto/crypto": ["@atproto/crypto@0.4.5", "", { "dependencies": { "@noble/curves": "^1.7.0", "@noble/hashes": "^1.6.1", "uint8arrays": "3.0.0" } }, "sha512-n40aKkMoCatP0u9Yvhrdk6fXyOHFDDbkdm4h4HCyWW+KlKl8iXfD5iV+ECq+w5BM+QH25aIpt3/j6EUNerhLxw=="],
1526
+
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
1527
+
1528
+
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1529
+
1530
+
"@opentelemetry/exporter-logs-otlp-http/@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=="],
1531
+
1532
+
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1533
+
1534
+
"@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1535
+
1536
+
"@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1537
+
1538
+
"@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1539
+
1540
+
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1175
1541
1176
-
"@atproto/ws-client/@atproto/common/multiformats": ["multiformats@9.9.0", "", {}, ""],
1542
+
"@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1543
+
1544
+
"@opentelemetry/otlp-grpc-exporter-base/@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=="],
1177
1545
1178
-
"@atproto/xrpc-server/@atproto/lexicon/@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, ""],
1546
+
"@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
1179
1547
1180
-
"@atproto/xrpc-server/@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, ""],
1548
+
"@opentelemetry/otlp-transformer/@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1181
1549
1182
-
"@atproto/xrpc-server/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, ""],
1550
+
"@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1183
1551
1184
-
"@tokenizer/inflate/debug/ms": ["ms@2.1.3", "", {}, ""],
1552
+
"@opentelemetry/sdk-metrics/@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1185
1553
1186
-
"@wisp/main-app/@atproto/api/@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, ""],
1554
+
"@opentelemetry/sdk-node/@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
1187
1555
1188
-
"@wisp/main-app/@atproto/api/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
1556
+
"@opentelemetry/sdk-node/@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
1189
1557
1190
-
"@wisp/main-app/@atproto/api/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, ""],
1558
+
"@tokenizer/inflate/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
1191
1559
1192
-
"@wisp/main-app/@atproto/api/@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, ""],
1560
+
"@wisp/main-app/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1193
1561
1194
-
"@wisp/main-app/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, ""],
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=="],
1195
1563
1196
-
"bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, ""],
1564
+
"require-in-the-middle/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
1197
1565
1198
-
"protobufjs/@types/node/undici-types": ["undici-types@7.16.0", "", {}, ""],
1566
+
"serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
1199
1567
1200
-
"require-in-the-middle/debug/ms": ["ms@2.1.3", "", {}, ""],
1568
+
"serve-static/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=="],
1201
1569
1202
-
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="],
1570
+
"serve-static/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
1203
1571
1204
-
"tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.0", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="],
1572
+
"serve-static/send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
1205
1573
1206
-
"tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="],
1574
+
"tiered-storage/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
1207
1575
1208
-
"tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.0", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="],
1576
+
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA=="],
1209
1577
1210
-
"tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="],
1578
+
"tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.1", "", { "os": "android", "cpu": "arm" }, "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg=="],
1211
1579
1212
-
"tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="],
1580
+
"tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.1", "", { "os": "android", "cpu": "arm64" }, "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ=="],
1213
1581
1214
-
"tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="],
1582
+
"tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.1", "", { "os": "android", "cpu": "x64" }, "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ=="],
1215
1583
1216
-
"tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="],
1584
+
"tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ=="],
1217
1585
1218
-
"tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="],
1586
+
"tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ=="],
1219
1587
1220
-
"tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="],
1588
+
"tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg=="],
1221
1589
1222
-
"tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="],
1590
+
"tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ=="],
1223
1591
1224
-
"tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="],
1592
+
"tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA=="],
1225
1593
1226
-
"tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="],
1594
+
"tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q=="],
1227
1595
1228
-
"tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="],
1596
+
"tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw=="],
1229
1597
1230
-
"tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="],
1598
+
"tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.1", "", { "os": "linux", "cpu": "none" }, "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg=="],
1231
1599
1232
-
"tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="],
1600
+
"tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.1", "", { "os": "linux", "cpu": "none" }, "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA=="],
1233
1601
1234
-
"tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="],
1602
+
"tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ=="],
1235
1603
1236
-
"tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="],
1604
+
"tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.1", "", { "os": "linux", "cpu": "none" }, "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ=="],
1237
1605
1238
-
"tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.0", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="],
1606
+
"tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw=="],
1239
1607
1240
-
"tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="],
1608
+
"tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.1", "", { "os": "linux", "cpu": "x64" }, "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA=="],
1241
1609
1242
-
"tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="],
1610
+
"tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.1", "", { "os": "none", "cpu": "arm64" }, "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ=="],
1243
1611
1244
-
"tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="],
1612
+
"tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.1", "", { "os": "none", "cpu": "x64" }, "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg=="],
1245
1613
1246
-
"tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="],
1614
+
"tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g=="],
1247
1615
1248
-
"tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="],
1616
+
"tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg=="],
1249
1617
1250
-
"tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="],
1618
+
"tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg=="],
1251
1619
1252
-
"tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="],
1620
+
"tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA=="],
1253
1621
1254
-
"wisp-hosting-service/@atproto/api/@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, ""],
1622
+
"tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg=="],
1255
1623
1256
-
"wisp-hosting-service/@atproto/api/@atproto/lexicon": ["@atproto/lexicon@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.3", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, ""],
1624
+
"tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ=="],
1257
1625
1258
-
"wisp-hosting-service/@atproto/api/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, ""],
1626
+
"tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.1", "", { "os": "win32", "cpu": "x64" }, "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw=="],
1259
1627
1260
-
"wisp-hosting-service/@atproto/api/@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, ""],
1628
+
"wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
1261
1629
1262
-
"wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, ""],
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=="],
1263
1631
1264
-
"@atproto/oauth-client/@atproto/xrpc/@atproto/lexicon/@atproto/common-web": ["@atproto/common-web@0.4.3", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, ""],
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=="],
1265
1633
1266
-
"@atproto/oauth-client/@atproto/xrpc/@atproto/lexicon/@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, ""],
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=="],
1267
1635
}
1268
1636
}
+370
-503
cli/Cargo.lock
+370
-503
cli/Cargo.lock
···
3
3
version = 4
4
4
5
5
[[package]]
6
-
name = "abnf"
7
-
version = "0.13.0"
8
-
source = "registry+https://github.com/rust-lang/crates.io-index"
9
-
checksum = "087113bd50d9adce24850eed5d0476c7d199d532fce8fab5173650331e09033a"
10
-
dependencies = [
11
-
"abnf-core",
12
-
"nom",
13
-
]
14
-
15
-
[[package]]
16
-
name = "abnf-core"
17
-
version = "0.5.0"
18
-
source = "registry+https://github.com/rust-lang/crates.io-index"
19
-
checksum = "c44e09c43ae1c368fb91a03a566472d0087c26cf7e1b9e8e289c14ede681dd7d"
20
-
dependencies = [
21
-
"nom",
22
-
]
23
-
24
-
[[package]]
25
6
name = "addr2line"
26
7
version = "0.25.1"
27
8
source = "registry+https://github.com/rust-lang/crates.io-index"
···
71
52
dependencies = [
72
53
"alloc-no-stdlib",
73
54
]
55
+
56
+
[[package]]
57
+
name = "allocator-api2"
58
+
version = "0.2.21"
59
+
source = "registry+https://github.com/rust-lang/crates.io-index"
60
+
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
74
61
75
62
[[package]]
76
63
name = "android_system_properties"
···
139
126
140
127
[[package]]
141
128
name = "async-compression"
142
-
version = "0.4.34"
129
+
version = "0.4.36"
143
130
source = "registry+https://github.com/rust-lang/crates.io-index"
144
-
checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473"
131
+
checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37"
145
132
dependencies = [
146
133
"compression-codecs",
147
134
"compression-core",
···
158
145
dependencies = [
159
146
"proc-macro2",
160
147
"quote",
161
-
"syn 2.0.111",
148
+
"syn 2.0.113",
149
+
]
150
+
151
+
[[package]]
152
+
name = "atomic-polyfill"
153
+
version = "1.0.3"
154
+
source = "registry+https://github.com/rust-lang/crates.io-index"
155
+
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
156
+
dependencies = [
157
+
"critical-section",
162
158
]
163
159
164
160
[[package]]
···
175
171
176
172
[[package]]
177
173
name = "axum"
178
-
version = "0.8.7"
174
+
version = "0.8.8"
179
175
source = "registry+https://github.com/rust-lang/crates.io-index"
180
-
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
176
+
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
181
177
dependencies = [
182
178
"axum-core",
183
179
"bytes",
···
208
204
209
205
[[package]]
210
206
name = "axum-core"
211
-
version = "0.5.5"
207
+
version = "0.5.6"
212
208
source = "registry+https://github.com/rust-lang/crates.io-index"
213
-
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
209
+
checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
214
210
dependencies = [
215
211
"bytes",
216
212
"futures-core",
···
237
233
"miniz_oxide",
238
234
"object",
239
235
"rustc-demangle",
240
-
"windows-link 0.2.1",
236
+
"windows-link",
241
237
]
242
238
243
239
[[package]]
···
285
281
286
282
[[package]]
287
283
name = "base64ct"
288
-
version = "1.8.0"
284
+
version = "1.8.2"
289
285
source = "registry+https://github.com/rust-lang/crates.io-index"
290
-
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
286
+
checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82"
291
287
292
288
[[package]]
293
289
name = "bitflags"
···
326
322
"proc-macro2",
327
323
"quote",
328
324
"rustversion",
329
-
"syn 2.0.111",
325
+
"syn 2.0.113",
330
326
]
331
327
332
328
[[package]]
333
329
name = "borsh"
334
-
version = "1.5.7"
330
+
version = "1.6.0"
335
331
source = "registry+https://github.com/rust-lang/crates.io-index"
336
-
checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
332
+
checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f"
337
333
dependencies = [
338
334
"cfg_aliases",
339
335
]
···
370
366
]
371
367
372
368
[[package]]
373
-
name = "btree-range-map"
374
-
version = "0.7.2"
375
-
source = "registry+https://github.com/rust-lang/crates.io-index"
376
-
checksum = "1be5c9672446d3800bcbcaabaeba121fe22f1fb25700c4562b22faf76d377c33"
377
-
dependencies = [
378
-
"btree-slab",
379
-
"cc-traits",
380
-
"range-traits",
381
-
"serde",
382
-
"slab",
383
-
]
384
-
385
-
[[package]]
386
-
name = "btree-slab"
387
-
version = "0.6.1"
388
-
source = "registry+https://github.com/rust-lang/crates.io-index"
389
-
checksum = "7a2b56d3029f075c4fa892428a098425b86cef5c89ae54073137ece416aef13c"
390
-
dependencies = [
391
-
"cc-traits",
392
-
"slab",
393
-
"smallvec",
394
-
]
395
-
396
-
[[package]]
397
369
name = "buf_redux"
398
370
version = "0.8.4"
399
371
source = "registry+https://github.com/rust-lang/crates.io-index"
···
405
377
406
378
[[package]]
407
379
name = "bumpalo"
408
-
version = "3.19.0"
380
+
version = "3.19.1"
409
381
source = "registry+https://github.com/rust-lang/crates.io-index"
410
-
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
382
+
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
411
383
412
384
[[package]]
413
385
name = "byteorder"
···
435
407
436
408
[[package]]
437
409
name = "cc"
438
-
version = "1.2.47"
410
+
version = "1.2.51"
439
411
source = "registry+https://github.com/rust-lang/crates.io-index"
440
-
checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
412
+
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
441
413
dependencies = [
442
414
"find-msvc-tools",
443
415
"shlex",
444
416
]
445
417
446
418
[[package]]
447
-
name = "cc-traits"
448
-
version = "2.0.0"
449
-
source = "registry+https://github.com/rust-lang/crates.io-index"
450
-
checksum = "060303ef31ef4a522737e1b1ab68c67916f2a787bb2f4f54f383279adba962b5"
451
-
dependencies = [
452
-
"slab",
453
-
]
454
-
455
-
[[package]]
456
419
name = "cesu8"
457
420
version = "1.1.0"
458
421
source = "registry+https://github.com/rust-lang/crates.io-index"
···
481
444
"num-traits",
482
445
"serde",
483
446
"wasm-bindgen",
484
-
"windows-link 0.2.1",
447
+
"windows-link",
485
448
]
486
449
487
450
[[package]]
···
533
496
534
497
[[package]]
535
498
name = "clap"
536
-
version = "4.5.53"
499
+
version = "4.5.54"
537
500
source = "registry+https://github.com/rust-lang/crates.io-index"
538
-
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
501
+
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
539
502
dependencies = [
540
503
"clap_builder",
541
504
"clap_derive",
···
543
506
544
507
[[package]]
545
508
name = "clap_builder"
546
-
version = "4.5.53"
509
+
version = "4.5.54"
547
510
source = "registry+https://github.com/rust-lang/crates.io-index"
548
-
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
511
+
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
549
512
dependencies = [
550
513
"anstream",
551
514
"anstyle",
···
562
525
"heck 0.5.0",
563
526
"proc-macro2",
564
527
"quote",
565
-
"syn 2.0.111",
528
+
"syn 2.0.113",
566
529
]
567
530
568
531
[[package]]
···
572
535
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
573
536
574
537
[[package]]
538
+
name = "cobs"
539
+
version = "0.3.0"
540
+
source = "registry+https://github.com/rust-lang/crates.io-index"
541
+
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
542
+
dependencies = [
543
+
"thiserror 2.0.17",
544
+
]
545
+
546
+
[[package]]
575
547
name = "colorchoice"
576
548
version = "1.0.4"
577
549
source = "registry+https://github.com/rust-lang/crates.io-index"
···
589
561
590
562
[[package]]
591
563
name = "compression-codecs"
592
-
version = "0.4.33"
564
+
version = "0.4.35"
593
565
source = "registry+https://github.com/rust-lang/crates.io-index"
594
-
checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad"
566
+
checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2"
595
567
dependencies = [
596
568
"compression-core",
597
569
"flate2",
···
693
665
]
694
666
695
667
[[package]]
668
+
name = "critical-section"
669
+
version = "1.2.0"
670
+
source = "registry+https://github.com/rust-lang/crates.io-index"
671
+
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
672
+
673
+
[[package]]
696
674
name = "crossbeam-channel"
697
675
version = "0.5.15"
698
676
source = "registry+https://github.com/rust-lang/crates.io-index"
···
775
753
"proc-macro2",
776
754
"quote",
777
755
"strsim",
778
-
"syn 2.0.111",
756
+
"syn 2.0.113",
779
757
]
780
758
781
759
[[package]]
···
786
764
dependencies = [
787
765
"darling_core",
788
766
"quote",
789
-
"syn 2.0.111",
767
+
"syn 2.0.113",
790
768
]
791
769
792
770
[[package]]
···
826
804
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
827
805
dependencies = [
828
806
"data-encoding",
829
-
"syn 2.0.111",
807
+
"syn 2.0.113",
830
808
]
831
809
832
810
[[package]]
···
857
835
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
858
836
dependencies = [
859
837
"powerfmt",
860
-
"serde_core",
861
838
]
862
839
863
840
[[package]]
···
877
854
dependencies = [
878
855
"proc-macro2",
879
856
"quote",
880
-
"syn 2.0.111",
857
+
"syn 2.0.113",
881
858
"unicode-xid",
882
859
]
883
860
···
928
905
dependencies = [
929
906
"proc-macro2",
930
907
"quote",
931
-
"syn 2.0.111",
908
+
"syn 2.0.113",
932
909
]
933
910
934
911
[[package]]
935
-
name = "dyn-clone"
936
-
version = "1.0.20"
937
-
source = "registry+https://github.com/rust-lang/crates.io-index"
938
-
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
939
-
940
-
[[package]]
941
912
name = "ecdsa"
942
913
version = "0.16.9"
943
914
source = "registry+https://github.com/rust-lang/crates.io-index"
···
972
943
]
973
944
974
945
[[package]]
946
+
name = "embedded-io"
947
+
version = "0.4.0"
948
+
source = "registry+https://github.com/rust-lang/crates.io-index"
949
+
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
950
+
951
+
[[package]]
952
+
name = "embedded-io"
953
+
version = "0.6.1"
954
+
source = "registry+https://github.com/rust-lang/crates.io-index"
955
+
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
956
+
957
+
[[package]]
975
958
name = "encode_unicode"
976
959
version = "1.0.0"
977
960
source = "registry+https://github.com/rust-lang/crates.io-index"
···
995
978
"heck 0.5.0",
996
979
"proc-macro2",
997
980
"quote",
998
-
"syn 2.0.111",
981
+
"syn 2.0.113",
999
982
]
1000
983
1001
984
[[package]]
···
1044
1027
1045
1028
[[package]]
1046
1029
name = "find-msvc-tools"
1047
-
version = "0.1.5"
1030
+
version = "0.1.6"
1048
1031
source = "registry+https://github.com/rust-lang/crates.io-index"
1049
-
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
1032
+
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
1050
1033
1051
1034
[[package]]
1052
1035
name = "flate2"
···
1063
1046
version = "1.0.7"
1064
1047
source = "registry+https://github.com/rust-lang/crates.io-index"
1065
1048
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
1049
+
1050
+
[[package]]
1051
+
name = "foldhash"
1052
+
version = "0.1.5"
1053
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1054
+
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1066
1055
1067
1056
[[package]]
1068
1057
name = "form_urlencoded"
···
1165
1154
dependencies = [
1166
1155
"proc-macro2",
1167
1156
"quote",
1168
-
"syn 2.0.111",
1157
+
"syn 2.0.113",
1169
1158
]
1170
1159
1171
1160
[[package]]
···
1200
1189
1201
1190
[[package]]
1202
1191
name = "generator"
1203
-
version = "0.8.7"
1192
+
version = "0.8.8"
1204
1193
source = "registry+https://github.com/rust-lang/crates.io-index"
1205
-
checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2"
1194
+
checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9"
1206
1195
dependencies = [
1207
1196
"cc",
1208
1197
"cfg-if",
1209
1198
"libc",
1210
1199
"log",
1211
1200
"rustversion",
1212
-
"windows",
1201
+
"windows-link",
1202
+
"windows-result",
1213
1203
]
1214
1204
1215
1205
[[package]]
···
1319
1309
1320
1310
[[package]]
1321
1311
name = "h2"
1322
-
version = "0.4.12"
1312
+
version = "0.4.13"
1323
1313
source = "registry+https://github.com/rust-lang/crates.io-index"
1324
-
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
1314
+
checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
1325
1315
dependencies = [
1326
1316
"atomic-waker",
1327
1317
"bytes",
···
1329
1319
"futures-core",
1330
1320
"futures-sink",
1331
1321
"http",
1332
-
"indexmap 2.12.1",
1322
+
"indexmap",
1333
1323
"slab",
1334
1324
"tokio",
1335
1325
"tokio-util",
···
1348
1338
]
1349
1339
1350
1340
[[package]]
1351
-
name = "hashbrown"
1352
-
version = "0.12.3"
1341
+
name = "hash32"
1342
+
version = "0.2.1"
1353
1343
source = "registry+https://github.com/rust-lang/crates.io-index"
1354
-
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
1344
+
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
1345
+
dependencies = [
1346
+
"byteorder",
1347
+
]
1355
1348
1356
1349
[[package]]
1357
1350
name = "hashbrown"
···
1361
1354
1362
1355
[[package]]
1363
1356
name = "hashbrown"
1357
+
version = "0.15.5"
1358
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1359
+
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
1360
+
dependencies = [
1361
+
"allocator-api2",
1362
+
"equivalent",
1363
+
"foldhash",
1364
+
]
1365
+
1366
+
[[package]]
1367
+
name = "hashbrown"
1364
1368
version = "0.16.1"
1365
1369
source = "registry+https://github.com/rust-lang/crates.io-index"
1366
1370
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
1367
1371
1368
1372
[[package]]
1373
+
name = "heapless"
1374
+
version = "0.7.17"
1375
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1376
+
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
1377
+
dependencies = [
1378
+
"atomic-polyfill",
1379
+
"hash32",
1380
+
"rustc_version",
1381
+
"serde",
1382
+
"spin 0.9.8",
1383
+
"stable_deref_trait",
1384
+
]
1385
+
1386
+
[[package]]
1369
1387
name = "heck"
1370
1388
version = "0.4.1"
1371
1389
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1390
1408
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
1391
1409
1392
1410
[[package]]
1393
-
name = "hex_fmt"
1394
-
version = "0.3.0"
1395
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1396
-
checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f"
1397
-
1398
-
[[package]]
1399
1411
name = "hickory-proto"
1400
1412
version = "0.24.4"
1401
1413
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1460
1472
"markup5ever",
1461
1473
"proc-macro2",
1462
1474
"quote",
1463
-
"syn 2.0.111",
1475
+
"syn 2.0.113",
1464
1476
]
1465
1477
1466
1478
[[package]]
···
1556
1568
1557
1569
[[package]]
1558
1570
name = "hyper-util"
1559
-
version = "0.1.18"
1571
+
version = "0.1.19"
1560
1572
source = "registry+https://github.com/rust-lang/crates.io-index"
1561
-
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
1573
+
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
1562
1574
dependencies = [
1563
1575
"base64 0.22.1",
1564
1576
"bytes",
···
1592
1604
"js-sys",
1593
1605
"log",
1594
1606
"wasm-bindgen",
1595
-
"windows-core 0.62.2",
1607
+
"windows-core",
1596
1608
]
1597
1609
1598
1610
[[package]]
···
1652
1664
1653
1665
[[package]]
1654
1666
name = "icu_properties"
1655
-
version = "2.1.1"
1667
+
version = "2.1.2"
1656
1668
source = "registry+https://github.com/rust-lang/crates.io-index"
1657
-
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99"
1669
+
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
1658
1670
dependencies = [
1659
1671
"icu_collections",
1660
1672
"icu_locale_core",
···
1666
1678
1667
1679
[[package]]
1668
1680
name = "icu_properties_data"
1669
-
version = "2.1.1"
1681
+
version = "2.1.2"
1670
1682
source = "registry+https://github.com/rust-lang/crates.io-index"
1671
-
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899"
1683
+
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
1672
1684
1673
1685
[[package]]
1674
1686
name = "icu_provider"
···
1730
1742
1731
1743
[[package]]
1732
1744
name = "indexmap"
1733
-
version = "1.9.3"
1734
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1735
-
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
1736
-
dependencies = [
1737
-
"autocfg",
1738
-
"hashbrown 0.12.3",
1739
-
"serde",
1740
-
]
1741
-
1742
-
[[package]]
1743
-
name = "indexmap"
1744
1745
version = "2.12.1"
1745
1746
source = "registry+https://github.com/rust-lang/crates.io-index"
1746
1747
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
1747
1748
dependencies = [
1748
1749
"equivalent",
1749
1750
"hashbrown 0.16.1",
1750
-
"serde",
1751
-
"serde_core",
1752
1751
]
1753
1752
1754
1753
[[package]]
···
1765
1764
]
1766
1765
1767
1766
[[package]]
1768
-
name = "indoc"
1769
-
version = "2.0.7"
1770
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1771
-
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
1772
-
dependencies = [
1773
-
"rustversion",
1774
-
]
1775
-
1776
-
[[package]]
1777
1767
name = "inventory"
1778
1768
version = "0.3.21"
1779
1769
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1813
1803
1814
1804
[[package]]
1815
1805
name = "iri-string"
1816
-
version = "0.7.9"
1806
+
version = "0.7.10"
1817
1807
source = "registry+https://github.com/rust-lang/crates.io-index"
1818
-
checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
1808
+
checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
1819
1809
dependencies = [
1820
1810
"memchr",
1821
1811
"serde",
···
1835
1825
1836
1826
[[package]]
1837
1827
name = "itoa"
1838
-
version = "1.0.15"
1828
+
version = "1.0.17"
1839
1829
source = "registry+https://github.com/rust-lang/crates.io-index"
1840
-
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1830
+
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
1841
1831
1842
1832
[[package]]
1843
1833
name = "jacquard"
1844
-
version = "0.9.3"
1834
+
version = "0.9.5"
1835
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1845
1836
dependencies = [
1846
1837
"bytes",
1847
1838
"getrandom 0.2.16",
···
1870
1861
1871
1862
[[package]]
1872
1863
name = "jacquard-api"
1873
-
version = "0.9.2"
1864
+
version = "0.9.5"
1865
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1874
1866
dependencies = [
1875
1867
"bon",
1876
1868
"bytes",
···
1880
1872
"miette",
1881
1873
"rustversion",
1882
1874
"serde",
1875
+
"serde_bytes",
1883
1876
"serde_ipld_dagcbor",
1884
1877
"thiserror 2.0.17",
1885
1878
"unicode-segmentation",
···
1887
1880
1888
1881
[[package]]
1889
1882
name = "jacquard-common"
1890
-
version = "0.9.2"
1883
+
version = "0.9.5"
1884
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1891
1885
dependencies = [
1892
1886
"base64 0.22.1",
1893
1887
"bon",
1894
1888
"bytes",
1895
1889
"chrono",
1896
1890
"ciborium",
1891
+
"ciborium-io",
1897
1892
"cid",
1898
1893
"futures",
1899
1894
"getrandom 0.2.16",
1900
1895
"getrandom 0.3.4",
1896
+
"hashbrown 0.15.5",
1901
1897
"http",
1902
1898
"ipld-core",
1903
1899
"k256",
1904
-
"langtag",
1900
+
"maitake-sync",
1905
1901
"miette",
1906
1902
"multibase",
1907
1903
"multihash",
1908
1904
"n0-future 0.1.3",
1909
1905
"ouroboros",
1906
+
"oxilangtag",
1910
1907
"p256",
1908
+
"postcard",
1911
1909
"rand 0.9.2",
1912
1910
"regex",
1911
+
"regex-automata",
1913
1912
"regex-lite",
1914
1913
"reqwest",
1915
1914
"serde",
1915
+
"serde_bytes",
1916
1916
"serde_html_form",
1917
1917
"serde_ipld_dagcbor",
1918
1918
"serde_json",
1919
1919
"signature",
1920
1920
"smol_str",
1921
+
"spin 0.10.0",
1921
1922
"thiserror 2.0.17",
1922
1923
"tokio",
1923
1924
"tokio-tungstenite-wasm",
···
1928
1929
1929
1930
[[package]]
1930
1931
name = "jacquard-derive"
1931
-
version = "0.9.3"
1932
+
version = "0.9.5"
1933
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1932
1934
dependencies = [
1933
1935
"heck 0.5.0",
1934
1936
"jacquard-lexicon",
1935
1937
"proc-macro2",
1936
1938
"quote",
1937
-
"syn 2.0.111",
1939
+
"syn 2.0.113",
1938
1940
]
1939
1941
1940
1942
[[package]]
1941
1943
name = "jacquard-identity"
1942
-
version = "0.9.2"
1944
+
version = "0.9.5"
1945
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1943
1946
dependencies = [
1944
1947
"bon",
1945
1948
"bytes",
···
1949
1952
"jacquard-common",
1950
1953
"jacquard-lexicon",
1951
1954
"miette",
1952
-
"mini-moka",
1955
+
"mini-moka-wasm",
1956
+
"n0-future 0.1.3",
1953
1957
"percent-encoding",
1954
1958
"reqwest",
1955
1959
"serde",
···
1964
1968
1965
1969
[[package]]
1966
1970
name = "jacquard-lexicon"
1967
-
version = "0.9.2"
1971
+
version = "0.9.5"
1972
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1968
1973
dependencies = [
1969
1974
"cid",
1970
1975
"dashmap",
···
1982
1987
"serde_repr",
1983
1988
"serde_with",
1984
1989
"sha2",
1985
-
"syn 2.0.111",
1990
+
"syn 2.0.113",
1986
1991
"thiserror 2.0.17",
1987
1992
"unicode-segmentation",
1988
1993
]
1989
1994
1990
1995
[[package]]
1991
1996
name = "jacquard-oauth"
1992
-
version = "0.9.2"
1997
+
version = "0.9.6"
1998
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
1993
1999
dependencies = [
1994
2000
"base64 0.22.1",
1995
2001
"bytes",
···
2077
2083
2078
2084
[[package]]
2079
2085
name = "js-sys"
2080
-
version = "0.3.82"
2086
+
version = "0.3.83"
2081
2087
source = "registry+https://github.com/rust-lang/crates.io-index"
2082
-
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
2088
+
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
2083
2089
dependencies = [
2084
2090
"once_cell",
2085
2091
"wasm-bindgen",
···
2098
2104
]
2099
2105
2100
2106
[[package]]
2101
-
name = "langtag"
2102
-
version = "0.4.0"
2103
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2104
-
checksum = "9ecb4c689a30e48ebeaa14237f34037e300dd072e6ad21a9ec72e810ff3c6600"
2105
-
dependencies = [
2106
-
"serde",
2107
-
"static-regular-grammar",
2108
-
"thiserror 1.0.69",
2109
-
]
2110
-
2111
-
[[package]]
2112
2107
name = "lazy_static"
2113
2108
version = "1.5.0"
2114
2109
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2119
2114
2120
2115
[[package]]
2121
2116
name = "libc"
2122
-
version = "0.2.177"
2117
+
version = "0.2.179"
2123
2118
source = "registry+https://github.com/rust-lang/crates.io-index"
2124
-
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
2119
+
checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
2125
2120
2126
2121
[[package]]
2127
2122
name = "libm"
···
2131
2126
2132
2127
[[package]]
2133
2128
name = "libredox"
2134
-
version = "0.1.10"
2129
+
version = "0.1.12"
2135
2130
source = "registry+https://github.com/rust-lang/crates.io-index"
2136
-
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
2131
+
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
2137
2132
dependencies = [
2138
2133
"bitflags",
2139
2134
"libc",
2140
-
"redox_syscall",
2135
+
"redox_syscall 0.7.0",
2141
2136
]
2142
2137
2143
2138
[[package]]
···
2169
2164
2170
2165
[[package]]
2171
2166
name = "log"
2172
-
version = "0.4.28"
2167
+
version = "0.4.29"
2173
2168
source = "registry+https://github.com/rust-lang/crates.io-index"
2174
-
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
2169
+
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2175
2170
2176
2171
[[package]]
2177
2172
name = "loom"
···
2208
2203
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
2209
2204
2210
2205
[[package]]
2206
+
name = "maitake-sync"
2207
+
version = "0.1.2"
2208
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2209
+
checksum = "6816ab14147f80234c675b80ed6dc4f440d8a1cefc158e766067aedb84c0bcd5"
2210
+
dependencies = [
2211
+
"cordyceps",
2212
+
"loom",
2213
+
"mycelium-bitfield",
2214
+
"pin-project",
2215
+
"portable-atomic",
2216
+
]
2217
+
2218
+
[[package]]
2211
2219
name = "markup5ever"
2212
2220
version = "0.12.1"
2213
2221
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2292
2300
dependencies = [
2293
2301
"proc-macro2",
2294
2302
"quote",
2295
-
"syn 2.0.111",
2303
+
"syn 2.0.113",
2296
2304
]
2297
2305
2298
2306
[[package]]
···
2312
2320
]
2313
2321
2314
2322
[[package]]
2315
-
name = "mini-moka"
2323
+
name = "mini-moka-wasm"
2316
2324
version = "0.10.99"
2325
+
source = "git+https://tangled.org/nonbinary.computer/jacquard#5bcf7f8e87324b8e67fc273c678d0490c9c6d15b"
2317
2326
dependencies = [
2318
2327
"crossbeam-channel",
2319
2328
"crossbeam-utils",
···
2325
2334
]
2326
2335
2327
2336
[[package]]
2328
-
name = "minimal-lexical"
2329
-
version = "0.2.1"
2330
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2331
-
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
2332
-
2333
-
[[package]]
2334
2337
name = "miniz_oxide"
2335
2338
version = "0.8.9"
2336
2339
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2342
2345
2343
2346
[[package]]
2344
2347
name = "mio"
2345
-
version = "1.1.0"
2348
+
version = "1.1.1"
2346
2349
source = "registry+https://github.com/rust-lang/crates.io-index"
2347
-
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
2350
+
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
2348
2351
dependencies = [
2349
2352
"libc",
2350
2353
"wasi",
···
2393
2396
]
2394
2397
2395
2398
[[package]]
2399
+
name = "mycelium-bitfield"
2400
+
version = "0.1.5"
2401
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2402
+
checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc"
2403
+
2404
+
[[package]]
2396
2405
name = "n0-future"
2397
2406
version = "0.1.3"
2398
2407
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2447
2456
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
2448
2457
2449
2458
[[package]]
2450
-
name = "nom"
2451
-
version = "7.1.3"
2452
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2453
-
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
2454
-
dependencies = [
2455
-
"memchr",
2456
-
"minimal-lexical",
2457
-
]
2458
-
2459
-
[[package]]
2460
2459
name = "nu-ansi-term"
2461
2460
version = "0.50.3"
2462
2461
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2590
2589
2591
2590
[[package]]
2592
2591
name = "openssl-probe"
2593
-
version = "0.1.6"
2592
+
version = "0.2.0"
2594
2593
source = "registry+https://github.com/rust-lang/crates.io-index"
2595
-
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
2594
+
checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391"
2596
2595
2597
2596
[[package]]
2598
2597
name = "option-ext"
···
2621
2620
"proc-macro2",
2622
2621
"proc-macro2-diagnostics",
2623
2622
"quote",
2624
-
"syn 2.0.111",
2623
+
"syn 2.0.113",
2625
2624
]
2626
2625
2627
2626
[[package]]
···
2631
2630
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
2632
2631
2633
2632
[[package]]
2633
+
name = "oxilangtag"
2634
+
version = "0.1.5"
2635
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2636
+
checksum = "23f3f87617a86af77fa3691e6350483e7154c2ead9f1261b75130e21ca0f8acb"
2637
+
dependencies = [
2638
+
"serde",
2639
+
]
2640
+
2641
+
[[package]]
2634
2642
name = "p256"
2635
2643
version = "0.13.2"
2636
2644
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2676
2684
dependencies = [
2677
2685
"cfg-if",
2678
2686
"libc",
2679
-
"redox_syscall",
2687
+
"redox_syscall 0.5.18",
2680
2688
"smallvec",
2681
-
"windows-link 0.2.1",
2689
+
"windows-link",
2682
2690
]
2683
2691
2684
2692
[[package]]
···
2751
2759
dependencies = [
2752
2760
"proc-macro2",
2753
2761
"quote",
2754
-
"syn 2.0.111",
2762
+
"syn 2.0.113",
2755
2763
]
2756
2764
2757
2765
[[package]]
···
2789
2797
2790
2798
[[package]]
2791
2799
name = "portable-atomic"
2792
-
version = "1.11.1"
2800
+
version = "1.13.0"
2793
2801
source = "registry+https://github.com/rust-lang/crates.io-index"
2794
-
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
2802
+
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
2803
+
2804
+
[[package]]
2805
+
name = "postcard"
2806
+
version = "1.1.3"
2807
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2808
+
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
2809
+
dependencies = [
2810
+
"cobs",
2811
+
"embedded-io 0.4.0",
2812
+
"embedded-io 0.6.1",
2813
+
"heapless",
2814
+
"serde",
2815
+
]
2795
2816
2796
2817
[[package]]
2797
2818
name = "potential_utf"
···
2830
2851
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
2831
2852
dependencies = [
2832
2853
"proc-macro2",
2833
-
"syn 2.0.111",
2854
+
"syn 2.0.113",
2834
2855
]
2835
2856
2836
2857
[[package]]
···
2843
2864
]
2844
2865
2845
2866
[[package]]
2846
-
name = "proc-macro-error"
2847
-
version = "1.0.4"
2848
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2849
-
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
2850
-
dependencies = [
2851
-
"proc-macro-error-attr",
2852
-
"proc-macro2",
2853
-
"quote",
2854
-
"syn 1.0.109",
2855
-
"version_check",
2856
-
]
2857
-
2858
-
[[package]]
2859
-
name = "proc-macro-error-attr"
2860
-
version = "1.0.4"
2861
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2862
-
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
2863
-
dependencies = [
2864
-
"proc-macro2",
2865
-
"quote",
2866
-
"version_check",
2867
-
]
2868
-
2869
-
[[package]]
2870
2867
name = "proc-macro2"
2871
-
version = "1.0.103"
2868
+
version = "1.0.105"
2872
2869
source = "registry+https://github.com/rust-lang/crates.io-index"
2873
-
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
2870
+
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
2874
2871
dependencies = [
2875
2872
"unicode-ident",
2876
2873
]
···
2883
2880
dependencies = [
2884
2881
"proc-macro2",
2885
2882
"quote",
2886
-
"syn 2.0.111",
2883
+
"syn 2.0.113",
2887
2884
"version_check",
2888
2885
"yansi",
2889
2886
]
···
2951
2948
2952
2949
[[package]]
2953
2950
name = "quote"
2954
-
version = "1.0.42"
2951
+
version = "1.0.43"
2955
2952
source = "registry+https://github.com/rust-lang/crates.io-index"
2956
-
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
2953
+
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
2957
2954
dependencies = [
2958
2955
"proc-macro2",
2959
2956
]
···
3024
3021
]
3025
3022
3026
3023
[[package]]
3027
-
name = "range-traits"
3028
-
version = "0.3.2"
3024
+
name = "redox_syscall"
3025
+
version = "0.5.18"
3029
3026
source = "registry+https://github.com/rust-lang/crates.io-index"
3030
-
checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab"
3027
+
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
3028
+
dependencies = [
3029
+
"bitflags",
3030
+
]
3031
3031
3032
3032
[[package]]
3033
3033
name = "redox_syscall"
3034
-
version = "0.5.18"
3034
+
version = "0.7.0"
3035
3035
source = "registry+https://github.com/rust-lang/crates.io-index"
3036
-
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
3036
+
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
3037
3037
dependencies = [
3038
3038
"bitflags",
3039
3039
]
···
3047
3047
"getrandom 0.2.16",
3048
3048
"libredox",
3049
3049
"thiserror 2.0.17",
3050
-
]
3051
-
3052
-
[[package]]
3053
-
name = "ref-cast"
3054
-
version = "1.0.25"
3055
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3056
-
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
3057
-
dependencies = [
3058
-
"ref-cast-impl",
3059
-
]
3060
-
3061
-
[[package]]
3062
-
name = "ref-cast-impl"
3063
-
version = "1.0.25"
3064
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3065
-
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
3066
-
dependencies = [
3067
-
"proc-macro2",
3068
-
"quote",
3069
-
"syn 2.0.111",
3070
3050
]
3071
3051
3072
3052
[[package]]
···
3106
3086
3107
3087
[[package]]
3108
3088
name = "reqwest"
3109
-
version = "0.12.24"
3089
+
version = "0.12.28"
3110
3090
source = "registry+https://github.com/rust-lang/crates.io-index"
3111
-
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
3091
+
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
3112
3092
dependencies = [
3113
-
"async-compression",
3114
3093
"base64 0.22.1",
3115
3094
"bytes",
3116
3095
"encoding_rs",
···
3205
3184
3206
3185
[[package]]
3207
3186
name = "rsa"
3208
-
version = "0.9.9"
3187
+
version = "0.9.10"
3209
3188
source = "registry+https://github.com/rust-lang/crates.io-index"
3210
-
checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88"
3189
+
checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
3211
3190
dependencies = [
3212
3191
"const-oid",
3213
3192
"digest",
···
3236
3215
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
3237
3216
3238
3217
[[package]]
3218
+
name = "rustc_version"
3219
+
version = "0.4.1"
3220
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3221
+
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
3222
+
dependencies = [
3223
+
"semver",
3224
+
]
3225
+
3226
+
[[package]]
3239
3227
name = "rustix"
3240
-
version = "1.1.2"
3228
+
version = "1.1.3"
3241
3229
source = "registry+https://github.com/rust-lang/crates.io-index"
3242
-
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
3230
+
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
3243
3231
dependencies = [
3244
3232
"bitflags",
3245
3233
"errno",
···
3250
3238
3251
3239
[[package]]
3252
3240
name = "rustls"
3253
-
version = "0.23.35"
3241
+
version = "0.23.36"
3254
3242
source = "registry+https://github.com/rust-lang/crates.io-index"
3255
-
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
3243
+
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
3256
3244
dependencies = [
3257
3245
"once_cell",
3258
3246
"ring",
···
3264
3252
3265
3253
[[package]]
3266
3254
name = "rustls-native-certs"
3267
-
version = "0.8.2"
3255
+
version = "0.8.3"
3268
3256
source = "registry+https://github.com/rust-lang/crates.io-index"
3269
-
checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923"
3257
+
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
3270
3258
dependencies = [
3271
3259
"openssl-probe",
3272
3260
"rustls-pki-types",
···
3276
3264
3277
3265
[[package]]
3278
3266
name = "rustls-pki-types"
3279
-
version = "1.13.0"
3267
+
version = "1.13.2"
3280
3268
source = "registry+https://github.com/rust-lang/crates.io-index"
3281
-
checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a"
3269
+
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
3282
3270
dependencies = [
3283
3271
"web-time",
3284
3272
"zeroize",
···
3303
3291
3304
3292
[[package]]
3305
3293
name = "ryu"
3306
-
version = "1.0.20"
3294
+
version = "1.0.22"
3307
3295
source = "registry+https://github.com/rust-lang/crates.io-index"
3308
-
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
3296
+
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
3309
3297
3310
3298
[[package]]
3311
3299
name = "safemem"
···
3332
3320
]
3333
3321
3334
3322
[[package]]
3335
-
name = "schemars"
3336
-
version = "0.9.0"
3337
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3338
-
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
3339
-
dependencies = [
3340
-
"dyn-clone",
3341
-
"ref-cast",
3342
-
"serde",
3343
-
"serde_json",
3344
-
]
3345
-
3346
-
[[package]]
3347
-
name = "schemars"
3348
-
version = "1.1.0"
3349
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3350
-
checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289"
3351
-
dependencies = [
3352
-
"dyn-clone",
3353
-
"ref-cast",
3354
-
"serde",
3355
-
"serde_json",
3356
-
]
3357
-
3358
-
[[package]]
3359
3323
name = "scoped-tls"
3360
3324
version = "1.0.1"
3361
3325
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3403
3367
"core-foundation-sys",
3404
3368
"libc",
3405
3369
]
3370
+
3371
+
[[package]]
3372
+
name = "semver"
3373
+
version = "1.0.27"
3374
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3375
+
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
3406
3376
3407
3377
[[package]]
3408
3378
name = "send_wrapper"
···
3447
3417
dependencies = [
3448
3418
"proc-macro2",
3449
3419
"quote",
3450
-
"syn 2.0.111",
3420
+
"syn 2.0.113",
3451
3421
]
3452
3422
3453
3423
[[package]]
3454
3424
name = "serde_html_form"
3455
-
version = "0.2.8"
3425
+
version = "0.3.2"
3456
3426
source = "registry+https://github.com/rust-lang/crates.io-index"
3457
-
checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
3427
+
checksum = "2acf96b1d9364968fce46ebb548f1c0e1d7eceae27bdff73865d42e6c7369d94"
3458
3428
dependencies = [
3459
3429
"form_urlencoded",
3460
-
"indexmap 2.12.1",
3430
+
"indexmap",
3461
3431
"itoa",
3462
-
"ryu",
3463
3432
"serde_core",
3464
3433
]
3465
3434
···
3477
3446
3478
3447
[[package]]
3479
3448
name = "serde_json"
3480
-
version = "1.0.145"
3449
+
version = "1.0.149"
3481
3450
source = "registry+https://github.com/rust-lang/crates.io-index"
3482
-
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
3451
+
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
3483
3452
dependencies = [
3484
3453
"itoa",
3485
3454
"memchr",
3486
-
"ryu",
3487
3455
"serde",
3488
3456
"serde_core",
3457
+
"zmij",
3489
3458
]
3490
3459
3491
3460
[[package]]
···
3507
3476
dependencies = [
3508
3477
"proc-macro2",
3509
3478
"quote",
3510
-
"syn 2.0.111",
3479
+
"syn 2.0.113",
3511
3480
]
3512
3481
3513
3482
[[package]]
···
3524
3493
3525
3494
[[package]]
3526
3495
name = "serde_with"
3527
-
version = "3.16.0"
3496
+
version = "3.16.1"
3528
3497
source = "registry+https://github.com/rust-lang/crates.io-index"
3529
-
checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1"
3498
+
checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
3530
3499
dependencies = [
3531
3500
"base64 0.22.1",
3532
3501
"chrono",
3533
3502
"hex",
3534
-
"indexmap 1.9.3",
3535
-
"indexmap 2.12.1",
3536
-
"schemars 0.9.0",
3537
-
"schemars 1.1.0",
3538
3503
"serde_core",
3539
3504
"serde_json",
3540
3505
"serde_with_macros",
···
3543
3508
3544
3509
[[package]]
3545
3510
name = "serde_with_macros"
3546
-
version = "3.16.0"
3511
+
version = "3.16.1"
3547
3512
source = "registry+https://github.com/rust-lang/crates.io-index"
3548
-
checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b"
3513
+
checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
3549
3514
dependencies = [
3550
3515
"darling",
3551
3516
"proc-macro2",
3552
3517
"quote",
3553
-
"syn 2.0.111",
3518
+
"syn 2.0.113",
3554
3519
]
3555
3520
3556
3521
[[package]]
···
3607
3572
3608
3573
[[package]]
3609
3574
name = "signal-hook-registry"
3610
-
version = "1.4.7"
3575
+
version = "1.4.8"
3611
3576
source = "registry+https://github.com/rust-lang/crates.io-index"
3612
-
checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
3577
+
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
3613
3578
dependencies = [
3579
+
"errno",
3614
3580
"libc",
3615
3581
]
3616
3582
···
3626
3592
3627
3593
[[package]]
3628
3594
name = "simd-adler32"
3629
-
version = "0.3.7"
3595
+
version = "0.3.8"
3630
3596
source = "registry+https://github.com/rust-lang/crates.io-index"
3631
-
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
3597
+
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
3632
3598
3633
3599
[[package]]
3634
3600
name = "siphasher"
···
3683
3649
version = "0.9.8"
3684
3650
source = "registry+https://github.com/rust-lang/crates.io-index"
3685
3651
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
3652
+
dependencies = [
3653
+
"lock_api",
3654
+
]
3686
3655
3687
3656
[[package]]
3688
3657
name = "spin"
···
3707
3676
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
3708
3677
3709
3678
[[package]]
3710
-
name = "static-regular-grammar"
3711
-
version = "2.0.2"
3712
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3713
-
checksum = "4f4a6c40247579acfbb138c3cd7de3dab113ab4ac6227f1b7de7d626ee667957"
3714
-
dependencies = [
3715
-
"abnf",
3716
-
"btree-range-map",
3717
-
"ciborium",
3718
-
"hex_fmt",
3719
-
"indoc",
3720
-
"proc-macro-error",
3721
-
"proc-macro2",
3722
-
"quote",
3723
-
"serde",
3724
-
"sha2",
3725
-
"syn 2.0.111",
3726
-
"thiserror 1.0.69",
3727
-
]
3728
-
3729
-
[[package]]
3730
3679
name = "static_assertions"
3731
3680
version = "1.1.0"
3732
3681
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3780
3729
3781
3730
[[package]]
3782
3731
name = "supports-hyperlinks"
3783
-
version = "3.1.0"
3732
+
version = "3.2.0"
3784
3733
source = "registry+https://github.com/rust-lang/crates.io-index"
3785
-
checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b"
3734
+
checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91"
3786
3735
3787
3736
[[package]]
3788
3737
name = "supports-unicode"
···
3803
3752
3804
3753
[[package]]
3805
3754
name = "syn"
3806
-
version = "2.0.111"
3755
+
version = "2.0.113"
3807
3756
source = "registry+https://github.com/rust-lang/crates.io-index"
3808
-
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
3757
+
checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
3809
3758
dependencies = [
3810
3759
"proc-macro2",
3811
3760
"quote",
···
3829
3778
dependencies = [
3830
3779
"proc-macro2",
3831
3780
"quote",
3832
-
"syn 2.0.111",
3781
+
"syn 2.0.113",
3833
3782
]
3834
3783
3835
3784
[[package]]
···
3861
3810
3862
3811
[[package]]
3863
3812
name = "tempfile"
3864
-
version = "3.23.0"
3813
+
version = "3.24.0"
3865
3814
source = "registry+https://github.com/rust-lang/crates.io-index"
3866
-
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
3815
+
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
3867
3816
dependencies = [
3868
3817
"fastrand",
3869
3818
"getrandom 0.3.4",
···
3929
3878
dependencies = [
3930
3879
"proc-macro2",
3931
3880
"quote",
3932
-
"syn 2.0.111",
3881
+
"syn 2.0.113",
3933
3882
]
3934
3883
3935
3884
[[package]]
···
3940
3889
dependencies = [
3941
3890
"proc-macro2",
3942
3891
"quote",
3943
-
"syn 2.0.111",
3892
+
"syn 2.0.113",
3944
3893
]
3945
3894
3946
3895
[[package]]
···
3968
3917
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
3969
3918
dependencies = [
3970
3919
"deranged",
3971
-
"itoa",
3972
3920
"libc",
3973
3921
"num-conv",
3974
3922
"num_threads",
3975
3923
"powerfmt",
3976
3924
"serde",
3977
3925
"time-core",
3978
-
"time-macros",
3979
3926
]
3980
3927
3981
3928
[[package]]
···
3983
3930
version = "0.1.6"
3984
3931
source = "registry+https://github.com/rust-lang/crates.io-index"
3985
3932
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
3986
-
3987
-
[[package]]
3988
-
name = "time-macros"
3989
-
version = "0.2.24"
3990
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3991
-
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
3992
-
dependencies = [
3993
-
"num-conv",
3994
-
"time-core",
3995
-
]
3996
3933
3997
3934
[[package]]
3998
3935
name = "tiny_http"
···
4033
3970
4034
3971
[[package]]
4035
3972
name = "tokio"
4036
-
version = "1.48.0"
3973
+
version = "1.49.0"
4037
3974
source = "registry+https://github.com/rust-lang/crates.io-index"
4038
-
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
3975
+
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
4039
3976
dependencies = [
4040
3977
"bytes",
4041
3978
"libc",
···
4056
3993
dependencies = [
4057
3994
"proc-macro2",
4058
3995
"quote",
4059
-
"syn 2.0.111",
3996
+
"syn 2.0.113",
4060
3997
]
4061
3998
4062
3999
[[package]]
···
4106
4043
4107
4044
[[package]]
4108
4045
name = "tokio-util"
4109
-
version = "0.7.17"
4046
+
version = "0.7.18"
4110
4047
source = "registry+https://github.com/rust-lang/crates.io-index"
4111
-
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
4048
+
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
4112
4049
dependencies = [
4113
4050
"bytes",
4114
4051
"futures-core",
···
4136
4073
4137
4074
[[package]]
4138
4075
name = "tower-http"
4139
-
version = "0.6.7"
4076
+
version = "0.6.8"
4140
4077
source = "registry+https://github.com/rust-lang/crates.io-index"
4141
-
checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456"
4078
+
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
4142
4079
dependencies = [
4143
4080
"async-compression",
4144
4081
"bitflags",
···
4177
4114
4178
4115
[[package]]
4179
4116
name = "tracing"
4180
-
version = "0.1.41"
4117
+
version = "0.1.44"
4181
4118
source = "registry+https://github.com/rust-lang/crates.io-index"
4182
-
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
4119
+
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
4183
4120
dependencies = [
4184
4121
"log",
4185
4122
"pin-project-lite",
···
4189
4126
4190
4127
[[package]]
4191
4128
name = "tracing-attributes"
4192
-
version = "0.1.30"
4129
+
version = "0.1.31"
4193
4130
source = "registry+https://github.com/rust-lang/crates.io-index"
4194
-
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
4131
+
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
4195
4132
dependencies = [
4196
4133
"proc-macro2",
4197
4134
"quote",
4198
-
"syn 2.0.111",
4135
+
"syn 2.0.113",
4199
4136
]
4200
4137
4201
4138
[[package]]
4202
4139
name = "tracing-core"
4203
-
version = "0.1.34"
4140
+
version = "0.1.36"
4204
4141
source = "registry+https://github.com/rust-lang/crates.io-index"
4205
-
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
4142
+
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
4206
4143
dependencies = [
4207
4144
"once_cell",
4208
4145
"valuable",
···
4221
4158
4222
4159
[[package]]
4223
4160
name = "tracing-subscriber"
4224
-
version = "0.3.20"
4161
+
version = "0.3.22"
4225
4162
source = "registry+https://github.com/rust-lang/crates.io-index"
4226
-
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
4163
+
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
4227
4164
dependencies = [
4228
4165
"matchers",
4229
4166
"nu-ansi-term",
···
4245
4182
dependencies = [
4246
4183
"proc-macro2",
4247
4184
"quote",
4248
-
"syn 2.0.111",
4185
+
"syn 2.0.113",
4249
4186
]
4250
4187
4251
4188
[[package]]
···
4297
4234
4298
4235
[[package]]
4299
4236
name = "unicase"
4300
-
version = "2.8.1"
4237
+
version = "2.9.0"
4301
4238
source = "registry+https://github.com/rust-lang/crates.io-index"
4302
-
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
4239
+
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
4303
4240
4304
4241
[[package]]
4305
4242
name = "unicode-ident"
···
4351
4288
4352
4289
[[package]]
4353
4290
name = "url"
4354
-
version = "2.5.7"
4291
+
version = "2.5.8"
4355
4292
source = "registry+https://github.com/rust-lang/crates.io-index"
4356
-
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
4293
+
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
4357
4294
dependencies = [
4358
4295
"form_urlencoded",
4359
4296
"idna",
4360
4297
"percent-encoding",
4361
4298
"serde",
4299
+
"serde_derive",
4362
4300
]
4363
4301
4364
4302
[[package]]
···
4433
4371
4434
4372
[[package]]
4435
4373
name = "wasm-bindgen"
4436
-
version = "0.2.105"
4374
+
version = "0.2.106"
4437
4375
source = "registry+https://github.com/rust-lang/crates.io-index"
4438
-
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
4376
+
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
4439
4377
dependencies = [
4440
4378
"cfg-if",
4441
4379
"once_cell",
···
4446
4384
4447
4385
[[package]]
4448
4386
name = "wasm-bindgen-futures"
4449
-
version = "0.4.55"
4387
+
version = "0.4.56"
4450
4388
source = "registry+https://github.com/rust-lang/crates.io-index"
4451
-
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
4389
+
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
4452
4390
dependencies = [
4453
4391
"cfg-if",
4454
4392
"js-sys",
···
4459
4397
4460
4398
[[package]]
4461
4399
name = "wasm-bindgen-macro"
4462
-
version = "0.2.105"
4400
+
version = "0.2.106"
4463
4401
source = "registry+https://github.com/rust-lang/crates.io-index"
4464
-
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
4402
+
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
4465
4403
dependencies = [
4466
4404
"quote",
4467
4405
"wasm-bindgen-macro-support",
···
4469
4407
4470
4408
[[package]]
4471
4409
name = "wasm-bindgen-macro-support"
4472
-
version = "0.2.105"
4410
+
version = "0.2.106"
4473
4411
source = "registry+https://github.com/rust-lang/crates.io-index"
4474
-
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
4412
+
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
4475
4413
dependencies = [
4476
4414
"bumpalo",
4477
4415
"proc-macro2",
4478
4416
"quote",
4479
-
"syn 2.0.111",
4417
+
"syn 2.0.113",
4480
4418
"wasm-bindgen-shared",
4481
4419
]
4482
4420
4483
4421
[[package]]
4484
4422
name = "wasm-bindgen-shared"
4485
-
version = "0.2.105"
4423
+
version = "0.2.106"
4486
4424
source = "registry+https://github.com/rust-lang/crates.io-index"
4487
-
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
4425
+
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
4488
4426
dependencies = [
4489
4427
"unicode-ident",
4490
4428
]
···
4504
4442
4505
4443
[[package]]
4506
4444
name = "web-sys"
4507
-
version = "0.3.82"
4445
+
version = "0.3.83"
4508
4446
source = "registry+https://github.com/rust-lang/crates.io-index"
4509
-
checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
4447
+
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
4510
4448
dependencies = [
4511
4449
"js-sys",
4512
4450
"wasm-bindgen",
···
4552
4490
4553
4491
[[package]]
4554
4492
name = "webpki-roots"
4555
-
version = "1.0.4"
4493
+
version = "1.0.5"
4556
4494
source = "registry+https://github.com/rust-lang/crates.io-index"
4557
-
checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
4495
+
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
4558
4496
dependencies = [
4559
4497
"rustls-pki-types",
4560
4498
]
···
4575
4513
]
4576
4514
4577
4515
[[package]]
4578
-
name = "windows"
4579
-
version = "0.61.3"
4580
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4581
-
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
4582
-
dependencies = [
4583
-
"windows-collections",
4584
-
"windows-core 0.61.2",
4585
-
"windows-future",
4586
-
"windows-link 0.1.3",
4587
-
"windows-numerics",
4588
-
]
4589
-
4590
-
[[package]]
4591
-
name = "windows-collections"
4592
-
version = "0.2.0"
4593
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4594
-
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
4595
-
dependencies = [
4596
-
"windows-core 0.61.2",
4597
-
]
4598
-
4599
-
[[package]]
4600
-
name = "windows-core"
4601
-
version = "0.61.2"
4602
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4603
-
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
4604
-
dependencies = [
4605
-
"windows-implement",
4606
-
"windows-interface",
4607
-
"windows-link 0.1.3",
4608
-
"windows-result 0.3.4",
4609
-
"windows-strings 0.4.2",
4610
-
]
4611
-
4612
-
[[package]]
4613
4516
name = "windows-core"
4614
4517
version = "0.62.2"
4615
4518
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4617
4520
dependencies = [
4618
4521
"windows-implement",
4619
4522
"windows-interface",
4620
-
"windows-link 0.2.1",
4621
-
"windows-result 0.4.1",
4622
-
"windows-strings 0.5.1",
4623
-
]
4624
-
4625
-
[[package]]
4626
-
name = "windows-future"
4627
-
version = "0.2.1"
4628
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4629
-
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
4630
-
dependencies = [
4631
-
"windows-core 0.61.2",
4632
-
"windows-link 0.1.3",
4633
-
"windows-threading",
4523
+
"windows-link",
4524
+
"windows-result",
4525
+
"windows-strings",
4634
4526
]
4635
4527
4636
4528
[[package]]
···
4641
4533
dependencies = [
4642
4534
"proc-macro2",
4643
4535
"quote",
4644
-
"syn 2.0.111",
4536
+
"syn 2.0.113",
4645
4537
]
4646
4538
4647
4539
[[package]]
···
4652
4544
dependencies = [
4653
4545
"proc-macro2",
4654
4546
"quote",
4655
-
"syn 2.0.111",
4547
+
"syn 2.0.113",
4656
4548
]
4657
4549
4658
4550
[[package]]
4659
4551
name = "windows-link"
4660
-
version = "0.1.3"
4661
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4662
-
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
4663
-
4664
-
[[package]]
4665
-
name = "windows-link"
4666
4552
version = "0.2.1"
4667
4553
source = "registry+https://github.com/rust-lang/crates.io-index"
4668
4554
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
4669
4555
4670
4556
[[package]]
4671
-
name = "windows-numerics"
4672
-
version = "0.2.0"
4673
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4674
-
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
4675
-
dependencies = [
4676
-
"windows-core 0.61.2",
4677
-
"windows-link 0.1.3",
4678
-
]
4679
-
4680
-
[[package]]
4681
4557
name = "windows-registry"
4682
4558
version = "0.6.1"
4683
4559
source = "registry+https://github.com/rust-lang/crates.io-index"
4684
4560
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
4685
4561
dependencies = [
4686
-
"windows-link 0.2.1",
4687
-
"windows-result 0.4.1",
4688
-
"windows-strings 0.5.1",
4689
-
]
4690
-
4691
-
[[package]]
4692
-
name = "windows-result"
4693
-
version = "0.3.4"
4694
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4695
-
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
4696
-
dependencies = [
4697
-
"windows-link 0.1.3",
4562
+
"windows-link",
4563
+
"windows-result",
4564
+
"windows-strings",
4698
4565
]
4699
4566
4700
4567
[[package]]
···
4703
4570
source = "registry+https://github.com/rust-lang/crates.io-index"
4704
4571
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
4705
4572
dependencies = [
4706
-
"windows-link 0.2.1",
4707
-
]
4708
-
4709
-
[[package]]
4710
-
name = "windows-strings"
4711
-
version = "0.4.2"
4712
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4713
-
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
4714
-
dependencies = [
4715
-
"windows-link 0.1.3",
4573
+
"windows-link",
4716
4574
]
4717
4575
4718
4576
[[package]]
···
4721
4579
source = "registry+https://github.com/rust-lang/crates.io-index"
4722
4580
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
4723
4581
dependencies = [
4724
-
"windows-link 0.2.1",
4582
+
"windows-link",
4725
4583
]
4726
4584
4727
4585
[[package]]
···
4775
4633
source = "registry+https://github.com/rust-lang/crates.io-index"
4776
4634
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
4777
4635
dependencies = [
4778
-
"windows-link 0.2.1",
4636
+
"windows-link",
4779
4637
]
4780
4638
4781
4639
[[package]]
···
4830
4688
source = "registry+https://github.com/rust-lang/crates.io-index"
4831
4689
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
4832
4690
dependencies = [
4833
-
"windows-link 0.2.1",
4691
+
"windows-link",
4834
4692
"windows_aarch64_gnullvm 0.53.1",
4835
4693
"windows_aarch64_msvc 0.53.1",
4836
4694
"windows_i686_gnu 0.53.1",
···
4839
4697
"windows_x86_64_gnu 0.53.1",
4840
4698
"windows_x86_64_gnullvm 0.53.1",
4841
4699
"windows_x86_64_msvc 0.53.1",
4842
-
]
4843
-
4844
-
[[package]]
4845
-
name = "windows-threading"
4846
-
version = "0.1.0"
4847
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4848
-
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
4849
-
dependencies = [
4850
-
"windows-link 0.1.3",
4851
4700
]
4852
4701
4853
4702
[[package]]
···
5078
4927
"tower-http",
5079
4928
"url",
5080
4929
"walkdir",
4930
+
"wisp-lexicons",
4931
+
]
4932
+
4933
+
[[package]]
4934
+
name = "wisp-lexicons"
4935
+
version = "0.1.0"
4936
+
dependencies = [
4937
+
"jacquard-common",
4938
+
"jacquard-derive",
4939
+
"jacquard-lexicon",
4940
+
"rustversion",
4941
+
"serde",
5081
4942
]
5082
4943
5083
4944
[[package]]
···
5128
4989
dependencies = [
5129
4990
"proc-macro2",
5130
4991
"quote",
5131
-
"syn 2.0.111",
4992
+
"syn 2.0.113",
5132
4993
"synstructure",
5133
4994
]
5134
4995
5135
4996
[[package]]
5136
4997
name = "zerocopy"
5137
-
version = "0.8.30"
4998
+
version = "0.8.32"
5138
4999
source = "registry+https://github.com/rust-lang/crates.io-index"
5139
-
checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
5000
+
checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56"
5140
5001
dependencies = [
5141
5002
"zerocopy-derive",
5142
5003
]
5143
5004
5144
5005
[[package]]
5145
5006
name = "zerocopy-derive"
5146
-
version = "0.8.30"
5007
+
version = "0.8.32"
5147
5008
source = "registry+https://github.com/rust-lang/crates.io-index"
5148
-
checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
5009
+
checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90"
5149
5010
dependencies = [
5150
5011
"proc-macro2",
5151
5012
"quote",
5152
-
"syn 2.0.111",
5013
+
"syn 2.0.113",
5153
5014
]
5154
5015
5155
5016
[[package]]
···
5169
5030
dependencies = [
5170
5031
"proc-macro2",
5171
5032
"quote",
5172
-
"syn 2.0.111",
5033
+
"syn 2.0.113",
5173
5034
"synstructure",
5174
5035
]
5175
5036
···
5212
5073
dependencies = [
5213
5074
"proc-macro2",
5214
5075
"quote",
5215
-
"syn 2.0.111",
5076
+
"syn 2.0.113",
5216
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"
+15
-14
cli/Cargo.toml
+15
-14
cli/Cargo.toml
···
8
8
place_wisp = []
9
9
10
10
[dependencies]
11
-
# jacquard = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["loopback"] }
12
-
# jacquard-oauth = { git = "https://tangled.org/nekomimi.pet/jacquard" }
13
-
# jacquard-api = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["streaming"] }
14
-
# jacquard-common = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["websocket"] }
15
-
# jacquard-identity = { git = "https://tangled.org/nekomimi.pet/jacquard", features = ["dns"] }
16
-
# jacquard-derive = { git = "https://tangled.org/nekomimi.pet/jacquard" }
17
-
# jacquard-lexicon = { git = "https://tangled.org/nekomimi.pet/jacquard" }
18
-
jacquard = { path = "../../jacquard/crates/jacquard", features = ["loopback"] }
19
-
jacquard-oauth = { path = "../../jacquard/crates/jacquard-oauth" }
20
-
jacquard-api = { path = "../../jacquard/crates/jacquard-api", features = ["streaming"] }
21
-
jacquard-common = { path = "../../jacquard/crates/jacquard-common", features = ["websocket"] }
22
-
jacquard-identity = { path = "../../jacquard/crates/jacquard-identity", features = ["dns"] }
23
-
jacquard-derive = { path = "../../jacquard/crates/jacquard-derive" }
24
-
jacquard-lexicon = { path = "../../jacquard/crates/jacquard-lexicon" }
11
+
jacquard = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["loopback"] }
12
+
jacquard-oauth = { git = "https://tangled.org/nonbinary.computer/jacquard" }
13
+
jacquard-api = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["streaming"] }
14
+
jacquard-common = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["websocket"] }
15
+
jacquard-identity = { git = "https://tangled.org/nonbinary.computer/jacquard", features = ["dns"] }
16
+
jacquard-derive = { git = "https://tangled.org/nonbinary.computer/jacquard" }
17
+
jacquard-lexicon = { git = "https://tangled.org/nonbinary.computer/jacquard" }
18
+
wisp-lexicons = { path = "crates/lexicons" }
19
+
#jacquard = { path = "../../jacquard/crates/jacquard", features = ["loopback"] }
20
+
#jacquard-oauth = { path = "../../jacquard/crates/jacquard-oauth" }
21
+
#jacquard-api = { path = "../../jacquard/crates/jacquard-api", features = ["streaming"] }
22
+
#jacquard-common = { path = "../../jacquard/crates/jacquard-common", features = ["websocket"] }
23
+
#jacquard-identity = { path = "../../jacquard/crates/jacquard-identity", features = ["dns"] }
24
+
#jacquard-derive = { path = "../../jacquard/crates/jacquard-derive" }
25
+
#jacquard-lexicon = { path = "../../jacquard/crates/jacquard-lexicon" }
25
26
clap = { version = "4.5.51", features = ["derive"] }
26
27
tokio = { version = "1.48", features = ["full"] }
27
28
miette = { version = "7.6.0", features = ["fancy"] }
+72
-2
cli/README.md
+72
-2
cli/README.md
···
32
32
33
33
## Usage
34
34
35
+
### Commands
36
+
37
+
The CLI supports three main commands:
38
+
- **deploy**: Upload a site to your PDS (default command)
39
+
- **pull**: Download a site from a PDS to a local directory
40
+
- **serve**: Serve a site locally with real-time firehose updates
41
+
35
42
### Basic Deployment
36
43
37
44
Deploy the current directory:
38
45
39
46
```bash
40
-
wisp-cli nekomimi.ppet --path . --site my-site
47
+
wisp-cli nekomimi.pet --path . --site my-site
41
48
```
42
49
43
50
Deploy a specific directory:
···
46
53
wisp-cli alice.bsky.social --path ./dist/ --site my-site
47
54
```
48
55
56
+
Or use the explicit `deploy` subcommand:
57
+
58
+
```bash
59
+
wisp-cli deploy alice.bsky.social --path ./dist/ --site my-site
60
+
```
61
+
62
+
### Pull a Site
63
+
64
+
Download a site from a PDS to a local directory:
65
+
66
+
```bash
67
+
wisp-cli pull alice.bsky.social --site my-site --path ./downloaded-site
68
+
```
69
+
70
+
This will download all files from the site to the specified directory.
71
+
72
+
### Serve a Site Locally
73
+
74
+
Serve a site locally with real-time updates from the firehose:
75
+
76
+
```bash
77
+
wisp-cli serve alice.bsky.social --site my-site --path ./site --port 8080
78
+
```
79
+
80
+
This will:
81
+
1. Download the site to the specified path
82
+
2. Start a local server on the specified port (default: 8080)
83
+
3. Watch the firehose for updates and automatically reload files when changed
84
+
49
85
### Authentication Methods
50
86
51
87
#### OAuth (Recommended)
···
79
115
80
116
## Command-Line Options
81
117
118
+
### Deploy Command
119
+
82
120
```
83
-
wisp-cli [OPTIONS] <INPUT>
121
+
wisp-cli [deploy] [OPTIONS] <INPUT>
84
122
85
123
Arguments:
86
124
<INPUT> Handle (e.g., alice.bsky.social), DID, or PDS URL
···
90
128
-s, --site <SITE> Site name (defaults to directory name)
91
129
--store <STORE> Path to auth store file (only used with OAuth) [default: /tmp/wisp-oauth-session.json]
92
130
--password <PASSWORD> App Password for authentication (alternative to OAuth)
131
+
--directory Enable directory listing mode for paths without index files
132
+
--spa Enable SPA mode (serve index.html for all routes)
133
+
-y, --yes Skip confirmation prompts (automatically accept warnings)
93
134
-h, --help Print help
94
135
-V, --version Print version
136
+
```
137
+
138
+
### Pull Command
139
+
140
+
```
141
+
wisp-cli pull [OPTIONS] --site <SITE> <INPUT>
142
+
143
+
Arguments:
144
+
<INPUT> Handle (e.g., alice.bsky.social) or DID
145
+
146
+
Options:
147
+
-s, --site <SITE> Site name (record key)
148
+
-p, --path <PATH> Output directory for the downloaded site [default: .]
149
+
-h, --help Print help
150
+
```
151
+
152
+
### Serve Command
153
+
154
+
```
155
+
wisp-cli serve [OPTIONS] --site <SITE> <INPUT>
156
+
157
+
Arguments:
158
+
<INPUT> Handle (e.g., alice.bsky.social) or DID
159
+
160
+
Options:
161
+
-s, --site <SITE> Site name (record key)
162
+
-p, --path <PATH> Output directory for the site files [default: .]
163
+
-P, --port <PORT> Port to serve on [default: 8080]
164
+
-h, --help Print help
95
165
```
96
166
97
167
## How It Works
+15
cli/crates/lexicons/Cargo.toml
+15
cli/crates/lexicons/Cargo.toml
···
1
+
[package]
2
+
name = "wisp-lexicons"
3
+
version = "0.1.0"
4
+
edition = "2024"
5
+
6
+
[features]
7
+
default = ["place_wisp"]
8
+
place_wisp = []
9
+
10
+
[dependencies]
11
+
jacquard-common = { git = "https://tangled.org/nonbinary.computer/jacquard" }
12
+
jacquard-derive = { git = "https://tangled.org/nonbinary.computer/jacquard" }
13
+
jacquard-lexicon = { git = "https://tangled.org/nonbinary.computer/jacquard" }
14
+
serde = { version = "1.0", features = ["derive"] }
15
+
rustversion = "1.0"
+43
cli/crates/lexicons/src/builder_types.rs
+43
cli/crates/lexicons/src/builder_types.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// This file was automatically generated from Lexicon schemas.
4
+
// Any manual changes will be overwritten on the next regeneration.
5
+
6
+
/// Marker type indicating a builder field has been set
7
+
pub struct Set<T>(pub T);
8
+
impl<T> Set<T> {
9
+
/// Extract the inner value
10
+
#[inline]
11
+
pub fn into_inner(self) -> T {
12
+
self.0
13
+
}
14
+
}
15
+
16
+
/// Marker type indicating a builder field has not been set
17
+
pub struct Unset;
18
+
/// Trait indicating a builder field is set (has a value)
19
+
#[rustversion::attr(
20
+
since(1.78.0),
21
+
diagnostic::on_unimplemented(
22
+
message = "the field `{Self}` was not set, but this method requires it to be set",
23
+
label = "the field `{Self}` was not set"
24
+
)
25
+
)]
26
+
pub trait IsSet: private::Sealed {}
27
+
/// Trait indicating a builder field is unset (no value yet)
28
+
#[rustversion::attr(
29
+
since(1.78.0),
30
+
diagnostic::on_unimplemented(
31
+
message = "the field `{Self}` was already set, but this method requires it to be unset",
32
+
label = "the field `{Self}` was already set"
33
+
)
34
+
)]
35
+
pub trait IsUnset: private::Sealed {}
36
+
impl<T> IsSet for Set<T> {}
37
+
impl IsUnset for Unset {}
38
+
mod private {
39
+
/// Sealed trait to prevent external implementations
40
+
pub trait Sealed {}
41
+
impl<T> Sealed for super::Set<T> {}
42
+
impl Sealed for super::Unset {}
43
+
}
+11
cli/crates/lexicons/src/lib.rs
+11
cli/crates/lexicons/src/lib.rs
···
1
+
extern crate alloc;
2
+
3
+
// @generated by jacquard-lexicon. DO NOT EDIT.
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
pub mod builder_types;
9
+
10
+
#[cfg(feature = "place_wisp")]
11
+
pub mod place_wisp;
+1490
cli/crates/lexicons/src/place_wisp/fs.rs
+1490
cli/crates/lexicons/src/place_wisp/fs.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// Lexicon: place.wisp.fs
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
#[jacquard_derive::lexicon]
9
+
#[derive(
10
+
serde::Serialize,
11
+
serde::Deserialize,
12
+
Debug,
13
+
Clone,
14
+
PartialEq,
15
+
Eq,
16
+
jacquard_derive::IntoStatic
17
+
)]
18
+
#[serde(rename_all = "camelCase")]
19
+
pub struct Directory<'a> {
20
+
#[serde(borrow)]
21
+
pub entries: Vec<crate::place_wisp::fs::Entry<'a>>,
22
+
#[serde(borrow)]
23
+
pub r#type: jacquard_common::CowStr<'a>,
24
+
}
25
+
26
+
pub mod directory_state {
27
+
28
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
+
#[allow(unused)]
30
+
use ::core::marker::PhantomData;
31
+
mod sealed {
32
+
pub trait Sealed {}
33
+
}
34
+
/// State trait tracking which required fields have been set
35
+
pub trait State: sealed::Sealed {
36
+
type Type;
37
+
type Entries;
38
+
}
39
+
/// Empty state - all required fields are unset
40
+
pub struct Empty(());
41
+
impl sealed::Sealed for Empty {}
42
+
impl State for Empty {
43
+
type Type = Unset;
44
+
type Entries = Unset;
45
+
}
46
+
///State transition - sets the `type` field to Set
47
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
+
impl<S: State> sealed::Sealed for SetType<S> {}
49
+
impl<S: State> State for SetType<S> {
50
+
type Type = Set<members::r#type>;
51
+
type Entries = S::Entries;
52
+
}
53
+
///State transition - sets the `entries` field to Set
54
+
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
+
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
+
impl<S: State> State for SetEntries<S> {
57
+
type Type = S::Type;
58
+
type Entries = Set<members::entries>;
59
+
}
60
+
/// Marker types for field names
61
+
#[allow(non_camel_case_types)]
62
+
pub mod members {
63
+
///Marker type for the `type` field
64
+
pub struct r#type(());
65
+
///Marker type for the `entries` field
66
+
pub struct entries(());
67
+
}
68
+
}
69
+
70
+
/// Builder for constructing an instance of this type
71
+
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
+
__unsafe_private_named: (
74
+
::core::option::Option<Vec<crate::place_wisp::fs::Entry<'a>>>,
75
+
::core::option::Option<jacquard_common::CowStr<'a>>,
76
+
),
77
+
_phantom: ::core::marker::PhantomData<&'a ()>,
78
+
}
79
+
80
+
impl<'a> Directory<'a> {
81
+
/// Create a new builder for this type
82
+
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
+
DirectoryBuilder::new()
84
+
}
85
+
}
86
+
87
+
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
+
/// Create a new builder with all fields unset
89
+
pub fn new() -> Self {
90
+
DirectoryBuilder {
91
+
_phantom_state: ::core::marker::PhantomData,
92
+
__unsafe_private_named: (None, None),
93
+
_phantom: ::core::marker::PhantomData,
94
+
}
95
+
}
96
+
}
97
+
98
+
impl<'a, S> DirectoryBuilder<'a, S>
99
+
where
100
+
S: directory_state::State,
101
+
S::Entries: directory_state::IsUnset,
102
+
{
103
+
/// Set the `entries` field (required)
104
+
pub fn entries(
105
+
mut self,
106
+
value: impl Into<Vec<crate::place_wisp::fs::Entry<'a>>>,
107
+
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
+
DirectoryBuilder {
110
+
_phantom_state: ::core::marker::PhantomData,
111
+
__unsafe_private_named: self.__unsafe_private_named,
112
+
_phantom: ::core::marker::PhantomData,
113
+
}
114
+
}
115
+
}
116
+
117
+
impl<'a, S> DirectoryBuilder<'a, S>
118
+
where
119
+
S: directory_state::State,
120
+
S::Type: directory_state::IsUnset,
121
+
{
122
+
/// Set the `type` field (required)
123
+
pub fn r#type(
124
+
mut self,
125
+
value: impl Into<jacquard_common::CowStr<'a>>,
126
+
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
+
DirectoryBuilder {
129
+
_phantom_state: ::core::marker::PhantomData,
130
+
__unsafe_private_named: self.__unsafe_private_named,
131
+
_phantom: ::core::marker::PhantomData,
132
+
}
133
+
}
134
+
}
135
+
136
+
impl<'a, S> DirectoryBuilder<'a, S>
137
+
where
138
+
S: directory_state::State,
139
+
S::Type: directory_state::IsSet,
140
+
S::Entries: directory_state::IsSet,
141
+
{
142
+
/// Build the final struct
143
+
pub fn build(self) -> Directory<'a> {
144
+
Directory {
145
+
entries: self.__unsafe_private_named.0.unwrap(),
146
+
r#type: self.__unsafe_private_named.1.unwrap(),
147
+
extra_data: Default::default(),
148
+
}
149
+
}
150
+
/// Build the final struct with custom extra_data
151
+
pub fn build_with_data(
152
+
self,
153
+
extra_data: std::collections::BTreeMap<
154
+
jacquard_common::smol_str::SmolStr,
155
+
jacquard_common::types::value::Data<'a>,
156
+
>,
157
+
) -> Directory<'a> {
158
+
Directory {
159
+
entries: self.__unsafe_private_named.0.unwrap(),
160
+
r#type: self.__unsafe_private_named.1.unwrap(),
161
+
extra_data: Some(extra_data),
162
+
}
163
+
}
164
+
}
165
+
166
+
fn lexicon_doc_place_wisp_fs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
+
::jacquard_lexicon::lexicon::LexiconDoc {
168
+
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
+
id: ::jacquard_common::CowStr::new_static("place.wisp.fs"),
170
+
revision: None,
171
+
description: None,
172
+
defs: {
173
+
let mut map = ::std::collections::BTreeMap::new();
174
+
map.insert(
175
+
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
+
description: None,
178
+
required: Some(
179
+
vec![
180
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
+
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
+
],
183
+
),
184
+
nullable: None,
185
+
properties: {
186
+
#[allow(unused_mut)]
187
+
let mut map = ::std::collections::BTreeMap::new();
188
+
map.insert(
189
+
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
+
description: None,
192
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
+
description: None,
194
+
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
+
}),
196
+
min_length: None,
197
+
max_length: Some(500usize),
198
+
}),
199
+
);
200
+
map.insert(
201
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
+
description: None,
204
+
format: None,
205
+
default: None,
206
+
min_length: None,
207
+
max_length: None,
208
+
min_graphemes: None,
209
+
max_graphemes: None,
210
+
r#enum: None,
211
+
r#const: None,
212
+
known_values: None,
213
+
}),
214
+
);
215
+
map
216
+
},
217
+
}),
218
+
);
219
+
map.insert(
220
+
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
+
description: None,
223
+
required: Some(
224
+
vec![
225
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
+
::jacquard_common::smol_str::SmolStr::new_static("node")
227
+
],
228
+
),
229
+
nullable: None,
230
+
properties: {
231
+
#[allow(unused_mut)]
232
+
let mut map = ::std::collections::BTreeMap::new();
233
+
map.insert(
234
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
+
description: None,
237
+
format: None,
238
+
default: None,
239
+
min_length: None,
240
+
max_length: Some(255usize),
241
+
min_graphemes: None,
242
+
max_graphemes: None,
243
+
r#enum: None,
244
+
r#const: None,
245
+
known_values: None,
246
+
}),
247
+
);
248
+
map.insert(
249
+
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
+
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
+
description: None,
252
+
refs: vec![
253
+
::jacquard_common::CowStr::new_static("#file"),
254
+
::jacquard_common::CowStr::new_static("#directory"),
255
+
::jacquard_common::CowStr::new_static("#subfs")
256
+
],
257
+
closed: None,
258
+
}),
259
+
);
260
+
map
261
+
},
262
+
}),
263
+
);
264
+
map.insert(
265
+
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
+
description: None,
268
+
required: Some(
269
+
vec![
270
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
+
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
+
],
273
+
),
274
+
nullable: None,
275
+
properties: {
276
+
#[allow(unused_mut)]
277
+
let mut map = ::std::collections::BTreeMap::new();
278
+
map.insert(
279
+
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
+
description: None,
282
+
default: None,
283
+
r#const: None,
284
+
}),
285
+
);
286
+
map.insert(
287
+
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
+
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
+
description: None,
290
+
accept: None,
291
+
max_size: None,
292
+
}),
293
+
);
294
+
map.insert(
295
+
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
+
description: Some(
298
+
::jacquard_common::CowStr::new_static(
299
+
"Content encoding (e.g., gzip for compressed files)",
300
+
),
301
+
),
302
+
format: None,
303
+
default: None,
304
+
min_length: None,
305
+
max_length: None,
306
+
min_graphemes: None,
307
+
max_graphemes: None,
308
+
r#enum: None,
309
+
r#const: None,
310
+
known_values: None,
311
+
}),
312
+
);
313
+
map.insert(
314
+
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
+
description: Some(
317
+
::jacquard_common::CowStr::new_static(
318
+
"Original MIME type before compression",
319
+
),
320
+
),
321
+
format: None,
322
+
default: None,
323
+
min_length: None,
324
+
max_length: None,
325
+
min_graphemes: None,
326
+
max_graphemes: None,
327
+
r#enum: None,
328
+
r#const: None,
329
+
known_values: None,
330
+
}),
331
+
);
332
+
map.insert(
333
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
+
description: None,
336
+
format: None,
337
+
default: None,
338
+
min_length: None,
339
+
max_length: None,
340
+
min_graphemes: None,
341
+
max_graphemes: None,
342
+
r#enum: None,
343
+
r#const: None,
344
+
known_values: None,
345
+
}),
346
+
);
347
+
map
348
+
},
349
+
}),
350
+
);
351
+
map.insert(
352
+
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
+
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
+
description: Some(
355
+
::jacquard_common::CowStr::new_static(
356
+
"Virtual filesystem manifest for a Wisp site",
357
+
),
358
+
),
359
+
key: None,
360
+
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
+
description: None,
362
+
required: Some(
363
+
vec![
364
+
::jacquard_common::smol_str::SmolStr::new_static("site"),
365
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
366
+
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
367
+
],
368
+
),
369
+
nullable: None,
370
+
properties: {
371
+
#[allow(unused_mut)]
372
+
let mut map = ::std::collections::BTreeMap::new();
373
+
map.insert(
374
+
::jacquard_common::smol_str::SmolStr::new_static(
375
+
"createdAt",
376
+
),
377
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
378
+
description: None,
379
+
format: Some(
380
+
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
381
+
),
382
+
default: None,
383
+
min_length: None,
384
+
max_length: None,
385
+
min_graphemes: None,
386
+
max_graphemes: None,
387
+
r#enum: None,
388
+
r#const: None,
389
+
known_values: None,
390
+
}),
391
+
);
392
+
map.insert(
393
+
::jacquard_common::smol_str::SmolStr::new_static(
394
+
"fileCount",
395
+
),
396
+
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
397
+
description: None,
398
+
default: None,
399
+
minimum: Some(0i64),
400
+
maximum: Some(1000i64),
401
+
r#enum: None,
402
+
r#const: None,
403
+
}),
404
+
);
405
+
map.insert(
406
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
407
+
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
408
+
description: None,
409
+
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
410
+
}),
411
+
);
412
+
map.insert(
413
+
::jacquard_common::smol_str::SmolStr::new_static("site"),
414
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
415
+
description: None,
416
+
format: None,
417
+
default: None,
418
+
min_length: None,
419
+
max_length: None,
420
+
min_graphemes: None,
421
+
max_graphemes: None,
422
+
r#enum: None,
423
+
r#const: None,
424
+
known_values: None,
425
+
}),
426
+
);
427
+
map
428
+
},
429
+
}),
430
+
}),
431
+
);
432
+
map.insert(
433
+
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
434
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
435
+
description: None,
436
+
required: Some(
437
+
vec![
438
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
439
+
::jacquard_common::smol_str::SmolStr::new_static("subject")
440
+
],
441
+
),
442
+
nullable: None,
443
+
properties: {
444
+
#[allow(unused_mut)]
445
+
let mut map = ::std::collections::BTreeMap::new();
446
+
map.insert(
447
+
::jacquard_common::smol_str::SmolStr::new_static("flat"),
448
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
449
+
description: None,
450
+
default: None,
451
+
r#const: None,
452
+
}),
453
+
);
454
+
map.insert(
455
+
::jacquard_common::smol_str::SmolStr::new_static("subject"),
456
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
457
+
description: Some(
458
+
::jacquard_common::CowStr::new_static(
459
+
"AT-URI pointing to a place.wisp.subfs record containing this subtree.",
460
+
),
461
+
),
462
+
format: Some(
463
+
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
464
+
),
465
+
default: None,
466
+
min_length: None,
467
+
max_length: None,
468
+
min_graphemes: None,
469
+
max_graphemes: None,
470
+
r#enum: None,
471
+
r#const: None,
472
+
known_values: None,
473
+
}),
474
+
);
475
+
map.insert(
476
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
477
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
478
+
description: None,
479
+
format: None,
480
+
default: None,
481
+
min_length: None,
482
+
max_length: None,
483
+
min_graphemes: None,
484
+
max_graphemes: None,
485
+
r#enum: None,
486
+
r#const: None,
487
+
known_values: None,
488
+
}),
489
+
);
490
+
map
491
+
},
492
+
}),
493
+
);
494
+
map
495
+
},
496
+
}
497
+
}
498
+
499
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
500
+
fn nsid() -> &'static str {
501
+
"place.wisp.fs"
502
+
}
503
+
fn def_name() -> &'static str {
504
+
"directory"
505
+
}
506
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
507
+
lexicon_doc_place_wisp_fs()
508
+
}
509
+
fn validate(
510
+
&self,
511
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
512
+
{
513
+
let value = &self.entries;
514
+
#[allow(unused_comparisons)]
515
+
if value.len() > 500usize {
516
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
517
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
518
+
"entries",
519
+
),
520
+
max: 500usize,
521
+
actual: value.len(),
522
+
});
523
+
}
524
+
}
525
+
Ok(())
526
+
}
527
+
}
528
+
529
+
#[jacquard_derive::lexicon]
530
+
#[derive(
531
+
serde::Serialize,
532
+
serde::Deserialize,
533
+
Debug,
534
+
Clone,
535
+
PartialEq,
536
+
Eq,
537
+
jacquard_derive::IntoStatic
538
+
)]
539
+
#[serde(rename_all = "camelCase")]
540
+
pub struct Entry<'a> {
541
+
#[serde(borrow)]
542
+
pub name: jacquard_common::CowStr<'a>,
543
+
#[serde(borrow)]
544
+
pub node: EntryNode<'a>,
545
+
}
546
+
547
+
pub mod entry_state {
548
+
549
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
550
+
#[allow(unused)]
551
+
use ::core::marker::PhantomData;
552
+
mod sealed {
553
+
pub trait Sealed {}
554
+
}
555
+
/// State trait tracking which required fields have been set
556
+
pub trait State: sealed::Sealed {
557
+
type Node;
558
+
type Name;
559
+
}
560
+
/// Empty state - all required fields are unset
561
+
pub struct Empty(());
562
+
impl sealed::Sealed for Empty {}
563
+
impl State for Empty {
564
+
type Node = Unset;
565
+
type Name = Unset;
566
+
}
567
+
///State transition - sets the `node` field to Set
568
+
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
569
+
impl<S: State> sealed::Sealed for SetNode<S> {}
570
+
impl<S: State> State for SetNode<S> {
571
+
type Node = Set<members::node>;
572
+
type Name = S::Name;
573
+
}
574
+
///State transition - sets the `name` field to Set
575
+
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
576
+
impl<S: State> sealed::Sealed for SetName<S> {}
577
+
impl<S: State> State for SetName<S> {
578
+
type Node = S::Node;
579
+
type Name = Set<members::name>;
580
+
}
581
+
/// Marker types for field names
582
+
#[allow(non_camel_case_types)]
583
+
pub mod members {
584
+
///Marker type for the `node` field
585
+
pub struct node(());
586
+
///Marker type for the `name` field
587
+
pub struct name(());
588
+
}
589
+
}
590
+
591
+
/// Builder for constructing an instance of this type
592
+
pub struct EntryBuilder<'a, S: entry_state::State> {
593
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
594
+
__unsafe_private_named: (
595
+
::core::option::Option<jacquard_common::CowStr<'a>>,
596
+
::core::option::Option<EntryNode<'a>>,
597
+
),
598
+
_phantom: ::core::marker::PhantomData<&'a ()>,
599
+
}
600
+
601
+
impl<'a> Entry<'a> {
602
+
/// Create a new builder for this type
603
+
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
604
+
EntryBuilder::new()
605
+
}
606
+
}
607
+
608
+
impl<'a> EntryBuilder<'a, entry_state::Empty> {
609
+
/// Create a new builder with all fields unset
610
+
pub fn new() -> Self {
611
+
EntryBuilder {
612
+
_phantom_state: ::core::marker::PhantomData,
613
+
__unsafe_private_named: (None, None),
614
+
_phantom: ::core::marker::PhantomData,
615
+
}
616
+
}
617
+
}
618
+
619
+
impl<'a, S> EntryBuilder<'a, S>
620
+
where
621
+
S: entry_state::State,
622
+
S::Name: entry_state::IsUnset,
623
+
{
624
+
/// Set the `name` field (required)
625
+
pub fn name(
626
+
mut self,
627
+
value: impl Into<jacquard_common::CowStr<'a>>,
628
+
) -> EntryBuilder<'a, entry_state::SetName<S>> {
629
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
630
+
EntryBuilder {
631
+
_phantom_state: ::core::marker::PhantomData,
632
+
__unsafe_private_named: self.__unsafe_private_named,
633
+
_phantom: ::core::marker::PhantomData,
634
+
}
635
+
}
636
+
}
637
+
638
+
impl<'a, S> EntryBuilder<'a, S>
639
+
where
640
+
S: entry_state::State,
641
+
S::Node: entry_state::IsUnset,
642
+
{
643
+
/// Set the `node` field (required)
644
+
pub fn node(
645
+
mut self,
646
+
value: impl Into<EntryNode<'a>>,
647
+
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
648
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
649
+
EntryBuilder {
650
+
_phantom_state: ::core::marker::PhantomData,
651
+
__unsafe_private_named: self.__unsafe_private_named,
652
+
_phantom: ::core::marker::PhantomData,
653
+
}
654
+
}
655
+
}
656
+
657
+
impl<'a, S> EntryBuilder<'a, S>
658
+
where
659
+
S: entry_state::State,
660
+
S::Node: entry_state::IsSet,
661
+
S::Name: entry_state::IsSet,
662
+
{
663
+
/// Build the final struct
664
+
pub fn build(self) -> Entry<'a> {
665
+
Entry {
666
+
name: self.__unsafe_private_named.0.unwrap(),
667
+
node: self.__unsafe_private_named.1.unwrap(),
668
+
extra_data: Default::default(),
669
+
}
670
+
}
671
+
/// Build the final struct with custom extra_data
672
+
pub fn build_with_data(
673
+
self,
674
+
extra_data: std::collections::BTreeMap<
675
+
jacquard_common::smol_str::SmolStr,
676
+
jacquard_common::types::value::Data<'a>,
677
+
>,
678
+
) -> Entry<'a> {
679
+
Entry {
680
+
name: self.__unsafe_private_named.0.unwrap(),
681
+
node: self.__unsafe_private_named.1.unwrap(),
682
+
extra_data: Some(extra_data),
683
+
}
684
+
}
685
+
}
686
+
687
+
#[jacquard_derive::open_union]
688
+
#[derive(
689
+
serde::Serialize,
690
+
serde::Deserialize,
691
+
Debug,
692
+
Clone,
693
+
PartialEq,
694
+
Eq,
695
+
jacquard_derive::IntoStatic
696
+
)]
697
+
#[serde(tag = "$type")]
698
+
#[serde(bound(deserialize = "'de: 'a"))]
699
+
pub enum EntryNode<'a> {
700
+
#[serde(rename = "place.wisp.fs#file")]
701
+
File(Box<crate::place_wisp::fs::File<'a>>),
702
+
#[serde(rename = "place.wisp.fs#directory")]
703
+
Directory(Box<crate::place_wisp::fs::Directory<'a>>),
704
+
#[serde(rename = "place.wisp.fs#subfs")]
705
+
Subfs(Box<crate::place_wisp::fs::Subfs<'a>>),
706
+
}
707
+
708
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
709
+
fn nsid() -> &'static str {
710
+
"place.wisp.fs"
711
+
}
712
+
fn def_name() -> &'static str {
713
+
"entry"
714
+
}
715
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
716
+
lexicon_doc_place_wisp_fs()
717
+
}
718
+
fn validate(
719
+
&self,
720
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
721
+
{
722
+
let value = &self.name;
723
+
#[allow(unused_comparisons)]
724
+
if <str>::len(value.as_ref()) > 255usize {
725
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
726
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
727
+
"name",
728
+
),
729
+
max: 255usize,
730
+
actual: <str>::len(value.as_ref()),
731
+
});
732
+
}
733
+
}
734
+
Ok(())
735
+
}
736
+
}
737
+
738
+
#[jacquard_derive::lexicon]
739
+
#[derive(
740
+
serde::Serialize,
741
+
serde::Deserialize,
742
+
Debug,
743
+
Clone,
744
+
PartialEq,
745
+
Eq,
746
+
jacquard_derive::IntoStatic
747
+
)]
748
+
#[serde(rename_all = "camelCase")]
749
+
pub struct File<'a> {
750
+
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
751
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
752
+
pub base64: std::option::Option<bool>,
753
+
/// Content blob ref
754
+
#[serde(borrow)]
755
+
pub blob: jacquard_common::types::blob::BlobRef<'a>,
756
+
/// Content encoding (e.g., gzip for compressed files)
757
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
758
+
#[serde(borrow)]
759
+
pub encoding: std::option::Option<jacquard_common::CowStr<'a>>,
760
+
/// Original MIME type before compression
761
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
762
+
#[serde(borrow)]
763
+
pub mime_type: std::option::Option<jacquard_common::CowStr<'a>>,
764
+
#[serde(borrow)]
765
+
pub r#type: jacquard_common::CowStr<'a>,
766
+
}
767
+
768
+
pub mod file_state {
769
+
770
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
771
+
#[allow(unused)]
772
+
use ::core::marker::PhantomData;
773
+
mod sealed {
774
+
pub trait Sealed {}
775
+
}
776
+
/// State trait tracking which required fields have been set
777
+
pub trait State: sealed::Sealed {
778
+
type Type;
779
+
type Blob;
780
+
}
781
+
/// Empty state - all required fields are unset
782
+
pub struct Empty(());
783
+
impl sealed::Sealed for Empty {}
784
+
impl State for Empty {
785
+
type Type = Unset;
786
+
type Blob = Unset;
787
+
}
788
+
///State transition - sets the `type` field to Set
789
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
790
+
impl<S: State> sealed::Sealed for SetType<S> {}
791
+
impl<S: State> State for SetType<S> {
792
+
type Type = Set<members::r#type>;
793
+
type Blob = S::Blob;
794
+
}
795
+
///State transition - sets the `blob` field to Set
796
+
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
797
+
impl<S: State> sealed::Sealed for SetBlob<S> {}
798
+
impl<S: State> State for SetBlob<S> {
799
+
type Type = S::Type;
800
+
type Blob = Set<members::blob>;
801
+
}
802
+
/// Marker types for field names
803
+
#[allow(non_camel_case_types)]
804
+
pub mod members {
805
+
///Marker type for the `type` field
806
+
pub struct r#type(());
807
+
///Marker type for the `blob` field
808
+
pub struct blob(());
809
+
}
810
+
}
811
+
812
+
/// Builder for constructing an instance of this type
813
+
pub struct FileBuilder<'a, S: file_state::State> {
814
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
815
+
__unsafe_private_named: (
816
+
::core::option::Option<bool>,
817
+
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
818
+
::core::option::Option<jacquard_common::CowStr<'a>>,
819
+
::core::option::Option<jacquard_common::CowStr<'a>>,
820
+
::core::option::Option<jacquard_common::CowStr<'a>>,
821
+
),
822
+
_phantom: ::core::marker::PhantomData<&'a ()>,
823
+
}
824
+
825
+
impl<'a> File<'a> {
826
+
/// Create a new builder for this type
827
+
pub fn new() -> FileBuilder<'a, file_state::Empty> {
828
+
FileBuilder::new()
829
+
}
830
+
}
831
+
832
+
impl<'a> FileBuilder<'a, file_state::Empty> {
833
+
/// Create a new builder with all fields unset
834
+
pub fn new() -> Self {
835
+
FileBuilder {
836
+
_phantom_state: ::core::marker::PhantomData,
837
+
__unsafe_private_named: (None, None, None, None, None),
838
+
_phantom: ::core::marker::PhantomData,
839
+
}
840
+
}
841
+
}
842
+
843
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
844
+
/// Set the `base64` field (optional)
845
+
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
846
+
self.__unsafe_private_named.0 = value.into();
847
+
self
848
+
}
849
+
/// Set the `base64` field to an Option value (optional)
850
+
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
851
+
self.__unsafe_private_named.0 = value;
852
+
self
853
+
}
854
+
}
855
+
856
+
impl<'a, S> FileBuilder<'a, S>
857
+
where
858
+
S: file_state::State,
859
+
S::Blob: file_state::IsUnset,
860
+
{
861
+
/// Set the `blob` field (required)
862
+
pub fn blob(
863
+
mut self,
864
+
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
865
+
) -> FileBuilder<'a, file_state::SetBlob<S>> {
866
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
867
+
FileBuilder {
868
+
_phantom_state: ::core::marker::PhantomData,
869
+
__unsafe_private_named: self.__unsafe_private_named,
870
+
_phantom: ::core::marker::PhantomData,
871
+
}
872
+
}
873
+
}
874
+
875
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
876
+
/// Set the `encoding` field (optional)
877
+
pub fn encoding(
878
+
mut self,
879
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
880
+
) -> Self {
881
+
self.__unsafe_private_named.2 = value.into();
882
+
self
883
+
}
884
+
/// Set the `encoding` field to an Option value (optional)
885
+
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
886
+
self.__unsafe_private_named.2 = value;
887
+
self
888
+
}
889
+
}
890
+
891
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
892
+
/// Set the `mimeType` field (optional)
893
+
pub fn mime_type(
894
+
mut self,
895
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
896
+
) -> Self {
897
+
self.__unsafe_private_named.3 = value.into();
898
+
self
899
+
}
900
+
/// Set the `mimeType` field to an Option value (optional)
901
+
pub fn maybe_mime_type(
902
+
mut self,
903
+
value: Option<jacquard_common::CowStr<'a>>,
904
+
) -> Self {
905
+
self.__unsafe_private_named.3 = value;
906
+
self
907
+
}
908
+
}
909
+
910
+
impl<'a, S> FileBuilder<'a, S>
911
+
where
912
+
S: file_state::State,
913
+
S::Type: file_state::IsUnset,
914
+
{
915
+
/// Set the `type` field (required)
916
+
pub fn r#type(
917
+
mut self,
918
+
value: impl Into<jacquard_common::CowStr<'a>>,
919
+
) -> FileBuilder<'a, file_state::SetType<S>> {
920
+
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
921
+
FileBuilder {
922
+
_phantom_state: ::core::marker::PhantomData,
923
+
__unsafe_private_named: self.__unsafe_private_named,
924
+
_phantom: ::core::marker::PhantomData,
925
+
}
926
+
}
927
+
}
928
+
929
+
impl<'a, S> FileBuilder<'a, S>
930
+
where
931
+
S: file_state::State,
932
+
S::Type: file_state::IsSet,
933
+
S::Blob: file_state::IsSet,
934
+
{
935
+
/// Build the final struct
936
+
pub fn build(self) -> File<'a> {
937
+
File {
938
+
base64: self.__unsafe_private_named.0,
939
+
blob: self.__unsafe_private_named.1.unwrap(),
940
+
encoding: self.__unsafe_private_named.2,
941
+
mime_type: self.__unsafe_private_named.3,
942
+
r#type: self.__unsafe_private_named.4.unwrap(),
943
+
extra_data: Default::default(),
944
+
}
945
+
}
946
+
/// Build the final struct with custom extra_data
947
+
pub fn build_with_data(
948
+
self,
949
+
extra_data: std::collections::BTreeMap<
950
+
jacquard_common::smol_str::SmolStr,
951
+
jacquard_common::types::value::Data<'a>,
952
+
>,
953
+
) -> File<'a> {
954
+
File {
955
+
base64: self.__unsafe_private_named.0,
956
+
blob: self.__unsafe_private_named.1.unwrap(),
957
+
encoding: self.__unsafe_private_named.2,
958
+
mime_type: self.__unsafe_private_named.3,
959
+
r#type: self.__unsafe_private_named.4.unwrap(),
960
+
extra_data: Some(extra_data),
961
+
}
962
+
}
963
+
}
964
+
965
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
966
+
fn nsid() -> &'static str {
967
+
"place.wisp.fs"
968
+
}
969
+
fn def_name() -> &'static str {
970
+
"file"
971
+
}
972
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
973
+
lexicon_doc_place_wisp_fs()
974
+
}
975
+
fn validate(
976
+
&self,
977
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
978
+
Ok(())
979
+
}
980
+
}
981
+
982
+
/// Virtual filesystem manifest for a Wisp site
983
+
#[jacquard_derive::lexicon]
984
+
#[derive(
985
+
serde::Serialize,
986
+
serde::Deserialize,
987
+
Debug,
988
+
Clone,
989
+
PartialEq,
990
+
Eq,
991
+
jacquard_derive::IntoStatic
992
+
)]
993
+
#[serde(rename_all = "camelCase")]
994
+
pub struct Fs<'a> {
995
+
pub created_at: jacquard_common::types::string::Datetime,
996
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
997
+
pub file_count: std::option::Option<i64>,
998
+
#[serde(borrow)]
999
+
pub root: crate::place_wisp::fs::Directory<'a>,
1000
+
#[serde(borrow)]
1001
+
pub site: jacquard_common::CowStr<'a>,
1002
+
}
1003
+
1004
+
pub mod fs_state {
1005
+
1006
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1007
+
#[allow(unused)]
1008
+
use ::core::marker::PhantomData;
1009
+
mod sealed {
1010
+
pub trait Sealed {}
1011
+
}
1012
+
/// State trait tracking which required fields have been set
1013
+
pub trait State: sealed::Sealed {
1014
+
type CreatedAt;
1015
+
type Site;
1016
+
type Root;
1017
+
}
1018
+
/// Empty state - all required fields are unset
1019
+
pub struct Empty(());
1020
+
impl sealed::Sealed for Empty {}
1021
+
impl State for Empty {
1022
+
type CreatedAt = Unset;
1023
+
type Site = Unset;
1024
+
type Root = Unset;
1025
+
}
1026
+
///State transition - sets the `created_at` field to Set
1027
+
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1028
+
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1029
+
impl<S: State> State for SetCreatedAt<S> {
1030
+
type CreatedAt = Set<members::created_at>;
1031
+
type Site = S::Site;
1032
+
type Root = S::Root;
1033
+
}
1034
+
///State transition - sets the `site` field to Set
1035
+
pub struct SetSite<S: State = Empty>(PhantomData<fn() -> S>);
1036
+
impl<S: State> sealed::Sealed for SetSite<S> {}
1037
+
impl<S: State> State for SetSite<S> {
1038
+
type CreatedAt = S::CreatedAt;
1039
+
type Site = Set<members::site>;
1040
+
type Root = S::Root;
1041
+
}
1042
+
///State transition - sets the `root` field to Set
1043
+
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1044
+
impl<S: State> sealed::Sealed for SetRoot<S> {}
1045
+
impl<S: State> State for SetRoot<S> {
1046
+
type CreatedAt = S::CreatedAt;
1047
+
type Site = S::Site;
1048
+
type Root = Set<members::root>;
1049
+
}
1050
+
/// Marker types for field names
1051
+
#[allow(non_camel_case_types)]
1052
+
pub mod members {
1053
+
///Marker type for the `created_at` field
1054
+
pub struct created_at(());
1055
+
///Marker type for the `site` field
1056
+
pub struct site(());
1057
+
///Marker type for the `root` field
1058
+
pub struct root(());
1059
+
}
1060
+
}
1061
+
1062
+
/// Builder for constructing an instance of this type
1063
+
pub struct FsBuilder<'a, S: fs_state::State> {
1064
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1065
+
__unsafe_private_named: (
1066
+
::core::option::Option<jacquard_common::types::string::Datetime>,
1067
+
::core::option::Option<i64>,
1068
+
::core::option::Option<crate::place_wisp::fs::Directory<'a>>,
1069
+
::core::option::Option<jacquard_common::CowStr<'a>>,
1070
+
),
1071
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1072
+
}
1073
+
1074
+
impl<'a> Fs<'a> {
1075
+
/// Create a new builder for this type
1076
+
pub fn new() -> FsBuilder<'a, fs_state::Empty> {
1077
+
FsBuilder::new()
1078
+
}
1079
+
}
1080
+
1081
+
impl<'a> FsBuilder<'a, fs_state::Empty> {
1082
+
/// Create a new builder with all fields unset
1083
+
pub fn new() -> Self {
1084
+
FsBuilder {
1085
+
_phantom_state: ::core::marker::PhantomData,
1086
+
__unsafe_private_named: (None, None, None, None),
1087
+
_phantom: ::core::marker::PhantomData,
1088
+
}
1089
+
}
1090
+
}
1091
+
1092
+
impl<'a, S> FsBuilder<'a, S>
1093
+
where
1094
+
S: fs_state::State,
1095
+
S::CreatedAt: fs_state::IsUnset,
1096
+
{
1097
+
/// Set the `createdAt` field (required)
1098
+
pub fn created_at(
1099
+
mut self,
1100
+
value: impl Into<jacquard_common::types::string::Datetime>,
1101
+
) -> FsBuilder<'a, fs_state::SetCreatedAt<S>> {
1102
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1103
+
FsBuilder {
1104
+
_phantom_state: ::core::marker::PhantomData,
1105
+
__unsafe_private_named: self.__unsafe_private_named,
1106
+
_phantom: ::core::marker::PhantomData,
1107
+
}
1108
+
}
1109
+
}
1110
+
1111
+
impl<'a, S: fs_state::State> FsBuilder<'a, S> {
1112
+
/// Set the `fileCount` field (optional)
1113
+
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1114
+
self.__unsafe_private_named.1 = value.into();
1115
+
self
1116
+
}
1117
+
/// Set the `fileCount` field to an Option value (optional)
1118
+
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1119
+
self.__unsafe_private_named.1 = value;
1120
+
self
1121
+
}
1122
+
}
1123
+
1124
+
impl<'a, S> FsBuilder<'a, S>
1125
+
where
1126
+
S: fs_state::State,
1127
+
S::Root: fs_state::IsUnset,
1128
+
{
1129
+
/// Set the `root` field (required)
1130
+
pub fn root(
1131
+
mut self,
1132
+
value: impl Into<crate::place_wisp::fs::Directory<'a>>,
1133
+
) -> FsBuilder<'a, fs_state::SetRoot<S>> {
1134
+
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1135
+
FsBuilder {
1136
+
_phantom_state: ::core::marker::PhantomData,
1137
+
__unsafe_private_named: self.__unsafe_private_named,
1138
+
_phantom: ::core::marker::PhantomData,
1139
+
}
1140
+
}
1141
+
}
1142
+
1143
+
impl<'a, S> FsBuilder<'a, S>
1144
+
where
1145
+
S: fs_state::State,
1146
+
S::Site: fs_state::IsUnset,
1147
+
{
1148
+
/// Set the `site` field (required)
1149
+
pub fn site(
1150
+
mut self,
1151
+
value: impl Into<jacquard_common::CowStr<'a>>,
1152
+
) -> FsBuilder<'a, fs_state::SetSite<S>> {
1153
+
self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into());
1154
+
FsBuilder {
1155
+
_phantom_state: ::core::marker::PhantomData,
1156
+
__unsafe_private_named: self.__unsafe_private_named,
1157
+
_phantom: ::core::marker::PhantomData,
1158
+
}
1159
+
}
1160
+
}
1161
+
1162
+
impl<'a, S> FsBuilder<'a, S>
1163
+
where
1164
+
S: fs_state::State,
1165
+
S::CreatedAt: fs_state::IsSet,
1166
+
S::Site: fs_state::IsSet,
1167
+
S::Root: fs_state::IsSet,
1168
+
{
1169
+
/// Build the final struct
1170
+
pub fn build(self) -> Fs<'a> {
1171
+
Fs {
1172
+
created_at: self.__unsafe_private_named.0.unwrap(),
1173
+
file_count: self.__unsafe_private_named.1,
1174
+
root: self.__unsafe_private_named.2.unwrap(),
1175
+
site: self.__unsafe_private_named.3.unwrap(),
1176
+
extra_data: Default::default(),
1177
+
}
1178
+
}
1179
+
/// Build the final struct with custom extra_data
1180
+
pub fn build_with_data(
1181
+
self,
1182
+
extra_data: std::collections::BTreeMap<
1183
+
jacquard_common::smol_str::SmolStr,
1184
+
jacquard_common::types::value::Data<'a>,
1185
+
>,
1186
+
) -> Fs<'a> {
1187
+
Fs {
1188
+
created_at: self.__unsafe_private_named.0.unwrap(),
1189
+
file_count: self.__unsafe_private_named.1,
1190
+
root: self.__unsafe_private_named.2.unwrap(),
1191
+
site: self.__unsafe_private_named.3.unwrap(),
1192
+
extra_data: Some(extra_data),
1193
+
}
1194
+
}
1195
+
}
1196
+
1197
+
impl<'a> Fs<'a> {
1198
+
pub fn uri(
1199
+
uri: impl Into<jacquard_common::CowStr<'a>>,
1200
+
) -> Result<
1201
+
jacquard_common::types::uri::RecordUri<'a, FsRecord>,
1202
+
jacquard_common::types::uri::UriError,
1203
+
> {
1204
+
jacquard_common::types::uri::RecordUri::try_from_uri(
1205
+
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1206
+
)
1207
+
}
1208
+
}
1209
+
1210
+
/// Typed wrapper for GetRecord response with this collection's record type.
1211
+
#[derive(
1212
+
serde::Serialize,
1213
+
serde::Deserialize,
1214
+
Debug,
1215
+
Clone,
1216
+
PartialEq,
1217
+
Eq,
1218
+
jacquard_derive::IntoStatic
1219
+
)]
1220
+
#[serde(rename_all = "camelCase")]
1221
+
pub struct FsGetRecordOutput<'a> {
1222
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1223
+
#[serde(borrow)]
1224
+
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1225
+
#[serde(borrow)]
1226
+
pub uri: jacquard_common::types::string::AtUri<'a>,
1227
+
#[serde(borrow)]
1228
+
pub value: Fs<'a>,
1229
+
}
1230
+
1231
+
impl From<FsGetRecordOutput<'_>> for Fs<'_> {
1232
+
fn from(output: FsGetRecordOutput<'_>) -> Self {
1233
+
use jacquard_common::IntoStatic;
1234
+
output.value.into_static()
1235
+
}
1236
+
}
1237
+
1238
+
impl jacquard_common::types::collection::Collection for Fs<'_> {
1239
+
const NSID: &'static str = "place.wisp.fs";
1240
+
type Record = FsRecord;
1241
+
}
1242
+
1243
+
/// Marker type for deserializing records from this collection.
1244
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1245
+
pub struct FsRecord;
1246
+
impl jacquard_common::xrpc::XrpcResp for FsRecord {
1247
+
const NSID: &'static str = "place.wisp.fs";
1248
+
const ENCODING: &'static str = "application/json";
1249
+
type Output<'de> = FsGetRecordOutput<'de>;
1250
+
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1251
+
}
1252
+
1253
+
impl jacquard_common::types::collection::Collection for FsRecord {
1254
+
const NSID: &'static str = "place.wisp.fs";
1255
+
type Record = FsRecord;
1256
+
}
1257
+
1258
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Fs<'a> {
1259
+
fn nsid() -> &'static str {
1260
+
"place.wisp.fs"
1261
+
}
1262
+
fn def_name() -> &'static str {
1263
+
"main"
1264
+
}
1265
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1266
+
lexicon_doc_place_wisp_fs()
1267
+
}
1268
+
fn validate(
1269
+
&self,
1270
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1271
+
if let Some(ref value) = self.file_count {
1272
+
if *value > 1000i64 {
1273
+
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1274
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1275
+
"file_count",
1276
+
),
1277
+
max: 1000i64,
1278
+
actual: *value,
1279
+
});
1280
+
}
1281
+
}
1282
+
if let Some(ref value) = self.file_count {
1283
+
if *value < 0i64 {
1284
+
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1285
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1286
+
"file_count",
1287
+
),
1288
+
min: 0i64,
1289
+
actual: *value,
1290
+
});
1291
+
}
1292
+
}
1293
+
Ok(())
1294
+
}
1295
+
}
1296
+
1297
+
#[jacquard_derive::lexicon]
1298
+
#[derive(
1299
+
serde::Serialize,
1300
+
serde::Deserialize,
1301
+
Debug,
1302
+
Clone,
1303
+
PartialEq,
1304
+
Eq,
1305
+
jacquard_derive::IntoStatic
1306
+
)]
1307
+
#[serde(rename_all = "camelCase")]
1308
+
pub struct Subfs<'a> {
1309
+
/// If true (default), the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false, the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure.
1310
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1311
+
pub flat: std::option::Option<bool>,
1312
+
/// AT-URI pointing to a place.wisp.subfs record containing this subtree.
1313
+
#[serde(borrow)]
1314
+
pub subject: jacquard_common::types::string::AtUri<'a>,
1315
+
#[serde(borrow)]
1316
+
pub r#type: jacquard_common::CowStr<'a>,
1317
+
}
1318
+
1319
+
pub mod subfs_state {
1320
+
1321
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1322
+
#[allow(unused)]
1323
+
use ::core::marker::PhantomData;
1324
+
mod sealed {
1325
+
pub trait Sealed {}
1326
+
}
1327
+
/// State trait tracking which required fields have been set
1328
+
pub trait State: sealed::Sealed {
1329
+
type Type;
1330
+
type Subject;
1331
+
}
1332
+
/// Empty state - all required fields are unset
1333
+
pub struct Empty(());
1334
+
impl sealed::Sealed for Empty {}
1335
+
impl State for Empty {
1336
+
type Type = Unset;
1337
+
type Subject = Unset;
1338
+
}
1339
+
///State transition - sets the `type` field to Set
1340
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1341
+
impl<S: State> sealed::Sealed for SetType<S> {}
1342
+
impl<S: State> State for SetType<S> {
1343
+
type Type = Set<members::r#type>;
1344
+
type Subject = S::Subject;
1345
+
}
1346
+
///State transition - sets the `subject` field to Set
1347
+
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1348
+
impl<S: State> sealed::Sealed for SetSubject<S> {}
1349
+
impl<S: State> State for SetSubject<S> {
1350
+
type Type = S::Type;
1351
+
type Subject = Set<members::subject>;
1352
+
}
1353
+
/// Marker types for field names
1354
+
#[allow(non_camel_case_types)]
1355
+
pub mod members {
1356
+
///Marker type for the `type` field
1357
+
pub struct r#type(());
1358
+
///Marker type for the `subject` field
1359
+
pub struct subject(());
1360
+
}
1361
+
}
1362
+
1363
+
/// Builder for constructing an instance of this type
1364
+
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1365
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1366
+
__unsafe_private_named: (
1367
+
::core::option::Option<bool>,
1368
+
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1369
+
::core::option::Option<jacquard_common::CowStr<'a>>,
1370
+
),
1371
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1372
+
}
1373
+
1374
+
impl<'a> Subfs<'a> {
1375
+
/// Create a new builder for this type
1376
+
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1377
+
SubfsBuilder::new()
1378
+
}
1379
+
}
1380
+
1381
+
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1382
+
/// Create a new builder with all fields unset
1383
+
pub fn new() -> Self {
1384
+
SubfsBuilder {
1385
+
_phantom_state: ::core::marker::PhantomData,
1386
+
__unsafe_private_named: (None, None, None),
1387
+
_phantom: ::core::marker::PhantomData,
1388
+
}
1389
+
}
1390
+
}
1391
+
1392
+
impl<'a, S: subfs_state::State> SubfsBuilder<'a, S> {
1393
+
/// Set the `flat` field (optional)
1394
+
pub fn flat(mut self, value: impl Into<Option<bool>>) -> Self {
1395
+
self.__unsafe_private_named.0 = value.into();
1396
+
self
1397
+
}
1398
+
/// Set the `flat` field to an Option value (optional)
1399
+
pub fn maybe_flat(mut self, value: Option<bool>) -> Self {
1400
+
self.__unsafe_private_named.0 = value;
1401
+
self
1402
+
}
1403
+
}
1404
+
1405
+
impl<'a, S> SubfsBuilder<'a, S>
1406
+
where
1407
+
S: subfs_state::State,
1408
+
S::Subject: subfs_state::IsUnset,
1409
+
{
1410
+
/// Set the `subject` field (required)
1411
+
pub fn subject(
1412
+
mut self,
1413
+
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1414
+
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1415
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1416
+
SubfsBuilder {
1417
+
_phantom_state: ::core::marker::PhantomData,
1418
+
__unsafe_private_named: self.__unsafe_private_named,
1419
+
_phantom: ::core::marker::PhantomData,
1420
+
}
1421
+
}
1422
+
}
1423
+
1424
+
impl<'a, S> SubfsBuilder<'a, S>
1425
+
where
1426
+
S: subfs_state::State,
1427
+
S::Type: subfs_state::IsUnset,
1428
+
{
1429
+
/// Set the `type` field (required)
1430
+
pub fn r#type(
1431
+
mut self,
1432
+
value: impl Into<jacquard_common::CowStr<'a>>,
1433
+
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1434
+
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1435
+
SubfsBuilder {
1436
+
_phantom_state: ::core::marker::PhantomData,
1437
+
__unsafe_private_named: self.__unsafe_private_named,
1438
+
_phantom: ::core::marker::PhantomData,
1439
+
}
1440
+
}
1441
+
}
1442
+
1443
+
impl<'a, S> SubfsBuilder<'a, S>
1444
+
where
1445
+
S: subfs_state::State,
1446
+
S::Type: subfs_state::IsSet,
1447
+
S::Subject: subfs_state::IsSet,
1448
+
{
1449
+
/// Build the final struct
1450
+
pub fn build(self) -> Subfs<'a> {
1451
+
Subfs {
1452
+
flat: self.__unsafe_private_named.0,
1453
+
subject: self.__unsafe_private_named.1.unwrap(),
1454
+
r#type: self.__unsafe_private_named.2.unwrap(),
1455
+
extra_data: Default::default(),
1456
+
}
1457
+
}
1458
+
/// Build the final struct with custom extra_data
1459
+
pub fn build_with_data(
1460
+
self,
1461
+
extra_data: std::collections::BTreeMap<
1462
+
jacquard_common::smol_str::SmolStr,
1463
+
jacquard_common::types::value::Data<'a>,
1464
+
>,
1465
+
) -> Subfs<'a> {
1466
+
Subfs {
1467
+
flat: self.__unsafe_private_named.0,
1468
+
subject: self.__unsafe_private_named.1.unwrap(),
1469
+
r#type: self.__unsafe_private_named.2.unwrap(),
1470
+
extra_data: Some(extra_data),
1471
+
}
1472
+
}
1473
+
}
1474
+
1475
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1476
+
fn nsid() -> &'static str {
1477
+
"place.wisp.fs"
1478
+
}
1479
+
fn def_name() -> &'static str {
1480
+
"subfs"
1481
+
}
1482
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1483
+
lexicon_doc_place_wisp_fs()
1484
+
}
1485
+
fn validate(
1486
+
&self,
1487
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1488
+
Ok(())
1489
+
}
1490
+
}
+653
cli/crates/lexicons/src/place_wisp/settings.rs
+653
cli/crates/lexicons/src/place_wisp/settings.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// Lexicon: place.wisp.settings
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
/// Custom HTTP header configuration
9
+
#[jacquard_derive::lexicon]
10
+
#[derive(
11
+
serde::Serialize,
12
+
serde::Deserialize,
13
+
Debug,
14
+
Clone,
15
+
PartialEq,
16
+
Eq,
17
+
jacquard_derive::IntoStatic,
18
+
Default
19
+
)]
20
+
#[serde(rename_all = "camelCase")]
21
+
pub struct CustomHeader<'a> {
22
+
/// HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')
23
+
#[serde(borrow)]
24
+
pub name: jacquard_common::CowStr<'a>,
25
+
/// Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.
26
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
27
+
#[serde(borrow)]
28
+
pub path: std::option::Option<jacquard_common::CowStr<'a>>,
29
+
/// HTTP header value
30
+
#[serde(borrow)]
31
+
pub value: jacquard_common::CowStr<'a>,
32
+
}
33
+
34
+
fn lexicon_doc_place_wisp_settings() -> ::jacquard_lexicon::lexicon::LexiconDoc<
35
+
'static,
36
+
> {
37
+
::jacquard_lexicon::lexicon::LexiconDoc {
38
+
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
39
+
id: ::jacquard_common::CowStr::new_static("place.wisp.settings"),
40
+
revision: None,
41
+
description: None,
42
+
defs: {
43
+
let mut map = ::std::collections::BTreeMap::new();
44
+
map.insert(
45
+
::jacquard_common::smol_str::SmolStr::new_static("customHeader"),
46
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
47
+
description: Some(
48
+
::jacquard_common::CowStr::new_static(
49
+
"Custom HTTP header configuration",
50
+
),
51
+
),
52
+
required: Some(
53
+
vec![
54
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
55
+
::jacquard_common::smol_str::SmolStr::new_static("value")
56
+
],
57
+
),
58
+
nullable: None,
59
+
properties: {
60
+
#[allow(unused_mut)]
61
+
let mut map = ::std::collections::BTreeMap::new();
62
+
map.insert(
63
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
64
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
65
+
description: Some(
66
+
::jacquard_common::CowStr::new_static(
67
+
"HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
68
+
),
69
+
),
70
+
format: None,
71
+
default: None,
72
+
min_length: None,
73
+
max_length: Some(100usize),
74
+
min_graphemes: None,
75
+
max_graphemes: None,
76
+
r#enum: None,
77
+
r#const: None,
78
+
known_values: None,
79
+
}),
80
+
);
81
+
map.insert(
82
+
::jacquard_common::smol_str::SmolStr::new_static("path"),
83
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
84
+
description: Some(
85
+
::jacquard_common::CowStr::new_static(
86
+
"Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
87
+
),
88
+
),
89
+
format: None,
90
+
default: None,
91
+
min_length: None,
92
+
max_length: Some(500usize),
93
+
min_graphemes: None,
94
+
max_graphemes: None,
95
+
r#enum: None,
96
+
r#const: None,
97
+
known_values: None,
98
+
}),
99
+
);
100
+
map.insert(
101
+
::jacquard_common::smol_str::SmolStr::new_static("value"),
102
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
103
+
description: Some(
104
+
::jacquard_common::CowStr::new_static("HTTP header value"),
105
+
),
106
+
format: None,
107
+
default: None,
108
+
min_length: None,
109
+
max_length: Some(1000usize),
110
+
min_graphemes: None,
111
+
max_graphemes: None,
112
+
r#enum: None,
113
+
r#const: None,
114
+
known_values: None,
115
+
}),
116
+
);
117
+
map
118
+
},
119
+
}),
120
+
);
121
+
map.insert(
122
+
::jacquard_common::smol_str::SmolStr::new_static("main"),
123
+
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
124
+
description: Some(
125
+
::jacquard_common::CowStr::new_static(
126
+
"Configuration settings for a static site hosted on wisp.place",
127
+
),
128
+
),
129
+
key: Some(::jacquard_common::CowStr::new_static("any")),
130
+
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
131
+
description: None,
132
+
required: None,
133
+
nullable: None,
134
+
properties: {
135
+
#[allow(unused_mut)]
136
+
let mut map = ::std::collections::BTreeMap::new();
137
+
map.insert(
138
+
::jacquard_common::smol_str::SmolStr::new_static(
139
+
"cleanUrls",
140
+
),
141
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
142
+
description: None,
143
+
default: None,
144
+
r#const: None,
145
+
}),
146
+
);
147
+
map.insert(
148
+
::jacquard_common::smol_str::SmolStr::new_static(
149
+
"custom404",
150
+
),
151
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
152
+
description: Some(
153
+
::jacquard_common::CowStr::new_static(
154
+
"Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
155
+
),
156
+
),
157
+
format: None,
158
+
default: None,
159
+
min_length: None,
160
+
max_length: Some(500usize),
161
+
min_graphemes: None,
162
+
max_graphemes: None,
163
+
r#enum: None,
164
+
r#const: None,
165
+
known_values: None,
166
+
}),
167
+
);
168
+
map.insert(
169
+
::jacquard_common::smol_str::SmolStr::new_static(
170
+
"directoryListing",
171
+
),
172
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
173
+
description: None,
174
+
default: None,
175
+
r#const: None,
176
+
}),
177
+
);
178
+
map.insert(
179
+
::jacquard_common::smol_str::SmolStr::new_static("headers"),
180
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
181
+
description: Some(
182
+
::jacquard_common::CowStr::new_static(
183
+
"Custom HTTP headers to set on responses",
184
+
),
185
+
),
186
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
187
+
description: None,
188
+
r#ref: ::jacquard_common::CowStr::new_static(
189
+
"#customHeader",
190
+
),
191
+
}),
192
+
min_length: None,
193
+
max_length: Some(50usize),
194
+
}),
195
+
);
196
+
map.insert(
197
+
::jacquard_common::smol_str::SmolStr::new_static(
198
+
"indexFiles",
199
+
),
200
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
201
+
description: Some(
202
+
::jacquard_common::CowStr::new_static(
203
+
"Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
204
+
),
205
+
),
206
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::String(::jacquard_lexicon::lexicon::LexString {
207
+
description: None,
208
+
format: None,
209
+
default: None,
210
+
min_length: None,
211
+
max_length: Some(255usize),
212
+
min_graphemes: None,
213
+
max_graphemes: None,
214
+
r#enum: None,
215
+
r#const: None,
216
+
known_values: None,
217
+
}),
218
+
min_length: None,
219
+
max_length: Some(10usize),
220
+
}),
221
+
);
222
+
map.insert(
223
+
::jacquard_common::smol_str::SmolStr::new_static("spaMode"),
224
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
225
+
description: Some(
226
+
::jacquard_common::CowStr::new_static(
227
+
"File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.",
228
+
),
229
+
),
230
+
format: None,
231
+
default: None,
232
+
min_length: None,
233
+
max_length: Some(500usize),
234
+
min_graphemes: None,
235
+
max_graphemes: None,
236
+
r#enum: None,
237
+
r#const: None,
238
+
known_values: None,
239
+
}),
240
+
);
241
+
map
242
+
},
243
+
}),
244
+
}),
245
+
);
246
+
map
247
+
},
248
+
}
249
+
}
250
+
251
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for CustomHeader<'a> {
252
+
fn nsid() -> &'static str {
253
+
"place.wisp.settings"
254
+
}
255
+
fn def_name() -> &'static str {
256
+
"customHeader"
257
+
}
258
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
259
+
lexicon_doc_place_wisp_settings()
260
+
}
261
+
fn validate(
262
+
&self,
263
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
264
+
{
265
+
let value = &self.name;
266
+
#[allow(unused_comparisons)]
267
+
if <str>::len(value.as_ref()) > 100usize {
268
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
269
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
270
+
"name",
271
+
),
272
+
max: 100usize,
273
+
actual: <str>::len(value.as_ref()),
274
+
});
275
+
}
276
+
}
277
+
if let Some(ref value) = self.path {
278
+
#[allow(unused_comparisons)]
279
+
if <str>::len(value.as_ref()) > 500usize {
280
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
281
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
282
+
"path",
283
+
),
284
+
max: 500usize,
285
+
actual: <str>::len(value.as_ref()),
286
+
});
287
+
}
288
+
}
289
+
{
290
+
let value = &self.value;
291
+
#[allow(unused_comparisons)]
292
+
if <str>::len(value.as_ref()) > 1000usize {
293
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
294
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
295
+
"value",
296
+
),
297
+
max: 1000usize,
298
+
actual: <str>::len(value.as_ref()),
299
+
});
300
+
}
301
+
}
302
+
Ok(())
303
+
}
304
+
}
305
+
306
+
/// Configuration settings for a static site hosted on wisp.place
307
+
#[jacquard_derive::lexicon]
308
+
#[derive(
309
+
serde::Serialize,
310
+
serde::Deserialize,
311
+
Debug,
312
+
Clone,
313
+
PartialEq,
314
+
Eq,
315
+
jacquard_derive::IntoStatic
316
+
)]
317
+
#[serde(rename_all = "camelCase")]
318
+
pub struct Settings<'a> {
319
+
/// Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.
320
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
321
+
pub clean_urls: std::option::Option<bool>,
322
+
/// Custom 404 error page file path. Incompatible with directoryListing and spaMode.
323
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
324
+
#[serde(borrow)]
325
+
pub custom404: std::option::Option<jacquard_common::CowStr<'a>>,
326
+
/// Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.
327
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
328
+
pub directory_listing: std::option::Option<bool>,
329
+
/// Custom HTTP headers to set on responses
330
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
331
+
#[serde(borrow)]
332
+
pub headers: std::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
333
+
/// Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.
334
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
335
+
#[serde(borrow)]
336
+
pub index_files: std::option::Option<Vec<jacquard_common::CowStr<'a>>>,
337
+
/// File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.
338
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
339
+
#[serde(borrow)]
340
+
pub spa_mode: std::option::Option<jacquard_common::CowStr<'a>>,
341
+
}
342
+
343
+
pub mod settings_state {
344
+
345
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
346
+
#[allow(unused)]
347
+
use ::core::marker::PhantomData;
348
+
mod sealed {
349
+
pub trait Sealed {}
350
+
}
351
+
/// State trait tracking which required fields have been set
352
+
pub trait State: sealed::Sealed {}
353
+
/// Empty state - all required fields are unset
354
+
pub struct Empty(());
355
+
impl sealed::Sealed for Empty {}
356
+
impl State for Empty {}
357
+
/// Marker types for field names
358
+
#[allow(non_camel_case_types)]
359
+
pub mod members {}
360
+
}
361
+
362
+
/// Builder for constructing an instance of this type
363
+
pub struct SettingsBuilder<'a, S: settings_state::State> {
364
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
365
+
__unsafe_private_named: (
366
+
::core::option::Option<bool>,
367
+
::core::option::Option<jacquard_common::CowStr<'a>>,
368
+
::core::option::Option<bool>,
369
+
::core::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
370
+
::core::option::Option<Vec<jacquard_common::CowStr<'a>>>,
371
+
::core::option::Option<jacquard_common::CowStr<'a>>,
372
+
),
373
+
_phantom: ::core::marker::PhantomData<&'a ()>,
374
+
}
375
+
376
+
impl<'a> Settings<'a> {
377
+
/// Create a new builder for this type
378
+
pub fn new() -> SettingsBuilder<'a, settings_state::Empty> {
379
+
SettingsBuilder::new()
380
+
}
381
+
}
382
+
383
+
impl<'a> SettingsBuilder<'a, settings_state::Empty> {
384
+
/// Create a new builder with all fields unset
385
+
pub fn new() -> Self {
386
+
SettingsBuilder {
387
+
_phantom_state: ::core::marker::PhantomData,
388
+
__unsafe_private_named: (None, None, None, None, None, None),
389
+
_phantom: ::core::marker::PhantomData,
390
+
}
391
+
}
392
+
}
393
+
394
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
395
+
/// Set the `cleanUrls` field (optional)
396
+
pub fn clean_urls(mut self, value: impl Into<Option<bool>>) -> Self {
397
+
self.__unsafe_private_named.0 = value.into();
398
+
self
399
+
}
400
+
/// Set the `cleanUrls` field to an Option value (optional)
401
+
pub fn maybe_clean_urls(mut self, value: Option<bool>) -> Self {
402
+
self.__unsafe_private_named.0 = value;
403
+
self
404
+
}
405
+
}
406
+
407
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
408
+
/// Set the `custom404` field (optional)
409
+
pub fn custom404(
410
+
mut self,
411
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
412
+
) -> Self {
413
+
self.__unsafe_private_named.1 = value.into();
414
+
self
415
+
}
416
+
/// Set the `custom404` field to an Option value (optional)
417
+
pub fn maybe_custom404(
418
+
mut self,
419
+
value: Option<jacquard_common::CowStr<'a>>,
420
+
) -> Self {
421
+
self.__unsafe_private_named.1 = value;
422
+
self
423
+
}
424
+
}
425
+
426
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
427
+
/// Set the `directoryListing` field (optional)
428
+
pub fn directory_listing(mut self, value: impl Into<Option<bool>>) -> Self {
429
+
self.__unsafe_private_named.2 = value.into();
430
+
self
431
+
}
432
+
/// Set the `directoryListing` field to an Option value (optional)
433
+
pub fn maybe_directory_listing(mut self, value: Option<bool>) -> Self {
434
+
self.__unsafe_private_named.2 = value;
435
+
self
436
+
}
437
+
}
438
+
439
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
440
+
/// Set the `headers` field (optional)
441
+
pub fn headers(
442
+
mut self,
443
+
value: impl Into<Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>>,
444
+
) -> Self {
445
+
self.__unsafe_private_named.3 = value.into();
446
+
self
447
+
}
448
+
/// Set the `headers` field to an Option value (optional)
449
+
pub fn maybe_headers(
450
+
mut self,
451
+
value: Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
452
+
) -> Self {
453
+
self.__unsafe_private_named.3 = value;
454
+
self
455
+
}
456
+
}
457
+
458
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
459
+
/// Set the `indexFiles` field (optional)
460
+
pub fn index_files(
461
+
mut self,
462
+
value: impl Into<Option<Vec<jacquard_common::CowStr<'a>>>>,
463
+
) -> Self {
464
+
self.__unsafe_private_named.4 = value.into();
465
+
self
466
+
}
467
+
/// Set the `indexFiles` field to an Option value (optional)
468
+
pub fn maybe_index_files(
469
+
mut self,
470
+
value: Option<Vec<jacquard_common::CowStr<'a>>>,
471
+
) -> Self {
472
+
self.__unsafe_private_named.4 = value;
473
+
self
474
+
}
475
+
}
476
+
477
+
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
478
+
/// Set the `spaMode` field (optional)
479
+
pub fn spa_mode(
480
+
mut self,
481
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
482
+
) -> Self {
483
+
self.__unsafe_private_named.5 = value.into();
484
+
self
485
+
}
486
+
/// Set the `spaMode` field to an Option value (optional)
487
+
pub fn maybe_spa_mode(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
488
+
self.__unsafe_private_named.5 = value;
489
+
self
490
+
}
491
+
}
492
+
493
+
impl<'a, S> SettingsBuilder<'a, S>
494
+
where
495
+
S: settings_state::State,
496
+
{
497
+
/// Build the final struct
498
+
pub fn build(self) -> Settings<'a> {
499
+
Settings {
500
+
clean_urls: self.__unsafe_private_named.0,
501
+
custom404: self.__unsafe_private_named.1,
502
+
directory_listing: self.__unsafe_private_named.2,
503
+
headers: self.__unsafe_private_named.3,
504
+
index_files: self.__unsafe_private_named.4,
505
+
spa_mode: self.__unsafe_private_named.5,
506
+
extra_data: Default::default(),
507
+
}
508
+
}
509
+
/// Build the final struct with custom extra_data
510
+
pub fn build_with_data(
511
+
self,
512
+
extra_data: std::collections::BTreeMap<
513
+
jacquard_common::smol_str::SmolStr,
514
+
jacquard_common::types::value::Data<'a>,
515
+
>,
516
+
) -> Settings<'a> {
517
+
Settings {
518
+
clean_urls: self.__unsafe_private_named.0,
519
+
custom404: self.__unsafe_private_named.1,
520
+
directory_listing: self.__unsafe_private_named.2,
521
+
headers: self.__unsafe_private_named.3,
522
+
index_files: self.__unsafe_private_named.4,
523
+
spa_mode: self.__unsafe_private_named.5,
524
+
extra_data: Some(extra_data),
525
+
}
526
+
}
527
+
}
528
+
529
+
impl<'a> Settings<'a> {
530
+
pub fn uri(
531
+
uri: impl Into<jacquard_common::CowStr<'a>>,
532
+
) -> Result<
533
+
jacquard_common::types::uri::RecordUri<'a, SettingsRecord>,
534
+
jacquard_common::types::uri::UriError,
535
+
> {
536
+
jacquard_common::types::uri::RecordUri::try_from_uri(
537
+
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
538
+
)
539
+
}
540
+
}
541
+
542
+
/// Typed wrapper for GetRecord response with this collection's record type.
543
+
#[derive(
544
+
serde::Serialize,
545
+
serde::Deserialize,
546
+
Debug,
547
+
Clone,
548
+
PartialEq,
549
+
Eq,
550
+
jacquard_derive::IntoStatic
551
+
)]
552
+
#[serde(rename_all = "camelCase")]
553
+
pub struct SettingsGetRecordOutput<'a> {
554
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
555
+
#[serde(borrow)]
556
+
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
557
+
#[serde(borrow)]
558
+
pub uri: jacquard_common::types::string::AtUri<'a>,
559
+
#[serde(borrow)]
560
+
pub value: Settings<'a>,
561
+
}
562
+
563
+
impl From<SettingsGetRecordOutput<'_>> for Settings<'_> {
564
+
fn from(output: SettingsGetRecordOutput<'_>) -> Self {
565
+
use jacquard_common::IntoStatic;
566
+
output.value.into_static()
567
+
}
568
+
}
569
+
570
+
impl jacquard_common::types::collection::Collection for Settings<'_> {
571
+
const NSID: &'static str = "place.wisp.settings";
572
+
type Record = SettingsRecord;
573
+
}
574
+
575
+
/// Marker type for deserializing records from this collection.
576
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
577
+
pub struct SettingsRecord;
578
+
impl jacquard_common::xrpc::XrpcResp for SettingsRecord {
579
+
const NSID: &'static str = "place.wisp.settings";
580
+
const ENCODING: &'static str = "application/json";
581
+
type Output<'de> = SettingsGetRecordOutput<'de>;
582
+
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
583
+
}
584
+
585
+
impl jacquard_common::types::collection::Collection for SettingsRecord {
586
+
const NSID: &'static str = "place.wisp.settings";
587
+
type Record = SettingsRecord;
588
+
}
589
+
590
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Settings<'a> {
591
+
fn nsid() -> &'static str {
592
+
"place.wisp.settings"
593
+
}
594
+
fn def_name() -> &'static str {
595
+
"main"
596
+
}
597
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
598
+
lexicon_doc_place_wisp_settings()
599
+
}
600
+
fn validate(
601
+
&self,
602
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
603
+
if let Some(ref value) = self.custom404 {
604
+
#[allow(unused_comparisons)]
605
+
if <str>::len(value.as_ref()) > 500usize {
606
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
607
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
608
+
"custom404",
609
+
),
610
+
max: 500usize,
611
+
actual: <str>::len(value.as_ref()),
612
+
});
613
+
}
614
+
}
615
+
if let Some(ref value) = self.headers {
616
+
#[allow(unused_comparisons)]
617
+
if value.len() > 50usize {
618
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
619
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
620
+
"headers",
621
+
),
622
+
max: 50usize,
623
+
actual: value.len(),
624
+
});
625
+
}
626
+
}
627
+
if let Some(ref value) = self.index_files {
628
+
#[allow(unused_comparisons)]
629
+
if value.len() > 10usize {
630
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
631
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
632
+
"index_files",
633
+
),
634
+
max: 10usize,
635
+
actual: value.len(),
636
+
});
637
+
}
638
+
}
639
+
if let Some(ref value) = self.spa_mode {
640
+
#[allow(unused_comparisons)]
641
+
if <str>::len(value.as_ref()) > 500usize {
642
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
643
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
644
+
"spa_mode",
645
+
),
646
+
max: 500usize,
647
+
actual: <str>::len(value.as_ref()),
648
+
});
649
+
}
650
+
}
651
+
Ok(())
652
+
}
653
+
}
+1408
cli/crates/lexicons/src/place_wisp/subfs.rs
+1408
cli/crates/lexicons/src/place_wisp/subfs.rs
···
1
+
// @generated by jacquard-lexicon. DO NOT EDIT.
2
+
//
3
+
// Lexicon: place.wisp.subfs
4
+
//
5
+
// This file was automatically generated from Lexicon schemas.
6
+
// Any manual changes will be overwritten on the next regeneration.
7
+
8
+
#[jacquard_derive::lexicon]
9
+
#[derive(
10
+
serde::Serialize,
11
+
serde::Deserialize,
12
+
Debug,
13
+
Clone,
14
+
PartialEq,
15
+
Eq,
16
+
jacquard_derive::IntoStatic
17
+
)]
18
+
#[serde(rename_all = "camelCase")]
19
+
pub struct Directory<'a> {
20
+
#[serde(borrow)]
21
+
pub entries: Vec<crate::place_wisp::subfs::Entry<'a>>,
22
+
#[serde(borrow)]
23
+
pub r#type: jacquard_common::CowStr<'a>,
24
+
}
25
+
26
+
pub mod directory_state {
27
+
28
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
+
#[allow(unused)]
30
+
use ::core::marker::PhantomData;
31
+
mod sealed {
32
+
pub trait Sealed {}
33
+
}
34
+
/// State trait tracking which required fields have been set
35
+
pub trait State: sealed::Sealed {
36
+
type Type;
37
+
type Entries;
38
+
}
39
+
/// Empty state - all required fields are unset
40
+
pub struct Empty(());
41
+
impl sealed::Sealed for Empty {}
42
+
impl State for Empty {
43
+
type Type = Unset;
44
+
type Entries = Unset;
45
+
}
46
+
///State transition - sets the `type` field to Set
47
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
+
impl<S: State> sealed::Sealed for SetType<S> {}
49
+
impl<S: State> State for SetType<S> {
50
+
type Type = Set<members::r#type>;
51
+
type Entries = S::Entries;
52
+
}
53
+
///State transition - sets the `entries` field to Set
54
+
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
+
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
+
impl<S: State> State for SetEntries<S> {
57
+
type Type = S::Type;
58
+
type Entries = Set<members::entries>;
59
+
}
60
+
/// Marker types for field names
61
+
#[allow(non_camel_case_types)]
62
+
pub mod members {
63
+
///Marker type for the `type` field
64
+
pub struct r#type(());
65
+
///Marker type for the `entries` field
66
+
pub struct entries(());
67
+
}
68
+
}
69
+
70
+
/// Builder for constructing an instance of this type
71
+
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
+
__unsafe_private_named: (
74
+
::core::option::Option<Vec<crate::place_wisp::subfs::Entry<'a>>>,
75
+
::core::option::Option<jacquard_common::CowStr<'a>>,
76
+
),
77
+
_phantom: ::core::marker::PhantomData<&'a ()>,
78
+
}
79
+
80
+
impl<'a> Directory<'a> {
81
+
/// Create a new builder for this type
82
+
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
+
DirectoryBuilder::new()
84
+
}
85
+
}
86
+
87
+
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
+
/// Create a new builder with all fields unset
89
+
pub fn new() -> Self {
90
+
DirectoryBuilder {
91
+
_phantom_state: ::core::marker::PhantomData,
92
+
__unsafe_private_named: (None, None),
93
+
_phantom: ::core::marker::PhantomData,
94
+
}
95
+
}
96
+
}
97
+
98
+
impl<'a, S> DirectoryBuilder<'a, S>
99
+
where
100
+
S: directory_state::State,
101
+
S::Entries: directory_state::IsUnset,
102
+
{
103
+
/// Set the `entries` field (required)
104
+
pub fn entries(
105
+
mut self,
106
+
value: impl Into<Vec<crate::place_wisp::subfs::Entry<'a>>>,
107
+
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
+
DirectoryBuilder {
110
+
_phantom_state: ::core::marker::PhantomData,
111
+
__unsafe_private_named: self.__unsafe_private_named,
112
+
_phantom: ::core::marker::PhantomData,
113
+
}
114
+
}
115
+
}
116
+
117
+
impl<'a, S> DirectoryBuilder<'a, S>
118
+
where
119
+
S: directory_state::State,
120
+
S::Type: directory_state::IsUnset,
121
+
{
122
+
/// Set the `type` field (required)
123
+
pub fn r#type(
124
+
mut self,
125
+
value: impl Into<jacquard_common::CowStr<'a>>,
126
+
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
+
DirectoryBuilder {
129
+
_phantom_state: ::core::marker::PhantomData,
130
+
__unsafe_private_named: self.__unsafe_private_named,
131
+
_phantom: ::core::marker::PhantomData,
132
+
}
133
+
}
134
+
}
135
+
136
+
impl<'a, S> DirectoryBuilder<'a, S>
137
+
where
138
+
S: directory_state::State,
139
+
S::Type: directory_state::IsSet,
140
+
S::Entries: directory_state::IsSet,
141
+
{
142
+
/// Build the final struct
143
+
pub fn build(self) -> Directory<'a> {
144
+
Directory {
145
+
entries: self.__unsafe_private_named.0.unwrap(),
146
+
r#type: self.__unsafe_private_named.1.unwrap(),
147
+
extra_data: Default::default(),
148
+
}
149
+
}
150
+
/// Build the final struct with custom extra_data
151
+
pub fn build_with_data(
152
+
self,
153
+
extra_data: std::collections::BTreeMap<
154
+
jacquard_common::smol_str::SmolStr,
155
+
jacquard_common::types::value::Data<'a>,
156
+
>,
157
+
) -> Directory<'a> {
158
+
Directory {
159
+
entries: self.__unsafe_private_named.0.unwrap(),
160
+
r#type: self.__unsafe_private_named.1.unwrap(),
161
+
extra_data: Some(extra_data),
162
+
}
163
+
}
164
+
}
165
+
166
+
fn lexicon_doc_place_wisp_subfs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
+
::jacquard_lexicon::lexicon::LexiconDoc {
168
+
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
+
id: ::jacquard_common::CowStr::new_static("place.wisp.subfs"),
170
+
revision: None,
171
+
description: None,
172
+
defs: {
173
+
let mut map = ::std::collections::BTreeMap::new();
174
+
map.insert(
175
+
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
+
description: None,
178
+
required: Some(
179
+
vec![
180
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
+
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
+
],
183
+
),
184
+
nullable: None,
185
+
properties: {
186
+
#[allow(unused_mut)]
187
+
let mut map = ::std::collections::BTreeMap::new();
188
+
map.insert(
189
+
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
+
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
+
description: None,
192
+
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
+
description: None,
194
+
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
+
}),
196
+
min_length: None,
197
+
max_length: Some(500usize),
198
+
}),
199
+
);
200
+
map.insert(
201
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
+
description: None,
204
+
format: None,
205
+
default: None,
206
+
min_length: None,
207
+
max_length: None,
208
+
min_graphemes: None,
209
+
max_graphemes: None,
210
+
r#enum: None,
211
+
r#const: None,
212
+
known_values: None,
213
+
}),
214
+
);
215
+
map
216
+
},
217
+
}),
218
+
);
219
+
map.insert(
220
+
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
+
description: None,
223
+
required: Some(
224
+
vec![
225
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
+
::jacquard_common::smol_str::SmolStr::new_static("node")
227
+
],
228
+
),
229
+
nullable: None,
230
+
properties: {
231
+
#[allow(unused_mut)]
232
+
let mut map = ::std::collections::BTreeMap::new();
233
+
map.insert(
234
+
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
+
description: None,
237
+
format: None,
238
+
default: None,
239
+
min_length: None,
240
+
max_length: Some(255usize),
241
+
min_graphemes: None,
242
+
max_graphemes: None,
243
+
r#enum: None,
244
+
r#const: None,
245
+
known_values: None,
246
+
}),
247
+
);
248
+
map.insert(
249
+
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
+
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
+
description: None,
252
+
refs: vec![
253
+
::jacquard_common::CowStr::new_static("#file"),
254
+
::jacquard_common::CowStr::new_static("#directory"),
255
+
::jacquard_common::CowStr::new_static("#subfs")
256
+
],
257
+
closed: None,
258
+
}),
259
+
);
260
+
map
261
+
},
262
+
}),
263
+
);
264
+
map.insert(
265
+
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
+
description: None,
268
+
required: Some(
269
+
vec![
270
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
+
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
+
],
273
+
),
274
+
nullable: None,
275
+
properties: {
276
+
#[allow(unused_mut)]
277
+
let mut map = ::std::collections::BTreeMap::new();
278
+
map.insert(
279
+
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
+
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
+
description: None,
282
+
default: None,
283
+
r#const: None,
284
+
}),
285
+
);
286
+
map.insert(
287
+
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
+
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
+
description: None,
290
+
accept: None,
291
+
max_size: None,
292
+
}),
293
+
);
294
+
map.insert(
295
+
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
+
description: Some(
298
+
::jacquard_common::CowStr::new_static(
299
+
"Content encoding (e.g., gzip for compressed files)",
300
+
),
301
+
),
302
+
format: None,
303
+
default: None,
304
+
min_length: None,
305
+
max_length: None,
306
+
min_graphemes: None,
307
+
max_graphemes: None,
308
+
r#enum: None,
309
+
r#const: None,
310
+
known_values: None,
311
+
}),
312
+
);
313
+
map.insert(
314
+
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
+
description: Some(
317
+
::jacquard_common::CowStr::new_static(
318
+
"Original MIME type before compression",
319
+
),
320
+
),
321
+
format: None,
322
+
default: None,
323
+
min_length: None,
324
+
max_length: None,
325
+
min_graphemes: None,
326
+
max_graphemes: None,
327
+
r#enum: None,
328
+
r#const: None,
329
+
known_values: None,
330
+
}),
331
+
);
332
+
map.insert(
333
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
+
description: None,
336
+
format: None,
337
+
default: None,
338
+
min_length: None,
339
+
max_length: None,
340
+
min_graphemes: None,
341
+
max_graphemes: None,
342
+
r#enum: None,
343
+
r#const: None,
344
+
known_values: None,
345
+
}),
346
+
);
347
+
map
348
+
},
349
+
}),
350
+
);
351
+
map.insert(
352
+
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
+
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
+
description: Some(
355
+
::jacquard_common::CowStr::new_static(
356
+
"Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.",
357
+
),
358
+
),
359
+
key: None,
360
+
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
+
description: None,
362
+
required: Some(
363
+
vec![
364
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
365
+
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
366
+
],
367
+
),
368
+
nullable: None,
369
+
properties: {
370
+
#[allow(unused_mut)]
371
+
let mut map = ::std::collections::BTreeMap::new();
372
+
map.insert(
373
+
::jacquard_common::smol_str::SmolStr::new_static(
374
+
"createdAt",
375
+
),
376
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
377
+
description: None,
378
+
format: Some(
379
+
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
380
+
),
381
+
default: None,
382
+
min_length: None,
383
+
max_length: None,
384
+
min_graphemes: None,
385
+
max_graphemes: None,
386
+
r#enum: None,
387
+
r#const: None,
388
+
known_values: None,
389
+
}),
390
+
);
391
+
map.insert(
392
+
::jacquard_common::smol_str::SmolStr::new_static(
393
+
"fileCount",
394
+
),
395
+
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
396
+
description: None,
397
+
default: None,
398
+
minimum: Some(0i64),
399
+
maximum: Some(1000i64),
400
+
r#enum: None,
401
+
r#const: None,
402
+
}),
403
+
);
404
+
map.insert(
405
+
::jacquard_common::smol_str::SmolStr::new_static("root"),
406
+
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
407
+
description: None,
408
+
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
409
+
}),
410
+
);
411
+
map
412
+
},
413
+
}),
414
+
}),
415
+
);
416
+
map.insert(
417
+
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
418
+
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
419
+
description: None,
420
+
required: Some(
421
+
vec![
422
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
423
+
::jacquard_common::smol_str::SmolStr::new_static("subject")
424
+
],
425
+
),
426
+
nullable: None,
427
+
properties: {
428
+
#[allow(unused_mut)]
429
+
let mut map = ::std::collections::BTreeMap::new();
430
+
map.insert(
431
+
::jacquard_common::smol_str::SmolStr::new_static("subject"),
432
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
433
+
description: Some(
434
+
::jacquard_common::CowStr::new_static(
435
+
"AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.",
436
+
),
437
+
),
438
+
format: Some(
439
+
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
440
+
),
441
+
default: None,
442
+
min_length: None,
443
+
max_length: None,
444
+
min_graphemes: None,
445
+
max_graphemes: None,
446
+
r#enum: None,
447
+
r#const: None,
448
+
known_values: None,
449
+
}),
450
+
);
451
+
map.insert(
452
+
::jacquard_common::smol_str::SmolStr::new_static("type"),
453
+
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
454
+
description: None,
455
+
format: None,
456
+
default: None,
457
+
min_length: None,
458
+
max_length: None,
459
+
min_graphemes: None,
460
+
max_graphemes: None,
461
+
r#enum: None,
462
+
r#const: None,
463
+
known_values: None,
464
+
}),
465
+
);
466
+
map
467
+
},
468
+
}),
469
+
);
470
+
map
471
+
},
472
+
}
473
+
}
474
+
475
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
476
+
fn nsid() -> &'static str {
477
+
"place.wisp.subfs"
478
+
}
479
+
fn def_name() -> &'static str {
480
+
"directory"
481
+
}
482
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
483
+
lexicon_doc_place_wisp_subfs()
484
+
}
485
+
fn validate(
486
+
&self,
487
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
488
+
{
489
+
let value = &self.entries;
490
+
#[allow(unused_comparisons)]
491
+
if value.len() > 500usize {
492
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
493
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
494
+
"entries",
495
+
),
496
+
max: 500usize,
497
+
actual: value.len(),
498
+
});
499
+
}
500
+
}
501
+
Ok(())
502
+
}
503
+
}
504
+
505
+
#[jacquard_derive::lexicon]
506
+
#[derive(
507
+
serde::Serialize,
508
+
serde::Deserialize,
509
+
Debug,
510
+
Clone,
511
+
PartialEq,
512
+
Eq,
513
+
jacquard_derive::IntoStatic
514
+
)]
515
+
#[serde(rename_all = "camelCase")]
516
+
pub struct Entry<'a> {
517
+
#[serde(borrow)]
518
+
pub name: jacquard_common::CowStr<'a>,
519
+
#[serde(borrow)]
520
+
pub node: EntryNode<'a>,
521
+
}
522
+
523
+
pub mod entry_state {
524
+
525
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
526
+
#[allow(unused)]
527
+
use ::core::marker::PhantomData;
528
+
mod sealed {
529
+
pub trait Sealed {}
530
+
}
531
+
/// State trait tracking which required fields have been set
532
+
pub trait State: sealed::Sealed {
533
+
type Name;
534
+
type Node;
535
+
}
536
+
/// Empty state - all required fields are unset
537
+
pub struct Empty(());
538
+
impl sealed::Sealed for Empty {}
539
+
impl State for Empty {
540
+
type Name = Unset;
541
+
type Node = Unset;
542
+
}
543
+
///State transition - sets the `name` field to Set
544
+
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
545
+
impl<S: State> sealed::Sealed for SetName<S> {}
546
+
impl<S: State> State for SetName<S> {
547
+
type Name = Set<members::name>;
548
+
type Node = S::Node;
549
+
}
550
+
///State transition - sets the `node` field to Set
551
+
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
552
+
impl<S: State> sealed::Sealed for SetNode<S> {}
553
+
impl<S: State> State for SetNode<S> {
554
+
type Name = S::Name;
555
+
type Node = Set<members::node>;
556
+
}
557
+
/// Marker types for field names
558
+
#[allow(non_camel_case_types)]
559
+
pub mod members {
560
+
///Marker type for the `name` field
561
+
pub struct name(());
562
+
///Marker type for the `node` field
563
+
pub struct node(());
564
+
}
565
+
}
566
+
567
+
/// Builder for constructing an instance of this type
568
+
pub struct EntryBuilder<'a, S: entry_state::State> {
569
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
570
+
__unsafe_private_named: (
571
+
::core::option::Option<jacquard_common::CowStr<'a>>,
572
+
::core::option::Option<EntryNode<'a>>,
573
+
),
574
+
_phantom: ::core::marker::PhantomData<&'a ()>,
575
+
}
576
+
577
+
impl<'a> Entry<'a> {
578
+
/// Create a new builder for this type
579
+
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
580
+
EntryBuilder::new()
581
+
}
582
+
}
583
+
584
+
impl<'a> EntryBuilder<'a, entry_state::Empty> {
585
+
/// Create a new builder with all fields unset
586
+
pub fn new() -> Self {
587
+
EntryBuilder {
588
+
_phantom_state: ::core::marker::PhantomData,
589
+
__unsafe_private_named: (None, None),
590
+
_phantom: ::core::marker::PhantomData,
591
+
}
592
+
}
593
+
}
594
+
595
+
impl<'a, S> EntryBuilder<'a, S>
596
+
where
597
+
S: entry_state::State,
598
+
S::Name: entry_state::IsUnset,
599
+
{
600
+
/// Set the `name` field (required)
601
+
pub fn name(
602
+
mut self,
603
+
value: impl Into<jacquard_common::CowStr<'a>>,
604
+
) -> EntryBuilder<'a, entry_state::SetName<S>> {
605
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
606
+
EntryBuilder {
607
+
_phantom_state: ::core::marker::PhantomData,
608
+
__unsafe_private_named: self.__unsafe_private_named,
609
+
_phantom: ::core::marker::PhantomData,
610
+
}
611
+
}
612
+
}
613
+
614
+
impl<'a, S> EntryBuilder<'a, S>
615
+
where
616
+
S: entry_state::State,
617
+
S::Node: entry_state::IsUnset,
618
+
{
619
+
/// Set the `node` field (required)
620
+
pub fn node(
621
+
mut self,
622
+
value: impl Into<EntryNode<'a>>,
623
+
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
624
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
625
+
EntryBuilder {
626
+
_phantom_state: ::core::marker::PhantomData,
627
+
__unsafe_private_named: self.__unsafe_private_named,
628
+
_phantom: ::core::marker::PhantomData,
629
+
}
630
+
}
631
+
}
632
+
633
+
impl<'a, S> EntryBuilder<'a, S>
634
+
where
635
+
S: entry_state::State,
636
+
S::Name: entry_state::IsSet,
637
+
S::Node: entry_state::IsSet,
638
+
{
639
+
/// Build the final struct
640
+
pub fn build(self) -> Entry<'a> {
641
+
Entry {
642
+
name: self.__unsafe_private_named.0.unwrap(),
643
+
node: self.__unsafe_private_named.1.unwrap(),
644
+
extra_data: Default::default(),
645
+
}
646
+
}
647
+
/// Build the final struct with custom extra_data
648
+
pub fn build_with_data(
649
+
self,
650
+
extra_data: std::collections::BTreeMap<
651
+
jacquard_common::smol_str::SmolStr,
652
+
jacquard_common::types::value::Data<'a>,
653
+
>,
654
+
) -> Entry<'a> {
655
+
Entry {
656
+
name: self.__unsafe_private_named.0.unwrap(),
657
+
node: self.__unsafe_private_named.1.unwrap(),
658
+
extra_data: Some(extra_data),
659
+
}
660
+
}
661
+
}
662
+
663
+
#[jacquard_derive::open_union]
664
+
#[derive(
665
+
serde::Serialize,
666
+
serde::Deserialize,
667
+
Debug,
668
+
Clone,
669
+
PartialEq,
670
+
Eq,
671
+
jacquard_derive::IntoStatic
672
+
)]
673
+
#[serde(tag = "$type")]
674
+
#[serde(bound(deserialize = "'de: 'a"))]
675
+
pub enum EntryNode<'a> {
676
+
#[serde(rename = "place.wisp.subfs#file")]
677
+
File(Box<crate::place_wisp::subfs::File<'a>>),
678
+
#[serde(rename = "place.wisp.subfs#directory")]
679
+
Directory(Box<crate::place_wisp::subfs::Directory<'a>>),
680
+
#[serde(rename = "place.wisp.subfs#subfs")]
681
+
Subfs(Box<crate::place_wisp::subfs::Subfs<'a>>),
682
+
}
683
+
684
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
685
+
fn nsid() -> &'static str {
686
+
"place.wisp.subfs"
687
+
}
688
+
fn def_name() -> &'static str {
689
+
"entry"
690
+
}
691
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
692
+
lexicon_doc_place_wisp_subfs()
693
+
}
694
+
fn validate(
695
+
&self,
696
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
697
+
{
698
+
let value = &self.name;
699
+
#[allow(unused_comparisons)]
700
+
if <str>::len(value.as_ref()) > 255usize {
701
+
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
702
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
703
+
"name",
704
+
),
705
+
max: 255usize,
706
+
actual: <str>::len(value.as_ref()),
707
+
});
708
+
}
709
+
}
710
+
Ok(())
711
+
}
712
+
}
713
+
714
+
#[jacquard_derive::lexicon]
715
+
#[derive(
716
+
serde::Serialize,
717
+
serde::Deserialize,
718
+
Debug,
719
+
Clone,
720
+
PartialEq,
721
+
Eq,
722
+
jacquard_derive::IntoStatic
723
+
)]
724
+
#[serde(rename_all = "camelCase")]
725
+
pub struct File<'a> {
726
+
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
727
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
728
+
pub base64: std::option::Option<bool>,
729
+
/// Content blob ref
730
+
#[serde(borrow)]
731
+
pub blob: jacquard_common::types::blob::BlobRef<'a>,
732
+
/// Content encoding (e.g., gzip for compressed files)
733
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
734
+
#[serde(borrow)]
735
+
pub encoding: std::option::Option<jacquard_common::CowStr<'a>>,
736
+
/// Original MIME type before compression
737
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
738
+
#[serde(borrow)]
739
+
pub mime_type: std::option::Option<jacquard_common::CowStr<'a>>,
740
+
#[serde(borrow)]
741
+
pub r#type: jacquard_common::CowStr<'a>,
742
+
}
743
+
744
+
pub mod file_state {
745
+
746
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
747
+
#[allow(unused)]
748
+
use ::core::marker::PhantomData;
749
+
mod sealed {
750
+
pub trait Sealed {}
751
+
}
752
+
/// State trait tracking which required fields have been set
753
+
pub trait State: sealed::Sealed {
754
+
type Blob;
755
+
type Type;
756
+
}
757
+
/// Empty state - all required fields are unset
758
+
pub struct Empty(());
759
+
impl sealed::Sealed for Empty {}
760
+
impl State for Empty {
761
+
type Blob = Unset;
762
+
type Type = Unset;
763
+
}
764
+
///State transition - sets the `blob` field to Set
765
+
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
766
+
impl<S: State> sealed::Sealed for SetBlob<S> {}
767
+
impl<S: State> State for SetBlob<S> {
768
+
type Blob = Set<members::blob>;
769
+
type Type = S::Type;
770
+
}
771
+
///State transition - sets the `type` field to Set
772
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
773
+
impl<S: State> sealed::Sealed for SetType<S> {}
774
+
impl<S: State> State for SetType<S> {
775
+
type Blob = S::Blob;
776
+
type Type = Set<members::r#type>;
777
+
}
778
+
/// Marker types for field names
779
+
#[allow(non_camel_case_types)]
780
+
pub mod members {
781
+
///Marker type for the `blob` field
782
+
pub struct blob(());
783
+
///Marker type for the `type` field
784
+
pub struct r#type(());
785
+
}
786
+
}
787
+
788
+
/// Builder for constructing an instance of this type
789
+
pub struct FileBuilder<'a, S: file_state::State> {
790
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
791
+
__unsafe_private_named: (
792
+
::core::option::Option<bool>,
793
+
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
794
+
::core::option::Option<jacquard_common::CowStr<'a>>,
795
+
::core::option::Option<jacquard_common::CowStr<'a>>,
796
+
::core::option::Option<jacquard_common::CowStr<'a>>,
797
+
),
798
+
_phantom: ::core::marker::PhantomData<&'a ()>,
799
+
}
800
+
801
+
impl<'a> File<'a> {
802
+
/// Create a new builder for this type
803
+
pub fn new() -> FileBuilder<'a, file_state::Empty> {
804
+
FileBuilder::new()
805
+
}
806
+
}
807
+
808
+
impl<'a> FileBuilder<'a, file_state::Empty> {
809
+
/// Create a new builder with all fields unset
810
+
pub fn new() -> Self {
811
+
FileBuilder {
812
+
_phantom_state: ::core::marker::PhantomData,
813
+
__unsafe_private_named: (None, None, None, None, None),
814
+
_phantom: ::core::marker::PhantomData,
815
+
}
816
+
}
817
+
}
818
+
819
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
820
+
/// Set the `base64` field (optional)
821
+
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
822
+
self.__unsafe_private_named.0 = value.into();
823
+
self
824
+
}
825
+
/// Set the `base64` field to an Option value (optional)
826
+
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
827
+
self.__unsafe_private_named.0 = value;
828
+
self
829
+
}
830
+
}
831
+
832
+
impl<'a, S> FileBuilder<'a, S>
833
+
where
834
+
S: file_state::State,
835
+
S::Blob: file_state::IsUnset,
836
+
{
837
+
/// Set the `blob` field (required)
838
+
pub fn blob(
839
+
mut self,
840
+
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
841
+
) -> FileBuilder<'a, file_state::SetBlob<S>> {
842
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
843
+
FileBuilder {
844
+
_phantom_state: ::core::marker::PhantomData,
845
+
__unsafe_private_named: self.__unsafe_private_named,
846
+
_phantom: ::core::marker::PhantomData,
847
+
}
848
+
}
849
+
}
850
+
851
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
852
+
/// Set the `encoding` field (optional)
853
+
pub fn encoding(
854
+
mut self,
855
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
856
+
) -> Self {
857
+
self.__unsafe_private_named.2 = value.into();
858
+
self
859
+
}
860
+
/// Set the `encoding` field to an Option value (optional)
861
+
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
862
+
self.__unsafe_private_named.2 = value;
863
+
self
864
+
}
865
+
}
866
+
867
+
impl<'a, S: file_state::State> FileBuilder<'a, S> {
868
+
/// Set the `mimeType` field (optional)
869
+
pub fn mime_type(
870
+
mut self,
871
+
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
872
+
) -> Self {
873
+
self.__unsafe_private_named.3 = value.into();
874
+
self
875
+
}
876
+
/// Set the `mimeType` field to an Option value (optional)
877
+
pub fn maybe_mime_type(
878
+
mut self,
879
+
value: Option<jacquard_common::CowStr<'a>>,
880
+
) -> Self {
881
+
self.__unsafe_private_named.3 = value;
882
+
self
883
+
}
884
+
}
885
+
886
+
impl<'a, S> FileBuilder<'a, S>
887
+
where
888
+
S: file_state::State,
889
+
S::Type: file_state::IsUnset,
890
+
{
891
+
/// Set the `type` field (required)
892
+
pub fn r#type(
893
+
mut self,
894
+
value: impl Into<jacquard_common::CowStr<'a>>,
895
+
) -> FileBuilder<'a, file_state::SetType<S>> {
896
+
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
897
+
FileBuilder {
898
+
_phantom_state: ::core::marker::PhantomData,
899
+
__unsafe_private_named: self.__unsafe_private_named,
900
+
_phantom: ::core::marker::PhantomData,
901
+
}
902
+
}
903
+
}
904
+
905
+
impl<'a, S> FileBuilder<'a, S>
906
+
where
907
+
S: file_state::State,
908
+
S::Blob: file_state::IsSet,
909
+
S::Type: file_state::IsSet,
910
+
{
911
+
/// Build the final struct
912
+
pub fn build(self) -> File<'a> {
913
+
File {
914
+
base64: self.__unsafe_private_named.0,
915
+
blob: self.__unsafe_private_named.1.unwrap(),
916
+
encoding: self.__unsafe_private_named.2,
917
+
mime_type: self.__unsafe_private_named.3,
918
+
r#type: self.__unsafe_private_named.4.unwrap(),
919
+
extra_data: Default::default(),
920
+
}
921
+
}
922
+
/// Build the final struct with custom extra_data
923
+
pub fn build_with_data(
924
+
self,
925
+
extra_data: std::collections::BTreeMap<
926
+
jacquard_common::smol_str::SmolStr,
927
+
jacquard_common::types::value::Data<'a>,
928
+
>,
929
+
) -> File<'a> {
930
+
File {
931
+
base64: self.__unsafe_private_named.0,
932
+
blob: self.__unsafe_private_named.1.unwrap(),
933
+
encoding: self.__unsafe_private_named.2,
934
+
mime_type: self.__unsafe_private_named.3,
935
+
r#type: self.__unsafe_private_named.4.unwrap(),
936
+
extra_data: Some(extra_data),
937
+
}
938
+
}
939
+
}
940
+
941
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
942
+
fn nsid() -> &'static str {
943
+
"place.wisp.subfs"
944
+
}
945
+
fn def_name() -> &'static str {
946
+
"file"
947
+
}
948
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
949
+
lexicon_doc_place_wisp_subfs()
950
+
}
951
+
fn validate(
952
+
&self,
953
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
954
+
Ok(())
955
+
}
956
+
}
957
+
958
+
/// Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.
959
+
#[jacquard_derive::lexicon]
960
+
#[derive(
961
+
serde::Serialize,
962
+
serde::Deserialize,
963
+
Debug,
964
+
Clone,
965
+
PartialEq,
966
+
Eq,
967
+
jacquard_derive::IntoStatic
968
+
)]
969
+
#[serde(rename_all = "camelCase")]
970
+
pub struct SubfsRecord<'a> {
971
+
pub created_at: jacquard_common::types::string::Datetime,
972
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
973
+
pub file_count: std::option::Option<i64>,
974
+
#[serde(borrow)]
975
+
pub root: crate::place_wisp::subfs::Directory<'a>,
976
+
}
977
+
978
+
pub mod subfs_record_state {
979
+
980
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
981
+
#[allow(unused)]
982
+
use ::core::marker::PhantomData;
983
+
mod sealed {
984
+
pub trait Sealed {}
985
+
}
986
+
/// State trait tracking which required fields have been set
987
+
pub trait State: sealed::Sealed {
988
+
type Root;
989
+
type CreatedAt;
990
+
}
991
+
/// Empty state - all required fields are unset
992
+
pub struct Empty(());
993
+
impl sealed::Sealed for Empty {}
994
+
impl State for Empty {
995
+
type Root = Unset;
996
+
type CreatedAt = Unset;
997
+
}
998
+
///State transition - sets the `root` field to Set
999
+
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1000
+
impl<S: State> sealed::Sealed for SetRoot<S> {}
1001
+
impl<S: State> State for SetRoot<S> {
1002
+
type Root = Set<members::root>;
1003
+
type CreatedAt = S::CreatedAt;
1004
+
}
1005
+
///State transition - sets the `created_at` field to Set
1006
+
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1007
+
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1008
+
impl<S: State> State for SetCreatedAt<S> {
1009
+
type Root = S::Root;
1010
+
type CreatedAt = Set<members::created_at>;
1011
+
}
1012
+
/// Marker types for field names
1013
+
#[allow(non_camel_case_types)]
1014
+
pub mod members {
1015
+
///Marker type for the `root` field
1016
+
pub struct root(());
1017
+
///Marker type for the `created_at` field
1018
+
pub struct created_at(());
1019
+
}
1020
+
}
1021
+
1022
+
/// Builder for constructing an instance of this type
1023
+
pub struct SubfsRecordBuilder<'a, S: subfs_record_state::State> {
1024
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1025
+
__unsafe_private_named: (
1026
+
::core::option::Option<jacquard_common::types::string::Datetime>,
1027
+
::core::option::Option<i64>,
1028
+
::core::option::Option<crate::place_wisp::subfs::Directory<'a>>,
1029
+
),
1030
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1031
+
}
1032
+
1033
+
impl<'a> SubfsRecord<'a> {
1034
+
/// Create a new builder for this type
1035
+
pub fn new() -> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1036
+
SubfsRecordBuilder::new()
1037
+
}
1038
+
}
1039
+
1040
+
impl<'a> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1041
+
/// Create a new builder with all fields unset
1042
+
pub fn new() -> Self {
1043
+
SubfsRecordBuilder {
1044
+
_phantom_state: ::core::marker::PhantomData,
1045
+
__unsafe_private_named: (None, None, None),
1046
+
_phantom: ::core::marker::PhantomData,
1047
+
}
1048
+
}
1049
+
}
1050
+
1051
+
impl<'a, S> SubfsRecordBuilder<'a, S>
1052
+
where
1053
+
S: subfs_record_state::State,
1054
+
S::CreatedAt: subfs_record_state::IsUnset,
1055
+
{
1056
+
/// Set the `createdAt` field (required)
1057
+
pub fn created_at(
1058
+
mut self,
1059
+
value: impl Into<jacquard_common::types::string::Datetime>,
1060
+
) -> SubfsRecordBuilder<'a, subfs_record_state::SetCreatedAt<S>> {
1061
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1062
+
SubfsRecordBuilder {
1063
+
_phantom_state: ::core::marker::PhantomData,
1064
+
__unsafe_private_named: self.__unsafe_private_named,
1065
+
_phantom: ::core::marker::PhantomData,
1066
+
}
1067
+
}
1068
+
}
1069
+
1070
+
impl<'a, S: subfs_record_state::State> SubfsRecordBuilder<'a, S> {
1071
+
/// Set the `fileCount` field (optional)
1072
+
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1073
+
self.__unsafe_private_named.1 = value.into();
1074
+
self
1075
+
}
1076
+
/// Set the `fileCount` field to an Option value (optional)
1077
+
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1078
+
self.__unsafe_private_named.1 = value;
1079
+
self
1080
+
}
1081
+
}
1082
+
1083
+
impl<'a, S> SubfsRecordBuilder<'a, S>
1084
+
where
1085
+
S: subfs_record_state::State,
1086
+
S::Root: subfs_record_state::IsUnset,
1087
+
{
1088
+
/// Set the `root` field (required)
1089
+
pub fn root(
1090
+
mut self,
1091
+
value: impl Into<crate::place_wisp::subfs::Directory<'a>>,
1092
+
) -> SubfsRecordBuilder<'a, subfs_record_state::SetRoot<S>> {
1093
+
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1094
+
SubfsRecordBuilder {
1095
+
_phantom_state: ::core::marker::PhantomData,
1096
+
__unsafe_private_named: self.__unsafe_private_named,
1097
+
_phantom: ::core::marker::PhantomData,
1098
+
}
1099
+
}
1100
+
}
1101
+
1102
+
impl<'a, S> SubfsRecordBuilder<'a, S>
1103
+
where
1104
+
S: subfs_record_state::State,
1105
+
S::Root: subfs_record_state::IsSet,
1106
+
S::CreatedAt: subfs_record_state::IsSet,
1107
+
{
1108
+
/// Build the final struct
1109
+
pub fn build(self) -> SubfsRecord<'a> {
1110
+
SubfsRecord {
1111
+
created_at: self.__unsafe_private_named.0.unwrap(),
1112
+
file_count: self.__unsafe_private_named.1,
1113
+
root: self.__unsafe_private_named.2.unwrap(),
1114
+
extra_data: Default::default(),
1115
+
}
1116
+
}
1117
+
/// Build the final struct with custom extra_data
1118
+
pub fn build_with_data(
1119
+
self,
1120
+
extra_data: std::collections::BTreeMap<
1121
+
jacquard_common::smol_str::SmolStr,
1122
+
jacquard_common::types::value::Data<'a>,
1123
+
>,
1124
+
) -> SubfsRecord<'a> {
1125
+
SubfsRecord {
1126
+
created_at: self.__unsafe_private_named.0.unwrap(),
1127
+
file_count: self.__unsafe_private_named.1,
1128
+
root: self.__unsafe_private_named.2.unwrap(),
1129
+
extra_data: Some(extra_data),
1130
+
}
1131
+
}
1132
+
}
1133
+
1134
+
impl<'a> SubfsRecord<'a> {
1135
+
pub fn uri(
1136
+
uri: impl Into<jacquard_common::CowStr<'a>>,
1137
+
) -> Result<
1138
+
jacquard_common::types::uri::RecordUri<'a, SubfsRecordRecord>,
1139
+
jacquard_common::types::uri::UriError,
1140
+
> {
1141
+
jacquard_common::types::uri::RecordUri::try_from_uri(
1142
+
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1143
+
)
1144
+
}
1145
+
}
1146
+
1147
+
/// Typed wrapper for GetRecord response with this collection's record type.
1148
+
#[derive(
1149
+
serde::Serialize,
1150
+
serde::Deserialize,
1151
+
Debug,
1152
+
Clone,
1153
+
PartialEq,
1154
+
Eq,
1155
+
jacquard_derive::IntoStatic
1156
+
)]
1157
+
#[serde(rename_all = "camelCase")]
1158
+
pub struct SubfsRecordGetRecordOutput<'a> {
1159
+
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1160
+
#[serde(borrow)]
1161
+
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1162
+
#[serde(borrow)]
1163
+
pub uri: jacquard_common::types::string::AtUri<'a>,
1164
+
#[serde(borrow)]
1165
+
pub value: SubfsRecord<'a>,
1166
+
}
1167
+
1168
+
impl From<SubfsRecordGetRecordOutput<'_>> for SubfsRecord<'_> {
1169
+
fn from(output: SubfsRecordGetRecordOutput<'_>) -> Self {
1170
+
use jacquard_common::IntoStatic;
1171
+
output.value.into_static()
1172
+
}
1173
+
}
1174
+
1175
+
impl jacquard_common::types::collection::Collection for SubfsRecord<'_> {
1176
+
const NSID: &'static str = "place.wisp.subfs";
1177
+
type Record = SubfsRecordRecord;
1178
+
}
1179
+
1180
+
/// Marker type for deserializing records from this collection.
1181
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1182
+
pub struct SubfsRecordRecord;
1183
+
impl jacquard_common::xrpc::XrpcResp for SubfsRecordRecord {
1184
+
const NSID: &'static str = "place.wisp.subfs";
1185
+
const ENCODING: &'static str = "application/json";
1186
+
type Output<'de> = SubfsRecordGetRecordOutput<'de>;
1187
+
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1188
+
}
1189
+
1190
+
impl jacquard_common::types::collection::Collection for SubfsRecordRecord {
1191
+
const NSID: &'static str = "place.wisp.subfs";
1192
+
type Record = SubfsRecordRecord;
1193
+
}
1194
+
1195
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for SubfsRecord<'a> {
1196
+
fn nsid() -> &'static str {
1197
+
"place.wisp.subfs"
1198
+
}
1199
+
fn def_name() -> &'static str {
1200
+
"main"
1201
+
}
1202
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1203
+
lexicon_doc_place_wisp_subfs()
1204
+
}
1205
+
fn validate(
1206
+
&self,
1207
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1208
+
if let Some(ref value) = self.file_count {
1209
+
if *value > 1000i64 {
1210
+
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1211
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1212
+
"file_count",
1213
+
),
1214
+
max: 1000i64,
1215
+
actual: *value,
1216
+
});
1217
+
}
1218
+
}
1219
+
if let Some(ref value) = self.file_count {
1220
+
if *value < 0i64 {
1221
+
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1222
+
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1223
+
"file_count",
1224
+
),
1225
+
min: 0i64,
1226
+
actual: *value,
1227
+
});
1228
+
}
1229
+
}
1230
+
Ok(())
1231
+
}
1232
+
}
1233
+
1234
+
#[jacquard_derive::lexicon]
1235
+
#[derive(
1236
+
serde::Serialize,
1237
+
serde::Deserialize,
1238
+
Debug,
1239
+
Clone,
1240
+
PartialEq,
1241
+
Eq,
1242
+
jacquard_derive::IntoStatic
1243
+
)]
1244
+
#[serde(rename_all = "camelCase")]
1245
+
pub struct Subfs<'a> {
1246
+
/// AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.
1247
+
#[serde(borrow)]
1248
+
pub subject: jacquard_common::types::string::AtUri<'a>,
1249
+
#[serde(borrow)]
1250
+
pub r#type: jacquard_common::CowStr<'a>,
1251
+
}
1252
+
1253
+
pub mod subfs_state {
1254
+
1255
+
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1256
+
#[allow(unused)]
1257
+
use ::core::marker::PhantomData;
1258
+
mod sealed {
1259
+
pub trait Sealed {}
1260
+
}
1261
+
/// State trait tracking which required fields have been set
1262
+
pub trait State: sealed::Sealed {
1263
+
type Subject;
1264
+
type Type;
1265
+
}
1266
+
/// Empty state - all required fields are unset
1267
+
pub struct Empty(());
1268
+
impl sealed::Sealed for Empty {}
1269
+
impl State for Empty {
1270
+
type Subject = Unset;
1271
+
type Type = Unset;
1272
+
}
1273
+
///State transition - sets the `subject` field to Set
1274
+
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1275
+
impl<S: State> sealed::Sealed for SetSubject<S> {}
1276
+
impl<S: State> State for SetSubject<S> {
1277
+
type Subject = Set<members::subject>;
1278
+
type Type = S::Type;
1279
+
}
1280
+
///State transition - sets the `type` field to Set
1281
+
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1282
+
impl<S: State> sealed::Sealed for SetType<S> {}
1283
+
impl<S: State> State for SetType<S> {
1284
+
type Subject = S::Subject;
1285
+
type Type = Set<members::r#type>;
1286
+
}
1287
+
/// Marker types for field names
1288
+
#[allow(non_camel_case_types)]
1289
+
pub mod members {
1290
+
///Marker type for the `subject` field
1291
+
pub struct subject(());
1292
+
///Marker type for the `type` field
1293
+
pub struct r#type(());
1294
+
}
1295
+
}
1296
+
1297
+
/// Builder for constructing an instance of this type
1298
+
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1299
+
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1300
+
__unsafe_private_named: (
1301
+
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1302
+
::core::option::Option<jacquard_common::CowStr<'a>>,
1303
+
),
1304
+
_phantom: ::core::marker::PhantomData<&'a ()>,
1305
+
}
1306
+
1307
+
impl<'a> Subfs<'a> {
1308
+
/// Create a new builder for this type
1309
+
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1310
+
SubfsBuilder::new()
1311
+
}
1312
+
}
1313
+
1314
+
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1315
+
/// Create a new builder with all fields unset
1316
+
pub fn new() -> Self {
1317
+
SubfsBuilder {
1318
+
_phantom_state: ::core::marker::PhantomData,
1319
+
__unsafe_private_named: (None, None),
1320
+
_phantom: ::core::marker::PhantomData,
1321
+
}
1322
+
}
1323
+
}
1324
+
1325
+
impl<'a, S> SubfsBuilder<'a, S>
1326
+
where
1327
+
S: subfs_state::State,
1328
+
S::Subject: subfs_state::IsUnset,
1329
+
{
1330
+
/// Set the `subject` field (required)
1331
+
pub fn subject(
1332
+
mut self,
1333
+
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1334
+
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1335
+
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1336
+
SubfsBuilder {
1337
+
_phantom_state: ::core::marker::PhantomData,
1338
+
__unsafe_private_named: self.__unsafe_private_named,
1339
+
_phantom: ::core::marker::PhantomData,
1340
+
}
1341
+
}
1342
+
}
1343
+
1344
+
impl<'a, S> SubfsBuilder<'a, S>
1345
+
where
1346
+
S: subfs_state::State,
1347
+
S::Type: subfs_state::IsUnset,
1348
+
{
1349
+
/// Set the `type` field (required)
1350
+
pub fn r#type(
1351
+
mut self,
1352
+
value: impl Into<jacquard_common::CowStr<'a>>,
1353
+
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1354
+
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1355
+
SubfsBuilder {
1356
+
_phantom_state: ::core::marker::PhantomData,
1357
+
__unsafe_private_named: self.__unsafe_private_named,
1358
+
_phantom: ::core::marker::PhantomData,
1359
+
}
1360
+
}
1361
+
}
1362
+
1363
+
impl<'a, S> SubfsBuilder<'a, S>
1364
+
where
1365
+
S: subfs_state::State,
1366
+
S::Subject: subfs_state::IsSet,
1367
+
S::Type: subfs_state::IsSet,
1368
+
{
1369
+
/// Build the final struct
1370
+
pub fn build(self) -> Subfs<'a> {
1371
+
Subfs {
1372
+
subject: self.__unsafe_private_named.0.unwrap(),
1373
+
r#type: self.__unsafe_private_named.1.unwrap(),
1374
+
extra_data: Default::default(),
1375
+
}
1376
+
}
1377
+
/// Build the final struct with custom extra_data
1378
+
pub fn build_with_data(
1379
+
self,
1380
+
extra_data: std::collections::BTreeMap<
1381
+
jacquard_common::smol_str::SmolStr,
1382
+
jacquard_common::types::value::Data<'a>,
1383
+
>,
1384
+
) -> Subfs<'a> {
1385
+
Subfs {
1386
+
subject: self.__unsafe_private_named.0.unwrap(),
1387
+
r#type: self.__unsafe_private_named.1.unwrap(),
1388
+
extra_data: Some(extra_data),
1389
+
}
1390
+
}
1391
+
}
1392
+
1393
+
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1394
+
fn nsid() -> &'static str {
1395
+
"place.wisp.subfs"
1396
+
}
1397
+
fn def_name() -> &'static str {
1398
+
"subfs"
1399
+
}
1400
+
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1401
+
lexicon_doc_place_wisp_subfs()
1402
+
}
1403
+
fn validate(
1404
+
&self,
1405
+
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1406
+
Ok(())
1407
+
}
1408
+
}
+8
cli/crates/lexicons/src/place_wisp.rs
+8
cli/crates/lexicons/src/place_wisp.rs
+16
cli/default.nix
+16
cli/default.nix
···
1
+
{
2
+
rustPlatform,
3
+
glibc,
4
+
}:
5
+
rustPlatform.buildRustPackage {
6
+
name = "wisp-cli";
7
+
src = ./.;
8
+
cargoLock = {
9
+
lockFile = ./Cargo.lock;
10
+
outputHashes = {
11
+
"jacquard-0.9.5" = "sha256-75bas4VAYFcZAcBspSqS4vlJe8nmFn9ncTgeoT/OvnA=";
12
+
};
13
+
};
14
+
buildInputs = [glibc.static];
15
+
RUSTFLAGS = ["-C" "target-feature=+crt-static"];
16
+
}
+96
cli/flake.lock
+96
cli/flake.lock
···
1
+
{
2
+
"nodes": {
3
+
"flake-utils": {
4
+
"inputs": {
5
+
"systems": "systems"
6
+
},
7
+
"locked": {
8
+
"lastModified": 1731533236,
9
+
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
10
+
"owner": "numtide",
11
+
"repo": "flake-utils",
12
+
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
13
+
"type": "github"
14
+
},
15
+
"original": {
16
+
"owner": "numtide",
17
+
"repo": "flake-utils",
18
+
"type": "github"
19
+
}
20
+
},
21
+
"nixpkgs": {
22
+
"locked": {
23
+
"lastModified": 1767640445,
24
+
"narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=",
25
+
"owner": "NixOS",
26
+
"repo": "nixpkgs",
27
+
"rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5",
28
+
"type": "github"
29
+
},
30
+
"original": {
31
+
"owner": "NixOS",
32
+
"ref": "nixos-unstable",
33
+
"repo": "nixpkgs",
34
+
"type": "github"
35
+
}
36
+
},
37
+
"nixpkgs_2": {
38
+
"locked": {
39
+
"lastModified": 1744536153,
40
+
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
41
+
"owner": "NixOS",
42
+
"repo": "nixpkgs",
43
+
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
44
+
"type": "github"
45
+
},
46
+
"original": {
47
+
"owner": "NixOS",
48
+
"ref": "nixpkgs-unstable",
49
+
"repo": "nixpkgs",
50
+
"type": "github"
51
+
}
52
+
},
53
+
"root": {
54
+
"inputs": {
55
+
"flake-utils": "flake-utils",
56
+
"nixpkgs": "nixpkgs",
57
+
"rust-overlay": "rust-overlay"
58
+
}
59
+
},
60
+
"rust-overlay": {
61
+
"inputs": {
62
+
"nixpkgs": "nixpkgs_2"
63
+
},
64
+
"locked": {
65
+
"lastModified": 1767667566,
66
+
"narHash": "sha256-COy+yxZGuhQRVD1r4bWVgeFt1GB+IB1k5WRpDKbLfI8=",
67
+
"owner": "oxalica",
68
+
"repo": "rust-overlay",
69
+
"rev": "056ce5b125ab32ffe78c7d3e394d9da44733c95e",
70
+
"type": "github"
71
+
},
72
+
"original": {
73
+
"owner": "oxalica",
74
+
"repo": "rust-overlay",
75
+
"type": "github"
76
+
}
77
+
},
78
+
"systems": {
79
+
"locked": {
80
+
"lastModified": 1681028828,
81
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
82
+
"owner": "nix-systems",
83
+
"repo": "default",
84
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
85
+
"type": "github"
86
+
},
87
+
"original": {
88
+
"owner": "nix-systems",
89
+
"repo": "default",
90
+
"type": "github"
91
+
}
92
+
}
93
+
},
94
+
"root": "root",
95
+
"version": 7
96
+
}
+136
cli/flake.nix
+136
cli/flake.nix
···
1
+
{
2
+
inputs = {
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4
+
rust-overlay.url = "github:oxalica/rust-overlay";
5
+
flake-utils.url = "github:numtide/flake-utils";
6
+
};
7
+
8
+
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
9
+
flake-utils.lib.eachDefaultSystem (system:
10
+
let
11
+
overlays = [ (import rust-overlay) ];
12
+
pkgs = import nixpkgs { inherit system overlays; };
13
+
14
+
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
15
+
targets = [
16
+
"x86_64-unknown-linux-musl"
17
+
"aarch64-unknown-linux-musl"
18
+
"x86_64-apple-darwin"
19
+
"aarch64-apple-darwin"
20
+
];
21
+
};
22
+
23
+
cargoLockConfig = {
24
+
lockFile = ./Cargo.lock;
25
+
outputHashes = {
26
+
"jacquard-0.9.5" = "sha256-75bas4VAYFcZAcBspSqS4vlJe8nmFn9ncTgeoT/OvnA=";
27
+
};
28
+
};
29
+
30
+
# Native build for current system
31
+
native = pkgs.rustPlatform.buildRustPackage {
32
+
pname = "wisp-cli";
33
+
version = "0.4.2";
34
+
src = ./.;
35
+
cargoLock = cargoLockConfig;
36
+
nativeBuildInputs = [ rustToolchain ];
37
+
};
38
+
39
+
# Cross-compilation targets (Linux from macOS needs zigbuild)
40
+
linuxTargets = let
41
+
zigbuildPkgs = pkgs;
42
+
in {
43
+
x86_64-linux = pkgs.stdenv.mkDerivation {
44
+
pname = "wisp-cli-x86_64-linux";
45
+
version = "0.4.2";
46
+
src = ./.;
47
+
48
+
nativeBuildInputs = [
49
+
rustToolchain
50
+
pkgs.cargo-zigbuild
51
+
pkgs.zig
52
+
];
53
+
54
+
buildPhase = ''
55
+
export HOME=$(mktemp -d)
56
+
cargo zigbuild --release --target x86_64-unknown-linux-musl
57
+
'';
58
+
59
+
installPhase = ''
60
+
mkdir -p $out/bin
61
+
cp target/x86_64-unknown-linux-musl/release/wisp-cli $out/bin/
62
+
'';
63
+
64
+
# Skip Nix's cargo vendor - we use network
65
+
dontConfigure = true;
66
+
dontFixup = true;
67
+
};
68
+
69
+
aarch64-linux = pkgs.stdenv.mkDerivation {
70
+
pname = "wisp-cli-aarch64-linux";
71
+
version = "0.4.2";
72
+
src = ./.;
73
+
74
+
nativeBuildInputs = [
75
+
rustToolchain
76
+
pkgs.cargo-zigbuild
77
+
pkgs.zig
78
+
];
79
+
80
+
buildPhase = ''
81
+
export HOME=$(mktemp -d)
82
+
cargo zigbuild --release --target aarch64-unknown-linux-musl
83
+
'';
84
+
85
+
installPhase = ''
86
+
mkdir -p $out/bin
87
+
cp target/aarch64-unknown-linux-musl/release/wisp-cli $out/bin/
88
+
'';
89
+
90
+
dontConfigure = true;
91
+
dontFixup = true;
92
+
};
93
+
};
94
+
95
+
in {
96
+
packages = {
97
+
default = native;
98
+
inherit native;
99
+
100
+
# macOS universal binary
101
+
macos-universal = pkgs.stdenv.mkDerivation {
102
+
pname = "wisp-cli-macos-universal";
103
+
version = "0.4.2";
104
+
src = ./.;
105
+
106
+
nativeBuildInputs = [ rustToolchain pkgs.darwin.lipo ];
107
+
108
+
buildPhase = ''
109
+
export HOME=$(mktemp -d)
110
+
cargo build --release --target aarch64-apple-darwin
111
+
cargo build --release --target x86_64-apple-darwin
112
+
'';
113
+
114
+
installPhase = ''
115
+
mkdir -p $out/bin
116
+
lipo -create \
117
+
target/aarch64-apple-darwin/release/wisp-cli \
118
+
target/x86_64-apple-darwin/release/wisp-cli \
119
+
-output $out/bin/wisp-cli
120
+
'';
121
+
122
+
dontConfigure = true;
123
+
dontFixup = true;
124
+
};
125
+
} // (if pkgs.stdenv.isDarwin then linuxTargets else {});
126
+
127
+
devShells.default = pkgs.mkShell {
128
+
buildInputs = [
129
+
rustToolchain
130
+
pkgs.cargo-zigbuild
131
+
pkgs.zig
132
+
];
133
+
};
134
+
}
135
+
);
136
+
}
+1
-1
cli/src/blob_map.rs
+1
-1
cli/src/blob_map.rs
···
2
2
use jacquard_common::IntoStatic;
3
3
use std::collections::HashMap;
4
4
5
-
use crate::place_wisp::fs::{Directory, EntryNode};
5
+
use wisp_lexicons::place_wisp::fs::{Directory, EntryNode};
6
6
7
7
/// Extract blob information from a directory tree
8
8
/// Returns a map of file paths to their blob refs and CIDs
-43
cli/src/builder_types.rs
-43
cli/src/builder_types.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// This file was automatically generated from Lexicon schemas.
4
-
// Any manual changes will be overwritten on the next regeneration.
5
-
6
-
/// Marker type indicating a builder field has been set
7
-
pub struct Set<T>(pub T);
8
-
impl<T> Set<T> {
9
-
/// Extract the inner value
10
-
#[inline]
11
-
pub fn into_inner(self) -> T {
12
-
self.0
13
-
}
14
-
}
15
-
16
-
/// Marker type indicating a builder field has not been set
17
-
pub struct Unset;
18
-
/// Trait indicating a builder field is set (has a value)
19
-
#[rustversion::attr(
20
-
since(1.78.0),
21
-
diagnostic::on_unimplemented(
22
-
message = "the field `{Self}` was not set, but this method requires it to be set",
23
-
label = "the field `{Self}` was not set"
24
-
)
25
-
)]
26
-
pub trait IsSet: private::Sealed {}
27
-
/// Trait indicating a builder field is unset (no value yet)
28
-
#[rustversion::attr(
29
-
since(1.78.0),
30
-
diagnostic::on_unimplemented(
31
-
message = "the field `{Self}` was already set, but this method requires it to be unset",
32
-
label = "the field `{Self}` was already set"
33
-
)
34
-
)]
35
-
pub trait IsUnset: private::Sealed {}
36
-
impl<T> IsSet for Set<T> {}
37
-
impl IsUnset for Unset {}
38
-
mod private {
39
-
/// Sealed trait to prevent external implementations
40
-
pub trait Sealed {}
41
-
impl<T> Sealed for super::Set<T> {}
42
-
impl Sealed for super::Unset {}
43
-
}
-9
cli/src/lib.rs
-9
cli/src/lib.rs
+152
-40
cli/src/main.rs
+152
-40
cli/src/main.rs
···
1
-
mod builder_types;
2
-
mod place_wisp;
3
1
mod cid;
4
2
mod blob_map;
5
3
mod metadata;
···
28
26
use futures::stream::{self, StreamExt};
29
27
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
30
28
31
-
use place_wisp::fs::*;
32
-
use place_wisp::settings::*;
29
+
use wisp_lexicons::place_wisp::fs::*;
30
+
use wisp_lexicons::place_wisp::settings::*;
33
31
34
32
/// Maximum number of concurrent file uploads to the PDS
35
33
const MAX_CONCURRENT_UPLOADS: usize = 2;
36
34
35
+
/// Limits for caching on wisp.place (from @wisp/constants)
36
+
const MAX_FILE_COUNT: usize = 1000;
37
+
const MAX_SITE_SIZE: usize = 300 * 1024 * 1024; // 300MB
38
+
37
39
#[derive(Parser, Debug)]
38
40
#[command(author, version, about = "wisp.place CLI tool")]
39
41
struct Args {
40
42
#[command(subcommand)]
41
43
command: Option<Commands>,
42
-
44
+
43
45
// Deploy arguments (when no subcommand is specified)
44
46
/// Handle (e.g., alice.bsky.social), DID, or PDS URL
45
-
#[arg(global = true, conflicts_with = "command")]
46
47
input: Option<CowStr<'static>>,
47
48
48
49
/// Path to the directory containing your static site
49
-
#[arg(short, long, global = true, conflicts_with = "command")]
50
+
#[arg(short, long)]
50
51
path: Option<PathBuf>,
51
52
52
53
/// Site name (defaults to directory name)
53
-
#[arg(short, long, global = true, conflicts_with = "command")]
54
+
#[arg(short, long)]
54
55
site: Option<String>,
55
56
56
57
/// Path to auth store file
57
-
#[arg(long, global = true, conflicts_with = "command")]
58
+
#[arg(long)]
58
59
store: Option<String>,
59
60
60
61
/// App Password for authentication
61
-
#[arg(long, global = true, conflicts_with = "command")]
62
+
#[arg(long)]
62
63
password: Option<CowStr<'static>>,
63
64
64
65
/// Enable directory listing mode for paths without index files
65
-
#[arg(long, global = true, conflicts_with = "command")]
66
+
#[arg(long)]
66
67
directory: bool,
67
68
68
69
/// Enable SPA mode (serve index.html for all routes)
69
-
#[arg(long, global = true, conflicts_with = "command")]
70
+
#[arg(long)]
70
71
spa: bool,
72
+
73
+
/// Skip confirmation prompts (automatically accept warnings)
74
+
#[arg(short = 'y', long)]
75
+
yes: bool,
71
76
}
72
77
73
78
#[derive(Subcommand, Debug)]
···
100
105
/// Enable SPA mode (serve index.html for all routes)
101
106
#[arg(long)]
102
107
spa: bool,
108
+
109
+
/// Skip confirmation prompts (automatically accept warnings)
110
+
#[arg(short = 'y', long)]
111
+
yes: bool,
103
112
},
104
113
/// Pull a site from the PDS to a local directory
105
114
Pull {
···
112
121
113
122
/// Output directory for the downloaded site
114
123
#[arg(short, long, default_value = ".")]
115
-
output: PathBuf,
124
+
path: PathBuf,
116
125
},
117
126
/// Serve a site locally with real-time firehose updates
118
127
Serve {
···
125
134
126
135
/// Output directory for the site files
127
136
#[arg(short, long, default_value = ".")]
128
-
output: PathBuf,
137
+
path: PathBuf,
129
138
130
139
/// Port to serve on
131
-
#[arg(short, long, default_value = "8080")]
140
+
#[arg(short = 'P', long, default_value = "8080")]
132
141
port: u16,
133
142
},
134
143
}
···
138
147
let args = Args::parse();
139
148
140
149
let result = match args.command {
141
-
Some(Commands::Deploy { input, path, site, store, password, directory, spa }) => {
150
+
Some(Commands::Deploy { input, path, site, store, password, directory, spa, yes }) => {
142
151
// Dispatch to appropriate authentication method
143
152
if let Some(password) = password {
144
-
run_with_app_password(input, password, path, site, directory, spa).await
153
+
run_with_app_password(input, password, path, site, directory, spa, yes).await
145
154
} else {
146
-
run_with_oauth(input, store, path, site, directory, spa).await
155
+
run_with_oauth(input, store, path, site, directory, spa, yes).await
147
156
}
148
157
}
149
-
Some(Commands::Pull { input, site, output }) => {
150
-
pull::pull_site(input, CowStr::from(site), output).await
158
+
Some(Commands::Pull { input, site, path }) => {
159
+
pull::pull_site(input, CowStr::from(site), path).await
151
160
}
152
-
Some(Commands::Serve { input, site, output, port }) => {
153
-
serve::serve_site(input, CowStr::from(site), output, port).await
161
+
Some(Commands::Serve { input, site, path, port }) => {
162
+
serve::serve_site(input, CowStr::from(site), path, port).await
154
163
}
155
164
None => {
156
165
// Legacy mode: if input is provided, assume deploy command
···
160
169
161
170
// Dispatch to appropriate authentication method
162
171
if let Some(password) = args.password {
163
-
run_with_app_password(input, password, path, args.site, args.directory, args.spa).await
172
+
run_with_app_password(input, password, path, args.site, args.directory, args.spa, args.yes).await
164
173
} else {
165
-
run_with_oauth(input, store, path, args.site, args.directory, args.spa).await
174
+
run_with_oauth(input, store, path, args.site, args.directory, args.spa, args.yes).await
166
175
}
167
176
} else {
168
177
// No command and no input, show help
···
191
200
site: Option<String>,
192
201
directory: bool,
193
202
spa: bool,
203
+
yes: bool,
194
204
) -> miette::Result<()> {
195
205
let (session, auth) =
196
206
MemoryCredentialSession::authenticated(input, password, None, None).await?;
197
207
println!("Signed in as {}", auth.handle);
198
208
199
209
let agent: Agent<_> = Agent::from(session);
200
-
deploy_site(&agent, path, site, directory, spa).await
210
+
deploy_site(&agent, path, site, directory, spa, yes).await
201
211
}
202
212
203
213
/// Run deployment with OAuth authentication
···
208
218
site: Option<String>,
209
219
directory: bool,
210
220
spa: bool,
221
+
yes: bool,
211
222
) -> miette::Result<()> {
212
223
use jacquard::oauth::scopes::Scope;
213
224
use jacquard::oauth::atproto::AtprotoClientMetadata;
···
240
251
.await?;
241
252
242
253
let agent: Agent<_> = Agent::from(session);
243
-
deploy_site(&agent, path, site, directory, spa).await
254
+
deploy_site(&agent, path, site, directory, spa, yes).await
255
+
}
256
+
257
+
/// Scan directory to count files and calculate total size
258
+
/// Returns (file_count, total_size_bytes)
259
+
fn scan_directory_stats(
260
+
dir_path: &Path,
261
+
ignore_matcher: &ignore_patterns::IgnoreMatcher,
262
+
current_path: String,
263
+
) -> miette::Result<(usize, u64)> {
264
+
let mut file_count = 0;
265
+
let mut total_size = 0u64;
266
+
267
+
let dir_entries: Vec<_> = std::fs::read_dir(dir_path)
268
+
.into_diagnostic()?
269
+
.collect::<Result<Vec<_>, _>>()
270
+
.into_diagnostic()?;
271
+
272
+
for entry in dir_entries {
273
+
let path = entry.path();
274
+
let name = entry.file_name();
275
+
let name_str = name.to_str()
276
+
.ok_or_else(|| miette::miette!("Invalid filename: {:?}", name))?
277
+
.to_string();
278
+
279
+
let full_path = if current_path.is_empty() {
280
+
name_str.clone()
281
+
} else {
282
+
format!("{}/{}", current_path, name_str)
283
+
};
284
+
285
+
// Skip files/directories that match ignore patterns
286
+
if ignore_matcher.is_ignored(&full_path) || ignore_matcher.is_filename_ignored(&name_str) {
287
+
continue;
288
+
}
289
+
290
+
let metadata = entry.metadata().into_diagnostic()?;
291
+
292
+
if metadata.is_file() {
293
+
file_count += 1;
294
+
total_size += metadata.len();
295
+
} else if metadata.is_dir() {
296
+
let subdir_path = if current_path.is_empty() {
297
+
name_str
298
+
} else {
299
+
format!("{}/{}", current_path, name_str)
300
+
};
301
+
let (sub_count, sub_size) = scan_directory_stats(&path, ignore_matcher, subdir_path)?;
302
+
file_count += sub_count;
303
+
total_size += sub_size;
304
+
}
305
+
}
306
+
307
+
Ok((file_count, total_size))
244
308
}
245
309
246
310
/// Deploy the site using the provided agent
···
250
314
site: Option<String>,
251
315
directory_listing: bool,
252
316
spa_mode: bool,
317
+
skip_prompts: bool,
253
318
) -> miette::Result<()> {
254
319
// Verify the path exists
255
320
if !path.exists() {
···
267
332
268
333
println!("Deploying site '{}'...", site_name);
269
334
335
+
// Scan directory to check file count and size
336
+
let ignore_matcher = ignore_patterns::IgnoreMatcher::new(&path)?;
337
+
let (file_count, total_size) = scan_directory_stats(&path, &ignore_matcher, String::new())?;
338
+
339
+
let size_mb = total_size as f64 / (1024.0 * 1024.0);
340
+
println!("Scanned: {} files, {:.1} MB total", file_count, size_mb);
341
+
342
+
// Check if limits are exceeded
343
+
let exceeds_file_count = file_count > MAX_FILE_COUNT;
344
+
let exceeds_size = total_size > MAX_SITE_SIZE as u64;
345
+
346
+
if exceeds_file_count || exceeds_size {
347
+
println!("\nโ ๏ธ Warning: Your site exceeds wisp.place caching limits:");
348
+
349
+
if exceeds_file_count {
350
+
println!(" โข File count: {} (limit: {})", file_count, MAX_FILE_COUNT);
351
+
}
352
+
353
+
if exceeds_size {
354
+
let size_mb = total_size as f64 / (1024.0 * 1024.0);
355
+
let limit_mb = MAX_SITE_SIZE as f64 / (1024.0 * 1024.0);
356
+
println!(" โข Total size: {:.1} MB (limit: {:.0} MB)", size_mb, limit_mb);
357
+
}
358
+
359
+
println!("\nwisp.place will NOT serve your site if you proceed.");
360
+
println!("Your site will be uploaded to your PDS, but will only be accessible via:");
361
+
println!(" โข wisp-cli serve (local hosting)");
362
+
println!(" โข Other hosting services with more generous limits");
363
+
364
+
if !skip_prompts {
365
+
// Prompt for confirmation
366
+
use std::io::{self, Write};
367
+
print!("\nDo you want to upload anyway? (y/N): ");
368
+
io::stdout().flush().into_diagnostic()?;
369
+
370
+
let mut input = String::new();
371
+
io::stdin().read_line(&mut input).into_diagnostic()?;
372
+
let input = input.trim().to_lowercase();
373
+
374
+
if input != "y" && input != "yes" {
375
+
println!("Upload cancelled.");
376
+
return Ok(());
377
+
}
378
+
} else {
379
+
println!("\nSkipping confirmation (--yes flag set).");
380
+
}
381
+
382
+
println!("\nProceeding with upload...\n");
383
+
}
384
+
270
385
// Try to fetch existing manifest for incremental updates
271
386
let (existing_blob_map, old_subfs_uris): (HashMap<String, (jacquard_common::types::blob::BlobRef<'static>, String)>, Vec<(String, String)>) = {
272
387
use jacquard_common::types::string::AtUri;
···
328
443
}
329
444
};
330
445
331
-
// Build directory tree with ignore patterns
332
-
let ignore_matcher = ignore_patterns::IgnoreMatcher::new(&path)?;
333
-
334
446
// Create progress tracking (spinner style since we don't know total count upfront)
335
447
let multi_progress = MultiProgress::new();
336
448
let progress = multi_progress.add(ProgressBar::new_spinner());
···
397
509
let chunk_file_count = subfs_utils::count_files_in_directory(chunk);
398
510
let chunk_size = subfs_utils::estimate_directory_size(chunk);
399
511
400
-
let chunk_manifest = crate::place_wisp::subfs::SubfsRecord::new()
512
+
let chunk_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new()
401
513
.root(convert_fs_dir_to_subfs_dir(chunk.clone()))
402
514
.file_count(Some(chunk_file_count as i64))
403
515
.created_at(Datetime::now())
···
420
532
// Each chunk reference MUST have flat: true to merge chunk contents
421
533
println!(" โ Creating parent subfs with {} chunk references...", chunk_uris.len());
422
534
use jacquard_common::CowStr;
423
-
use crate::place_wisp::fs::{Subfs};
535
+
use wisp_lexicons::place_wisp::fs::{Subfs};
424
536
425
537
// Convert to fs::Subfs (which has the 'flat' field) instead of subfs::Subfs
426
538
let parent_entries_fs: Vec<Entry> = chunk_uris.iter().enumerate().map(|(i, (uri, _))| {
···
450
562
let parent_tid = Tid::now_0();
451
563
let parent_rkey = parent_tid.to_string();
452
564
453
-
let parent_manifest = crate::place_wisp::subfs::SubfsRecord::new()
565
+
let parent_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new()
454
566
.root(parent_root_subfs)
455
567
.file_count(Some(largest_dir.file_count as i64))
456
568
.created_at(Datetime::now())
···
469
581
let subfs_tid = Tid::now_0();
470
582
let subfs_rkey = subfs_tid.to_string();
471
583
472
-
let subfs_manifest = crate::place_wisp::subfs::SubfsRecord::new()
584
+
let subfs_manifest = wisp_lexicons::place_wisp::subfs::SubfsRecord::new()
473
585
.root(convert_fs_dir_to_subfs_dir(largest_dir.directory.clone()))
474
586
.file_count(Some(largest_dir.file_count as i64))
475
587
.created_at(Datetime::now())
···
837
949
838
950
/// Convert fs::Directory to subfs::Directory
839
951
/// They have the same structure, but different types
840
-
fn convert_fs_dir_to_subfs_dir(fs_dir: place_wisp::fs::Directory<'static>) -> place_wisp::subfs::Directory<'static> {
841
-
use place_wisp::subfs::{Directory as SubfsDirectory, Entry as SubfsEntry, EntryNode as SubfsEntryNode, File as SubfsFile};
952
+
fn convert_fs_dir_to_subfs_dir(fs_dir: wisp_lexicons::place_wisp::fs::Directory<'static>) -> wisp_lexicons::place_wisp::subfs::Directory<'static> {
953
+
use wisp_lexicons::place_wisp::subfs::{Directory as SubfsDirectory, Entry as SubfsEntry, EntryNode as SubfsEntryNode, File as SubfsFile};
842
954
843
955
let subfs_entries: Vec<SubfsEntry> = fs_dir.entries.into_iter().map(|entry| {
844
956
let node = match entry.node {
845
-
place_wisp::fs::EntryNode::File(file) => {
957
+
wisp_lexicons::place_wisp::fs::EntryNode::File(file) => {
846
958
SubfsEntryNode::File(Box::new(SubfsFile::new()
847
959
.r#type(file.r#type)
848
960
.blob(file.blob)
···
851
963
.base64(file.base64)
852
964
.build()))
853
965
}
854
-
place_wisp::fs::EntryNode::Directory(dir) => {
966
+
wisp_lexicons::place_wisp::fs::EntryNode::Directory(dir) => {
855
967
SubfsEntryNode::Directory(Box::new(convert_fs_dir_to_subfs_dir(*dir)))
856
968
}
857
-
place_wisp::fs::EntryNode::Subfs(subfs) => {
969
+
wisp_lexicons::place_wisp::fs::EntryNode::Subfs(subfs) => {
858
970
// Nested subfs in the directory we're converting
859
971
// Note: subfs::Subfs doesn't have the 'flat' field - that's only in fs::Subfs
860
-
SubfsEntryNode::Subfs(Box::new(place_wisp::subfs::Subfs::new()
972
+
SubfsEntryNode::Subfs(Box::new(wisp_lexicons::place_wisp::subfs::Subfs::new()
861
973
.r#type(subfs.r#type)
862
974
.subject(subfs.subject)
863
975
.build()))
864
976
}
865
-
place_wisp::fs::EntryNode::Unknown(unknown) => {
977
+
wisp_lexicons::place_wisp::fs::EntryNode::Unknown(unknown) => {
866
978
SubfsEntryNode::Unknown(unknown)
867
979
}
868
980
};
-9
cli/src/mod.rs
-9
cli/src/mod.rs
-1490
cli/src/place_wisp/fs.rs
-1490
cli/src/place_wisp/fs.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// Lexicon: place.wisp.fs
4
-
//
5
-
// This file was automatically generated from Lexicon schemas.
6
-
// Any manual changes will be overwritten on the next regeneration.
7
-
8
-
#[jacquard_derive::lexicon]
9
-
#[derive(
10
-
serde::Serialize,
11
-
serde::Deserialize,
12
-
Debug,
13
-
Clone,
14
-
PartialEq,
15
-
Eq,
16
-
jacquard_derive::IntoStatic
17
-
)]
18
-
#[serde(rename_all = "camelCase")]
19
-
pub struct Directory<'a> {
20
-
#[serde(borrow)]
21
-
pub entries: Vec<crate::place_wisp::fs::Entry<'a>>,
22
-
#[serde(borrow)]
23
-
pub r#type: jacquard_common::CowStr<'a>,
24
-
}
25
-
26
-
pub mod directory_state {
27
-
28
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
-
#[allow(unused)]
30
-
use ::core::marker::PhantomData;
31
-
mod sealed {
32
-
pub trait Sealed {}
33
-
}
34
-
/// State trait tracking which required fields have been set
35
-
pub trait State: sealed::Sealed {
36
-
type Type;
37
-
type Entries;
38
-
}
39
-
/// Empty state - all required fields are unset
40
-
pub struct Empty(());
41
-
impl sealed::Sealed for Empty {}
42
-
impl State for Empty {
43
-
type Type = Unset;
44
-
type Entries = Unset;
45
-
}
46
-
///State transition - sets the `type` field to Set
47
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
-
impl<S: State> sealed::Sealed for SetType<S> {}
49
-
impl<S: State> State for SetType<S> {
50
-
type Type = Set<members::r#type>;
51
-
type Entries = S::Entries;
52
-
}
53
-
///State transition - sets the `entries` field to Set
54
-
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
-
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
-
impl<S: State> State for SetEntries<S> {
57
-
type Type = S::Type;
58
-
type Entries = Set<members::entries>;
59
-
}
60
-
/// Marker types for field names
61
-
#[allow(non_camel_case_types)]
62
-
pub mod members {
63
-
///Marker type for the `type` field
64
-
pub struct r#type(());
65
-
///Marker type for the `entries` field
66
-
pub struct entries(());
67
-
}
68
-
}
69
-
70
-
/// Builder for constructing an instance of this type
71
-
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
-
__unsafe_private_named: (
74
-
::core::option::Option<Vec<crate::place_wisp::fs::Entry<'a>>>,
75
-
::core::option::Option<jacquard_common::CowStr<'a>>,
76
-
),
77
-
_phantom: ::core::marker::PhantomData<&'a ()>,
78
-
}
79
-
80
-
impl<'a> Directory<'a> {
81
-
/// Create a new builder for this type
82
-
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
-
DirectoryBuilder::new()
84
-
}
85
-
}
86
-
87
-
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
-
/// Create a new builder with all fields unset
89
-
pub fn new() -> Self {
90
-
DirectoryBuilder {
91
-
_phantom_state: ::core::marker::PhantomData,
92
-
__unsafe_private_named: (None, None),
93
-
_phantom: ::core::marker::PhantomData,
94
-
}
95
-
}
96
-
}
97
-
98
-
impl<'a, S> DirectoryBuilder<'a, S>
99
-
where
100
-
S: directory_state::State,
101
-
S::Entries: directory_state::IsUnset,
102
-
{
103
-
/// Set the `entries` field (required)
104
-
pub fn entries(
105
-
mut self,
106
-
value: impl Into<Vec<crate::place_wisp::fs::Entry<'a>>>,
107
-
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
-
DirectoryBuilder {
110
-
_phantom_state: ::core::marker::PhantomData,
111
-
__unsafe_private_named: self.__unsafe_private_named,
112
-
_phantom: ::core::marker::PhantomData,
113
-
}
114
-
}
115
-
}
116
-
117
-
impl<'a, S> DirectoryBuilder<'a, S>
118
-
where
119
-
S: directory_state::State,
120
-
S::Type: directory_state::IsUnset,
121
-
{
122
-
/// Set the `type` field (required)
123
-
pub fn r#type(
124
-
mut self,
125
-
value: impl Into<jacquard_common::CowStr<'a>>,
126
-
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
-
DirectoryBuilder {
129
-
_phantom_state: ::core::marker::PhantomData,
130
-
__unsafe_private_named: self.__unsafe_private_named,
131
-
_phantom: ::core::marker::PhantomData,
132
-
}
133
-
}
134
-
}
135
-
136
-
impl<'a, S> DirectoryBuilder<'a, S>
137
-
where
138
-
S: directory_state::State,
139
-
S::Type: directory_state::IsSet,
140
-
S::Entries: directory_state::IsSet,
141
-
{
142
-
/// Build the final struct
143
-
pub fn build(self) -> Directory<'a> {
144
-
Directory {
145
-
entries: self.__unsafe_private_named.0.unwrap(),
146
-
r#type: self.__unsafe_private_named.1.unwrap(),
147
-
extra_data: Default::default(),
148
-
}
149
-
}
150
-
/// Build the final struct with custom extra_data
151
-
pub fn build_with_data(
152
-
self,
153
-
extra_data: std::collections::BTreeMap<
154
-
jacquard_common::smol_str::SmolStr,
155
-
jacquard_common::types::value::Data<'a>,
156
-
>,
157
-
) -> Directory<'a> {
158
-
Directory {
159
-
entries: self.__unsafe_private_named.0.unwrap(),
160
-
r#type: self.__unsafe_private_named.1.unwrap(),
161
-
extra_data: Some(extra_data),
162
-
}
163
-
}
164
-
}
165
-
166
-
fn lexicon_doc_place_wisp_fs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
-
::jacquard_lexicon::lexicon::LexiconDoc {
168
-
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
-
id: ::jacquard_common::CowStr::new_static("place.wisp.fs"),
170
-
revision: None,
171
-
description: None,
172
-
defs: {
173
-
let mut map = ::std::collections::BTreeMap::new();
174
-
map.insert(
175
-
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
-
description: None,
178
-
required: Some(
179
-
vec![
180
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
-
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
-
],
183
-
),
184
-
nullable: None,
185
-
properties: {
186
-
#[allow(unused_mut)]
187
-
let mut map = ::std::collections::BTreeMap::new();
188
-
map.insert(
189
-
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
-
description: None,
192
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
-
description: None,
194
-
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
-
}),
196
-
min_length: None,
197
-
max_length: Some(500usize),
198
-
}),
199
-
);
200
-
map.insert(
201
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
-
description: None,
204
-
format: None,
205
-
default: None,
206
-
min_length: None,
207
-
max_length: None,
208
-
min_graphemes: None,
209
-
max_graphemes: None,
210
-
r#enum: None,
211
-
r#const: None,
212
-
known_values: None,
213
-
}),
214
-
);
215
-
map
216
-
},
217
-
}),
218
-
);
219
-
map.insert(
220
-
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
-
description: None,
223
-
required: Some(
224
-
vec![
225
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
-
::jacquard_common::smol_str::SmolStr::new_static("node")
227
-
],
228
-
),
229
-
nullable: None,
230
-
properties: {
231
-
#[allow(unused_mut)]
232
-
let mut map = ::std::collections::BTreeMap::new();
233
-
map.insert(
234
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
-
description: None,
237
-
format: None,
238
-
default: None,
239
-
min_length: None,
240
-
max_length: Some(255usize),
241
-
min_graphemes: None,
242
-
max_graphemes: None,
243
-
r#enum: None,
244
-
r#const: None,
245
-
known_values: None,
246
-
}),
247
-
);
248
-
map.insert(
249
-
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
-
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
-
description: None,
252
-
refs: vec![
253
-
::jacquard_common::CowStr::new_static("#file"),
254
-
::jacquard_common::CowStr::new_static("#directory"),
255
-
::jacquard_common::CowStr::new_static("#subfs")
256
-
],
257
-
closed: None,
258
-
}),
259
-
);
260
-
map
261
-
},
262
-
}),
263
-
);
264
-
map.insert(
265
-
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
-
description: None,
268
-
required: Some(
269
-
vec![
270
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
-
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
-
],
273
-
),
274
-
nullable: None,
275
-
properties: {
276
-
#[allow(unused_mut)]
277
-
let mut map = ::std::collections::BTreeMap::new();
278
-
map.insert(
279
-
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
-
description: None,
282
-
default: None,
283
-
r#const: None,
284
-
}),
285
-
);
286
-
map.insert(
287
-
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
-
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
-
description: None,
290
-
accept: None,
291
-
max_size: None,
292
-
}),
293
-
);
294
-
map.insert(
295
-
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
-
description: Some(
298
-
::jacquard_common::CowStr::new_static(
299
-
"Content encoding (e.g., gzip for compressed files)",
300
-
),
301
-
),
302
-
format: None,
303
-
default: None,
304
-
min_length: None,
305
-
max_length: None,
306
-
min_graphemes: None,
307
-
max_graphemes: None,
308
-
r#enum: None,
309
-
r#const: None,
310
-
known_values: None,
311
-
}),
312
-
);
313
-
map.insert(
314
-
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
-
description: Some(
317
-
::jacquard_common::CowStr::new_static(
318
-
"Original MIME type before compression",
319
-
),
320
-
),
321
-
format: None,
322
-
default: None,
323
-
min_length: None,
324
-
max_length: None,
325
-
min_graphemes: None,
326
-
max_graphemes: None,
327
-
r#enum: None,
328
-
r#const: None,
329
-
known_values: None,
330
-
}),
331
-
);
332
-
map.insert(
333
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
-
description: None,
336
-
format: None,
337
-
default: None,
338
-
min_length: None,
339
-
max_length: None,
340
-
min_graphemes: None,
341
-
max_graphemes: None,
342
-
r#enum: None,
343
-
r#const: None,
344
-
known_values: None,
345
-
}),
346
-
);
347
-
map
348
-
},
349
-
}),
350
-
);
351
-
map.insert(
352
-
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
-
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
-
description: Some(
355
-
::jacquard_common::CowStr::new_static(
356
-
"Virtual filesystem manifest for a Wisp site",
357
-
),
358
-
),
359
-
key: None,
360
-
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
-
description: None,
362
-
required: Some(
363
-
vec![
364
-
::jacquard_common::smol_str::SmolStr::new_static("site"),
365
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
366
-
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
367
-
],
368
-
),
369
-
nullable: None,
370
-
properties: {
371
-
#[allow(unused_mut)]
372
-
let mut map = ::std::collections::BTreeMap::new();
373
-
map.insert(
374
-
::jacquard_common::smol_str::SmolStr::new_static(
375
-
"createdAt",
376
-
),
377
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
378
-
description: None,
379
-
format: Some(
380
-
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
381
-
),
382
-
default: None,
383
-
min_length: None,
384
-
max_length: None,
385
-
min_graphemes: None,
386
-
max_graphemes: None,
387
-
r#enum: None,
388
-
r#const: None,
389
-
known_values: None,
390
-
}),
391
-
);
392
-
map.insert(
393
-
::jacquard_common::smol_str::SmolStr::new_static(
394
-
"fileCount",
395
-
),
396
-
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
397
-
description: None,
398
-
default: None,
399
-
minimum: Some(0i64),
400
-
maximum: Some(1000i64),
401
-
r#enum: None,
402
-
r#const: None,
403
-
}),
404
-
);
405
-
map.insert(
406
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
407
-
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
408
-
description: None,
409
-
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
410
-
}),
411
-
);
412
-
map.insert(
413
-
::jacquard_common::smol_str::SmolStr::new_static("site"),
414
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
415
-
description: None,
416
-
format: None,
417
-
default: None,
418
-
min_length: None,
419
-
max_length: None,
420
-
min_graphemes: None,
421
-
max_graphemes: None,
422
-
r#enum: None,
423
-
r#const: None,
424
-
known_values: None,
425
-
}),
426
-
);
427
-
map
428
-
},
429
-
}),
430
-
}),
431
-
);
432
-
map.insert(
433
-
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
434
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
435
-
description: None,
436
-
required: Some(
437
-
vec![
438
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
439
-
::jacquard_common::smol_str::SmolStr::new_static("subject")
440
-
],
441
-
),
442
-
nullable: None,
443
-
properties: {
444
-
#[allow(unused_mut)]
445
-
let mut map = ::std::collections::BTreeMap::new();
446
-
map.insert(
447
-
::jacquard_common::smol_str::SmolStr::new_static("flat"),
448
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
449
-
description: None,
450
-
default: None,
451
-
r#const: None,
452
-
}),
453
-
);
454
-
map.insert(
455
-
::jacquard_common::smol_str::SmolStr::new_static("subject"),
456
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
457
-
description: Some(
458
-
::jacquard_common::CowStr::new_static(
459
-
"AT-URI pointing to a place.wisp.subfs record containing this subtree.",
460
-
),
461
-
),
462
-
format: Some(
463
-
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
464
-
),
465
-
default: None,
466
-
min_length: None,
467
-
max_length: None,
468
-
min_graphemes: None,
469
-
max_graphemes: None,
470
-
r#enum: None,
471
-
r#const: None,
472
-
known_values: None,
473
-
}),
474
-
);
475
-
map.insert(
476
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
477
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
478
-
description: None,
479
-
format: None,
480
-
default: None,
481
-
min_length: None,
482
-
max_length: None,
483
-
min_graphemes: None,
484
-
max_graphemes: None,
485
-
r#enum: None,
486
-
r#const: None,
487
-
known_values: None,
488
-
}),
489
-
);
490
-
map
491
-
},
492
-
}),
493
-
);
494
-
map
495
-
},
496
-
}
497
-
}
498
-
499
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
500
-
fn nsid() -> &'static str {
501
-
"place.wisp.fs"
502
-
}
503
-
fn def_name() -> &'static str {
504
-
"directory"
505
-
}
506
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
507
-
lexicon_doc_place_wisp_fs()
508
-
}
509
-
fn validate(
510
-
&self,
511
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
512
-
{
513
-
let value = &self.entries;
514
-
#[allow(unused_comparisons)]
515
-
if value.len() > 500usize {
516
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
517
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
518
-
"entries",
519
-
),
520
-
max: 500usize,
521
-
actual: value.len(),
522
-
});
523
-
}
524
-
}
525
-
Ok(())
526
-
}
527
-
}
528
-
529
-
#[jacquard_derive::lexicon]
530
-
#[derive(
531
-
serde::Serialize,
532
-
serde::Deserialize,
533
-
Debug,
534
-
Clone,
535
-
PartialEq,
536
-
Eq,
537
-
jacquard_derive::IntoStatic
538
-
)]
539
-
#[serde(rename_all = "camelCase")]
540
-
pub struct Entry<'a> {
541
-
#[serde(borrow)]
542
-
pub name: jacquard_common::CowStr<'a>,
543
-
#[serde(borrow)]
544
-
pub node: EntryNode<'a>,
545
-
}
546
-
547
-
pub mod entry_state {
548
-
549
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
550
-
#[allow(unused)]
551
-
use ::core::marker::PhantomData;
552
-
mod sealed {
553
-
pub trait Sealed {}
554
-
}
555
-
/// State trait tracking which required fields have been set
556
-
pub trait State: sealed::Sealed {
557
-
type Name;
558
-
type Node;
559
-
}
560
-
/// Empty state - all required fields are unset
561
-
pub struct Empty(());
562
-
impl sealed::Sealed for Empty {}
563
-
impl State for Empty {
564
-
type Name = Unset;
565
-
type Node = Unset;
566
-
}
567
-
///State transition - sets the `name` field to Set
568
-
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
569
-
impl<S: State> sealed::Sealed for SetName<S> {}
570
-
impl<S: State> State for SetName<S> {
571
-
type Name = Set<members::name>;
572
-
type Node = S::Node;
573
-
}
574
-
///State transition - sets the `node` field to Set
575
-
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
576
-
impl<S: State> sealed::Sealed for SetNode<S> {}
577
-
impl<S: State> State for SetNode<S> {
578
-
type Name = S::Name;
579
-
type Node = Set<members::node>;
580
-
}
581
-
/// Marker types for field names
582
-
#[allow(non_camel_case_types)]
583
-
pub mod members {
584
-
///Marker type for the `name` field
585
-
pub struct name(());
586
-
///Marker type for the `node` field
587
-
pub struct node(());
588
-
}
589
-
}
590
-
591
-
/// Builder for constructing an instance of this type
592
-
pub struct EntryBuilder<'a, S: entry_state::State> {
593
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
594
-
__unsafe_private_named: (
595
-
::core::option::Option<jacquard_common::CowStr<'a>>,
596
-
::core::option::Option<EntryNode<'a>>,
597
-
),
598
-
_phantom: ::core::marker::PhantomData<&'a ()>,
599
-
}
600
-
601
-
impl<'a> Entry<'a> {
602
-
/// Create a new builder for this type
603
-
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
604
-
EntryBuilder::new()
605
-
}
606
-
}
607
-
608
-
impl<'a> EntryBuilder<'a, entry_state::Empty> {
609
-
/// Create a new builder with all fields unset
610
-
pub fn new() -> Self {
611
-
EntryBuilder {
612
-
_phantom_state: ::core::marker::PhantomData,
613
-
__unsafe_private_named: (None, None),
614
-
_phantom: ::core::marker::PhantomData,
615
-
}
616
-
}
617
-
}
618
-
619
-
impl<'a, S> EntryBuilder<'a, S>
620
-
where
621
-
S: entry_state::State,
622
-
S::Name: entry_state::IsUnset,
623
-
{
624
-
/// Set the `name` field (required)
625
-
pub fn name(
626
-
mut self,
627
-
value: impl Into<jacquard_common::CowStr<'a>>,
628
-
) -> EntryBuilder<'a, entry_state::SetName<S>> {
629
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
630
-
EntryBuilder {
631
-
_phantom_state: ::core::marker::PhantomData,
632
-
__unsafe_private_named: self.__unsafe_private_named,
633
-
_phantom: ::core::marker::PhantomData,
634
-
}
635
-
}
636
-
}
637
-
638
-
impl<'a, S> EntryBuilder<'a, S>
639
-
where
640
-
S: entry_state::State,
641
-
S::Node: entry_state::IsUnset,
642
-
{
643
-
/// Set the `node` field (required)
644
-
pub fn node(
645
-
mut self,
646
-
value: impl Into<EntryNode<'a>>,
647
-
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
648
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
649
-
EntryBuilder {
650
-
_phantom_state: ::core::marker::PhantomData,
651
-
__unsafe_private_named: self.__unsafe_private_named,
652
-
_phantom: ::core::marker::PhantomData,
653
-
}
654
-
}
655
-
}
656
-
657
-
impl<'a, S> EntryBuilder<'a, S>
658
-
where
659
-
S: entry_state::State,
660
-
S::Name: entry_state::IsSet,
661
-
S::Node: entry_state::IsSet,
662
-
{
663
-
/// Build the final struct
664
-
pub fn build(self) -> Entry<'a> {
665
-
Entry {
666
-
name: self.__unsafe_private_named.0.unwrap(),
667
-
node: self.__unsafe_private_named.1.unwrap(),
668
-
extra_data: Default::default(),
669
-
}
670
-
}
671
-
/// Build the final struct with custom extra_data
672
-
pub fn build_with_data(
673
-
self,
674
-
extra_data: std::collections::BTreeMap<
675
-
jacquard_common::smol_str::SmolStr,
676
-
jacquard_common::types::value::Data<'a>,
677
-
>,
678
-
) -> Entry<'a> {
679
-
Entry {
680
-
name: self.__unsafe_private_named.0.unwrap(),
681
-
node: self.__unsafe_private_named.1.unwrap(),
682
-
extra_data: Some(extra_data),
683
-
}
684
-
}
685
-
}
686
-
687
-
#[jacquard_derive::open_union]
688
-
#[derive(
689
-
serde::Serialize,
690
-
serde::Deserialize,
691
-
Debug,
692
-
Clone,
693
-
PartialEq,
694
-
Eq,
695
-
jacquard_derive::IntoStatic
696
-
)]
697
-
#[serde(tag = "$type")]
698
-
#[serde(bound(deserialize = "'de: 'a"))]
699
-
pub enum EntryNode<'a> {
700
-
#[serde(rename = "place.wisp.fs#file")]
701
-
File(Box<crate::place_wisp::fs::File<'a>>),
702
-
#[serde(rename = "place.wisp.fs#directory")]
703
-
Directory(Box<crate::place_wisp::fs::Directory<'a>>),
704
-
#[serde(rename = "place.wisp.fs#subfs")]
705
-
Subfs(Box<crate::place_wisp::fs::Subfs<'a>>),
706
-
}
707
-
708
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
709
-
fn nsid() -> &'static str {
710
-
"place.wisp.fs"
711
-
}
712
-
fn def_name() -> &'static str {
713
-
"entry"
714
-
}
715
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
716
-
lexicon_doc_place_wisp_fs()
717
-
}
718
-
fn validate(
719
-
&self,
720
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
721
-
{
722
-
let value = &self.name;
723
-
#[allow(unused_comparisons)]
724
-
if <str>::len(value.as_ref()) > 255usize {
725
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
726
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
727
-
"name",
728
-
),
729
-
max: 255usize,
730
-
actual: <str>::len(value.as_ref()),
731
-
});
732
-
}
733
-
}
734
-
Ok(())
735
-
}
736
-
}
737
-
738
-
#[jacquard_derive::lexicon]
739
-
#[derive(
740
-
serde::Serialize,
741
-
serde::Deserialize,
742
-
Debug,
743
-
Clone,
744
-
PartialEq,
745
-
Eq,
746
-
jacquard_derive::IntoStatic
747
-
)]
748
-
#[serde(rename_all = "camelCase")]
749
-
pub struct File<'a> {
750
-
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
751
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
752
-
pub base64: Option<bool>,
753
-
/// Content blob ref
754
-
#[serde(borrow)]
755
-
pub blob: jacquard_common::types::blob::BlobRef<'a>,
756
-
/// Content encoding (e.g., gzip for compressed files)
757
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
758
-
#[serde(borrow)]
759
-
pub encoding: Option<jacquard_common::CowStr<'a>>,
760
-
/// Original MIME type before compression
761
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
762
-
#[serde(borrow)]
763
-
pub mime_type: Option<jacquard_common::CowStr<'a>>,
764
-
#[serde(borrow)]
765
-
pub r#type: jacquard_common::CowStr<'a>,
766
-
}
767
-
768
-
pub mod file_state {
769
-
770
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
771
-
#[allow(unused)]
772
-
use ::core::marker::PhantomData;
773
-
mod sealed {
774
-
pub trait Sealed {}
775
-
}
776
-
/// State trait tracking which required fields have been set
777
-
pub trait State: sealed::Sealed {
778
-
type Type;
779
-
type Blob;
780
-
}
781
-
/// Empty state - all required fields are unset
782
-
pub struct Empty(());
783
-
impl sealed::Sealed for Empty {}
784
-
impl State for Empty {
785
-
type Type = Unset;
786
-
type Blob = Unset;
787
-
}
788
-
///State transition - sets the `type` field to Set
789
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
790
-
impl<S: State> sealed::Sealed for SetType<S> {}
791
-
impl<S: State> State for SetType<S> {
792
-
type Type = Set<members::r#type>;
793
-
type Blob = S::Blob;
794
-
}
795
-
///State transition - sets the `blob` field to Set
796
-
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
797
-
impl<S: State> sealed::Sealed for SetBlob<S> {}
798
-
impl<S: State> State for SetBlob<S> {
799
-
type Type = S::Type;
800
-
type Blob = Set<members::blob>;
801
-
}
802
-
/// Marker types for field names
803
-
#[allow(non_camel_case_types)]
804
-
pub mod members {
805
-
///Marker type for the `type` field
806
-
pub struct r#type(());
807
-
///Marker type for the `blob` field
808
-
pub struct blob(());
809
-
}
810
-
}
811
-
812
-
/// Builder for constructing an instance of this type
813
-
pub struct FileBuilder<'a, S: file_state::State> {
814
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
815
-
__unsafe_private_named: (
816
-
::core::option::Option<bool>,
817
-
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
818
-
::core::option::Option<jacquard_common::CowStr<'a>>,
819
-
::core::option::Option<jacquard_common::CowStr<'a>>,
820
-
::core::option::Option<jacquard_common::CowStr<'a>>,
821
-
),
822
-
_phantom: ::core::marker::PhantomData<&'a ()>,
823
-
}
824
-
825
-
impl<'a> File<'a> {
826
-
/// Create a new builder for this type
827
-
pub fn new() -> FileBuilder<'a, file_state::Empty> {
828
-
FileBuilder::new()
829
-
}
830
-
}
831
-
832
-
impl<'a> FileBuilder<'a, file_state::Empty> {
833
-
/// Create a new builder with all fields unset
834
-
pub fn new() -> Self {
835
-
FileBuilder {
836
-
_phantom_state: ::core::marker::PhantomData,
837
-
__unsafe_private_named: (None, None, None, None, None),
838
-
_phantom: ::core::marker::PhantomData,
839
-
}
840
-
}
841
-
}
842
-
843
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
844
-
/// Set the `base64` field (optional)
845
-
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
846
-
self.__unsafe_private_named.0 = value.into();
847
-
self
848
-
}
849
-
/// Set the `base64` field to an Option value (optional)
850
-
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
851
-
self.__unsafe_private_named.0 = value;
852
-
self
853
-
}
854
-
}
855
-
856
-
impl<'a, S> FileBuilder<'a, S>
857
-
where
858
-
S: file_state::State,
859
-
S::Blob: file_state::IsUnset,
860
-
{
861
-
/// Set the `blob` field (required)
862
-
pub fn blob(
863
-
mut self,
864
-
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
865
-
) -> FileBuilder<'a, file_state::SetBlob<S>> {
866
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
867
-
FileBuilder {
868
-
_phantom_state: ::core::marker::PhantomData,
869
-
__unsafe_private_named: self.__unsafe_private_named,
870
-
_phantom: ::core::marker::PhantomData,
871
-
}
872
-
}
873
-
}
874
-
875
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
876
-
/// Set the `encoding` field (optional)
877
-
pub fn encoding(
878
-
mut self,
879
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
880
-
) -> Self {
881
-
self.__unsafe_private_named.2 = value.into();
882
-
self
883
-
}
884
-
/// Set the `encoding` field to an Option value (optional)
885
-
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
886
-
self.__unsafe_private_named.2 = value;
887
-
self
888
-
}
889
-
}
890
-
891
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
892
-
/// Set the `mimeType` field (optional)
893
-
pub fn mime_type(
894
-
mut self,
895
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
896
-
) -> Self {
897
-
self.__unsafe_private_named.3 = value.into();
898
-
self
899
-
}
900
-
/// Set the `mimeType` field to an Option value (optional)
901
-
pub fn maybe_mime_type(
902
-
mut self,
903
-
value: Option<jacquard_common::CowStr<'a>>,
904
-
) -> Self {
905
-
self.__unsafe_private_named.3 = value;
906
-
self
907
-
}
908
-
}
909
-
910
-
impl<'a, S> FileBuilder<'a, S>
911
-
where
912
-
S: file_state::State,
913
-
S::Type: file_state::IsUnset,
914
-
{
915
-
/// Set the `type` field (required)
916
-
pub fn r#type(
917
-
mut self,
918
-
value: impl Into<jacquard_common::CowStr<'a>>,
919
-
) -> FileBuilder<'a, file_state::SetType<S>> {
920
-
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
921
-
FileBuilder {
922
-
_phantom_state: ::core::marker::PhantomData,
923
-
__unsafe_private_named: self.__unsafe_private_named,
924
-
_phantom: ::core::marker::PhantomData,
925
-
}
926
-
}
927
-
}
928
-
929
-
impl<'a, S> FileBuilder<'a, S>
930
-
where
931
-
S: file_state::State,
932
-
S::Type: file_state::IsSet,
933
-
S::Blob: file_state::IsSet,
934
-
{
935
-
/// Build the final struct
936
-
pub fn build(self) -> File<'a> {
937
-
File {
938
-
base64: self.__unsafe_private_named.0,
939
-
blob: self.__unsafe_private_named.1.unwrap(),
940
-
encoding: self.__unsafe_private_named.2,
941
-
mime_type: self.__unsafe_private_named.3,
942
-
r#type: self.__unsafe_private_named.4.unwrap(),
943
-
extra_data: Default::default(),
944
-
}
945
-
}
946
-
/// Build the final struct with custom extra_data
947
-
pub fn build_with_data(
948
-
self,
949
-
extra_data: std::collections::BTreeMap<
950
-
jacquard_common::smol_str::SmolStr,
951
-
jacquard_common::types::value::Data<'a>,
952
-
>,
953
-
) -> File<'a> {
954
-
File {
955
-
base64: self.__unsafe_private_named.0,
956
-
blob: self.__unsafe_private_named.1.unwrap(),
957
-
encoding: self.__unsafe_private_named.2,
958
-
mime_type: self.__unsafe_private_named.3,
959
-
r#type: self.__unsafe_private_named.4.unwrap(),
960
-
extra_data: Some(extra_data),
961
-
}
962
-
}
963
-
}
964
-
965
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
966
-
fn nsid() -> &'static str {
967
-
"place.wisp.fs"
968
-
}
969
-
fn def_name() -> &'static str {
970
-
"file"
971
-
}
972
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
973
-
lexicon_doc_place_wisp_fs()
974
-
}
975
-
fn validate(
976
-
&self,
977
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
978
-
Ok(())
979
-
}
980
-
}
981
-
982
-
/// Virtual filesystem manifest for a Wisp site
983
-
#[jacquard_derive::lexicon]
984
-
#[derive(
985
-
serde::Serialize,
986
-
serde::Deserialize,
987
-
Debug,
988
-
Clone,
989
-
PartialEq,
990
-
Eq,
991
-
jacquard_derive::IntoStatic
992
-
)]
993
-
#[serde(rename_all = "camelCase")]
994
-
pub struct Fs<'a> {
995
-
pub created_at: jacquard_common::types::string::Datetime,
996
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
997
-
pub file_count: Option<i64>,
998
-
#[serde(borrow)]
999
-
pub root: crate::place_wisp::fs::Directory<'a>,
1000
-
#[serde(borrow)]
1001
-
pub site: jacquard_common::CowStr<'a>,
1002
-
}
1003
-
1004
-
pub mod fs_state {
1005
-
1006
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1007
-
#[allow(unused)]
1008
-
use ::core::marker::PhantomData;
1009
-
mod sealed {
1010
-
pub trait Sealed {}
1011
-
}
1012
-
/// State trait tracking which required fields have been set
1013
-
pub trait State: sealed::Sealed {
1014
-
type Site;
1015
-
type Root;
1016
-
type CreatedAt;
1017
-
}
1018
-
/// Empty state - all required fields are unset
1019
-
pub struct Empty(());
1020
-
impl sealed::Sealed for Empty {}
1021
-
impl State for Empty {
1022
-
type Site = Unset;
1023
-
type Root = Unset;
1024
-
type CreatedAt = Unset;
1025
-
}
1026
-
///State transition - sets the `site` field to Set
1027
-
pub struct SetSite<S: State = Empty>(PhantomData<fn() -> S>);
1028
-
impl<S: State> sealed::Sealed for SetSite<S> {}
1029
-
impl<S: State> State for SetSite<S> {
1030
-
type Site = Set<members::site>;
1031
-
type Root = S::Root;
1032
-
type CreatedAt = S::CreatedAt;
1033
-
}
1034
-
///State transition - sets the `root` field to Set
1035
-
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1036
-
impl<S: State> sealed::Sealed for SetRoot<S> {}
1037
-
impl<S: State> State for SetRoot<S> {
1038
-
type Site = S::Site;
1039
-
type Root = Set<members::root>;
1040
-
type CreatedAt = S::CreatedAt;
1041
-
}
1042
-
///State transition - sets the `created_at` field to Set
1043
-
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1044
-
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1045
-
impl<S: State> State for SetCreatedAt<S> {
1046
-
type Site = S::Site;
1047
-
type Root = S::Root;
1048
-
type CreatedAt = Set<members::created_at>;
1049
-
}
1050
-
/// Marker types for field names
1051
-
#[allow(non_camel_case_types)]
1052
-
pub mod members {
1053
-
///Marker type for the `site` field
1054
-
pub struct site(());
1055
-
///Marker type for the `root` field
1056
-
pub struct root(());
1057
-
///Marker type for the `created_at` field
1058
-
pub struct created_at(());
1059
-
}
1060
-
}
1061
-
1062
-
/// Builder for constructing an instance of this type
1063
-
pub struct FsBuilder<'a, S: fs_state::State> {
1064
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1065
-
__unsafe_private_named: (
1066
-
::core::option::Option<jacquard_common::types::string::Datetime>,
1067
-
::core::option::Option<i64>,
1068
-
::core::option::Option<crate::place_wisp::fs::Directory<'a>>,
1069
-
::core::option::Option<jacquard_common::CowStr<'a>>,
1070
-
),
1071
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1072
-
}
1073
-
1074
-
impl<'a> Fs<'a> {
1075
-
/// Create a new builder for this type
1076
-
pub fn new() -> FsBuilder<'a, fs_state::Empty> {
1077
-
FsBuilder::new()
1078
-
}
1079
-
}
1080
-
1081
-
impl<'a> FsBuilder<'a, fs_state::Empty> {
1082
-
/// Create a new builder with all fields unset
1083
-
pub fn new() -> Self {
1084
-
FsBuilder {
1085
-
_phantom_state: ::core::marker::PhantomData,
1086
-
__unsafe_private_named: (None, None, None, None),
1087
-
_phantom: ::core::marker::PhantomData,
1088
-
}
1089
-
}
1090
-
}
1091
-
1092
-
impl<'a, S> FsBuilder<'a, S>
1093
-
where
1094
-
S: fs_state::State,
1095
-
S::CreatedAt: fs_state::IsUnset,
1096
-
{
1097
-
/// Set the `createdAt` field (required)
1098
-
pub fn created_at(
1099
-
mut self,
1100
-
value: impl Into<jacquard_common::types::string::Datetime>,
1101
-
) -> FsBuilder<'a, fs_state::SetCreatedAt<S>> {
1102
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1103
-
FsBuilder {
1104
-
_phantom_state: ::core::marker::PhantomData,
1105
-
__unsafe_private_named: self.__unsafe_private_named,
1106
-
_phantom: ::core::marker::PhantomData,
1107
-
}
1108
-
}
1109
-
}
1110
-
1111
-
impl<'a, S: fs_state::State> FsBuilder<'a, S> {
1112
-
/// Set the `fileCount` field (optional)
1113
-
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1114
-
self.__unsafe_private_named.1 = value.into();
1115
-
self
1116
-
}
1117
-
/// Set the `fileCount` field to an Option value (optional)
1118
-
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1119
-
self.__unsafe_private_named.1 = value;
1120
-
self
1121
-
}
1122
-
}
1123
-
1124
-
impl<'a, S> FsBuilder<'a, S>
1125
-
where
1126
-
S: fs_state::State,
1127
-
S::Root: fs_state::IsUnset,
1128
-
{
1129
-
/// Set the `root` field (required)
1130
-
pub fn root(
1131
-
mut self,
1132
-
value: impl Into<crate::place_wisp::fs::Directory<'a>>,
1133
-
) -> FsBuilder<'a, fs_state::SetRoot<S>> {
1134
-
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1135
-
FsBuilder {
1136
-
_phantom_state: ::core::marker::PhantomData,
1137
-
__unsafe_private_named: self.__unsafe_private_named,
1138
-
_phantom: ::core::marker::PhantomData,
1139
-
}
1140
-
}
1141
-
}
1142
-
1143
-
impl<'a, S> FsBuilder<'a, S>
1144
-
where
1145
-
S: fs_state::State,
1146
-
S::Site: fs_state::IsUnset,
1147
-
{
1148
-
/// Set the `site` field (required)
1149
-
pub fn site(
1150
-
mut self,
1151
-
value: impl Into<jacquard_common::CowStr<'a>>,
1152
-
) -> FsBuilder<'a, fs_state::SetSite<S>> {
1153
-
self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into());
1154
-
FsBuilder {
1155
-
_phantom_state: ::core::marker::PhantomData,
1156
-
__unsafe_private_named: self.__unsafe_private_named,
1157
-
_phantom: ::core::marker::PhantomData,
1158
-
}
1159
-
}
1160
-
}
1161
-
1162
-
impl<'a, S> FsBuilder<'a, S>
1163
-
where
1164
-
S: fs_state::State,
1165
-
S::Site: fs_state::IsSet,
1166
-
S::Root: fs_state::IsSet,
1167
-
S::CreatedAt: fs_state::IsSet,
1168
-
{
1169
-
/// Build the final struct
1170
-
pub fn build(self) -> Fs<'a> {
1171
-
Fs {
1172
-
created_at: self.__unsafe_private_named.0.unwrap(),
1173
-
file_count: self.__unsafe_private_named.1,
1174
-
root: self.__unsafe_private_named.2.unwrap(),
1175
-
site: self.__unsafe_private_named.3.unwrap(),
1176
-
extra_data: Default::default(),
1177
-
}
1178
-
}
1179
-
/// Build the final struct with custom extra_data
1180
-
pub fn build_with_data(
1181
-
self,
1182
-
extra_data: std::collections::BTreeMap<
1183
-
jacquard_common::smol_str::SmolStr,
1184
-
jacquard_common::types::value::Data<'a>,
1185
-
>,
1186
-
) -> Fs<'a> {
1187
-
Fs {
1188
-
created_at: self.__unsafe_private_named.0.unwrap(),
1189
-
file_count: self.__unsafe_private_named.1,
1190
-
root: self.__unsafe_private_named.2.unwrap(),
1191
-
site: self.__unsafe_private_named.3.unwrap(),
1192
-
extra_data: Some(extra_data),
1193
-
}
1194
-
}
1195
-
}
1196
-
1197
-
impl<'a> Fs<'a> {
1198
-
pub fn uri(
1199
-
uri: impl Into<jacquard_common::CowStr<'a>>,
1200
-
) -> Result<
1201
-
jacquard_common::types::uri::RecordUri<'a, FsRecord>,
1202
-
jacquard_common::types::uri::UriError,
1203
-
> {
1204
-
jacquard_common::types::uri::RecordUri::try_from_uri(
1205
-
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1206
-
)
1207
-
}
1208
-
}
1209
-
1210
-
/// Typed wrapper for GetRecord response with this collection's record type.
1211
-
#[derive(
1212
-
serde::Serialize,
1213
-
serde::Deserialize,
1214
-
Debug,
1215
-
Clone,
1216
-
PartialEq,
1217
-
Eq,
1218
-
jacquard_derive::IntoStatic
1219
-
)]
1220
-
#[serde(rename_all = "camelCase")]
1221
-
pub struct FsGetRecordOutput<'a> {
1222
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1223
-
#[serde(borrow)]
1224
-
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1225
-
#[serde(borrow)]
1226
-
pub uri: jacquard_common::types::string::AtUri<'a>,
1227
-
#[serde(borrow)]
1228
-
pub value: Fs<'a>,
1229
-
}
1230
-
1231
-
impl From<FsGetRecordOutput<'_>> for Fs<'_> {
1232
-
fn from(output: FsGetRecordOutput<'_>) -> Self {
1233
-
use jacquard_common::IntoStatic;
1234
-
output.value.into_static()
1235
-
}
1236
-
}
1237
-
1238
-
impl jacquard_common::types::collection::Collection for Fs<'_> {
1239
-
const NSID: &'static str = "place.wisp.fs";
1240
-
type Record = FsRecord;
1241
-
}
1242
-
1243
-
/// Marker type for deserializing records from this collection.
1244
-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1245
-
pub struct FsRecord;
1246
-
impl jacquard_common::xrpc::XrpcResp for FsRecord {
1247
-
const NSID: &'static str = "place.wisp.fs";
1248
-
const ENCODING: &'static str = "application/json";
1249
-
type Output<'de> = FsGetRecordOutput<'de>;
1250
-
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1251
-
}
1252
-
1253
-
impl jacquard_common::types::collection::Collection for FsRecord {
1254
-
const NSID: &'static str = "place.wisp.fs";
1255
-
type Record = FsRecord;
1256
-
}
1257
-
1258
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Fs<'a> {
1259
-
fn nsid() -> &'static str {
1260
-
"place.wisp.fs"
1261
-
}
1262
-
fn def_name() -> &'static str {
1263
-
"main"
1264
-
}
1265
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1266
-
lexicon_doc_place_wisp_fs()
1267
-
}
1268
-
fn validate(
1269
-
&self,
1270
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1271
-
if let Some(ref value) = self.file_count {
1272
-
if *value > 1000i64 {
1273
-
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1274
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1275
-
"file_count",
1276
-
),
1277
-
max: 1000i64,
1278
-
actual: *value,
1279
-
});
1280
-
}
1281
-
}
1282
-
if let Some(ref value) = self.file_count {
1283
-
if *value < 0i64 {
1284
-
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1285
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1286
-
"file_count",
1287
-
),
1288
-
min: 0i64,
1289
-
actual: *value,
1290
-
});
1291
-
}
1292
-
}
1293
-
Ok(())
1294
-
}
1295
-
}
1296
-
1297
-
#[jacquard_derive::lexicon]
1298
-
#[derive(
1299
-
serde::Serialize,
1300
-
serde::Deserialize,
1301
-
Debug,
1302
-
Clone,
1303
-
PartialEq,
1304
-
Eq,
1305
-
jacquard_derive::IntoStatic
1306
-
)]
1307
-
#[serde(rename_all = "camelCase")]
1308
-
pub struct Subfs<'a> {
1309
-
/// If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure.
1310
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1311
-
pub flat: Option<bool>,
1312
-
/// AT-URI pointing to a place.wisp.subfs record containing this subtree.
1313
-
#[serde(borrow)]
1314
-
pub subject: jacquard_common::types::string::AtUri<'a>,
1315
-
#[serde(borrow)]
1316
-
pub r#type: jacquard_common::CowStr<'a>,
1317
-
}
1318
-
1319
-
pub mod subfs_state {
1320
-
1321
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1322
-
#[allow(unused)]
1323
-
use ::core::marker::PhantomData;
1324
-
mod sealed {
1325
-
pub trait Sealed {}
1326
-
}
1327
-
/// State trait tracking which required fields have been set
1328
-
pub trait State: sealed::Sealed {
1329
-
type Type;
1330
-
type Subject;
1331
-
}
1332
-
/// Empty state - all required fields are unset
1333
-
pub struct Empty(());
1334
-
impl sealed::Sealed for Empty {}
1335
-
impl State for Empty {
1336
-
type Type = Unset;
1337
-
type Subject = Unset;
1338
-
}
1339
-
///State transition - sets the `type` field to Set
1340
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1341
-
impl<S: State> sealed::Sealed for SetType<S> {}
1342
-
impl<S: State> State for SetType<S> {
1343
-
type Type = Set<members::r#type>;
1344
-
type Subject = S::Subject;
1345
-
}
1346
-
///State transition - sets the `subject` field to Set
1347
-
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1348
-
impl<S: State> sealed::Sealed for SetSubject<S> {}
1349
-
impl<S: State> State for SetSubject<S> {
1350
-
type Type = S::Type;
1351
-
type Subject = Set<members::subject>;
1352
-
}
1353
-
/// Marker types for field names
1354
-
#[allow(non_camel_case_types)]
1355
-
pub mod members {
1356
-
///Marker type for the `type` field
1357
-
pub struct r#type(());
1358
-
///Marker type for the `subject` field
1359
-
pub struct subject(());
1360
-
}
1361
-
}
1362
-
1363
-
/// Builder for constructing an instance of this type
1364
-
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1365
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1366
-
__unsafe_private_named: (
1367
-
::core::option::Option<bool>,
1368
-
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1369
-
::core::option::Option<jacquard_common::CowStr<'a>>,
1370
-
),
1371
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1372
-
}
1373
-
1374
-
impl<'a> Subfs<'a> {
1375
-
/// Create a new builder for this type
1376
-
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1377
-
SubfsBuilder::new()
1378
-
}
1379
-
}
1380
-
1381
-
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1382
-
/// Create a new builder with all fields unset
1383
-
pub fn new() -> Self {
1384
-
SubfsBuilder {
1385
-
_phantom_state: ::core::marker::PhantomData,
1386
-
__unsafe_private_named: (None, None, None),
1387
-
_phantom: ::core::marker::PhantomData,
1388
-
}
1389
-
}
1390
-
}
1391
-
1392
-
impl<'a, S: subfs_state::State> SubfsBuilder<'a, S> {
1393
-
/// Set the `flat` field (optional)
1394
-
pub fn flat(mut self, value: impl Into<Option<bool>>) -> Self {
1395
-
self.__unsafe_private_named.0 = value.into();
1396
-
self
1397
-
}
1398
-
/// Set the `flat` field to an Option value (optional)
1399
-
pub fn maybe_flat(mut self, value: Option<bool>) -> Self {
1400
-
self.__unsafe_private_named.0 = value;
1401
-
self
1402
-
}
1403
-
}
1404
-
1405
-
impl<'a, S> SubfsBuilder<'a, S>
1406
-
where
1407
-
S: subfs_state::State,
1408
-
S::Subject: subfs_state::IsUnset,
1409
-
{
1410
-
/// Set the `subject` field (required)
1411
-
pub fn subject(
1412
-
mut self,
1413
-
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1414
-
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1415
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1416
-
SubfsBuilder {
1417
-
_phantom_state: ::core::marker::PhantomData,
1418
-
__unsafe_private_named: self.__unsafe_private_named,
1419
-
_phantom: ::core::marker::PhantomData,
1420
-
}
1421
-
}
1422
-
}
1423
-
1424
-
impl<'a, S> SubfsBuilder<'a, S>
1425
-
where
1426
-
S: subfs_state::State,
1427
-
S::Type: subfs_state::IsUnset,
1428
-
{
1429
-
/// Set the `type` field (required)
1430
-
pub fn r#type(
1431
-
mut self,
1432
-
value: impl Into<jacquard_common::CowStr<'a>>,
1433
-
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1434
-
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1435
-
SubfsBuilder {
1436
-
_phantom_state: ::core::marker::PhantomData,
1437
-
__unsafe_private_named: self.__unsafe_private_named,
1438
-
_phantom: ::core::marker::PhantomData,
1439
-
}
1440
-
}
1441
-
}
1442
-
1443
-
impl<'a, S> SubfsBuilder<'a, S>
1444
-
where
1445
-
S: subfs_state::State,
1446
-
S::Type: subfs_state::IsSet,
1447
-
S::Subject: subfs_state::IsSet,
1448
-
{
1449
-
/// Build the final struct
1450
-
pub fn build(self) -> Subfs<'a> {
1451
-
Subfs {
1452
-
flat: self.__unsafe_private_named.0,
1453
-
subject: self.__unsafe_private_named.1.unwrap(),
1454
-
r#type: self.__unsafe_private_named.2.unwrap(),
1455
-
extra_data: Default::default(),
1456
-
}
1457
-
}
1458
-
/// Build the final struct with custom extra_data
1459
-
pub fn build_with_data(
1460
-
self,
1461
-
extra_data: std::collections::BTreeMap<
1462
-
jacquard_common::smol_str::SmolStr,
1463
-
jacquard_common::types::value::Data<'a>,
1464
-
>,
1465
-
) -> Subfs<'a> {
1466
-
Subfs {
1467
-
flat: self.__unsafe_private_named.0,
1468
-
subject: self.__unsafe_private_named.1.unwrap(),
1469
-
r#type: self.__unsafe_private_named.2.unwrap(),
1470
-
extra_data: Some(extra_data),
1471
-
}
1472
-
}
1473
-
}
1474
-
1475
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1476
-
fn nsid() -> &'static str {
1477
-
"place.wisp.fs"
1478
-
}
1479
-
fn def_name() -> &'static str {
1480
-
"subfs"
1481
-
}
1482
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1483
-
lexicon_doc_place_wisp_fs()
1484
-
}
1485
-
fn validate(
1486
-
&self,
1487
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1488
-
Ok(())
1489
-
}
1490
-
}
-653
cli/src/place_wisp/settings.rs
-653
cli/src/place_wisp/settings.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// Lexicon: place.wisp.settings
4
-
//
5
-
// This file was automatically generated from Lexicon schemas.
6
-
// Any manual changes will be overwritten on the next regeneration.
7
-
8
-
/// Custom HTTP header configuration
9
-
#[jacquard_derive::lexicon]
10
-
#[derive(
11
-
serde::Serialize,
12
-
serde::Deserialize,
13
-
Debug,
14
-
Clone,
15
-
PartialEq,
16
-
Eq,
17
-
jacquard_derive::IntoStatic,
18
-
Default
19
-
)]
20
-
#[serde(rename_all = "camelCase")]
21
-
pub struct CustomHeader<'a> {
22
-
/// HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')
23
-
#[serde(borrow)]
24
-
pub name: jacquard_common::CowStr<'a>,
25
-
/// Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.
26
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
27
-
#[serde(borrow)]
28
-
pub path: std::option::Option<jacquard_common::CowStr<'a>>,
29
-
/// HTTP header value
30
-
#[serde(borrow)]
31
-
pub value: jacquard_common::CowStr<'a>,
32
-
}
33
-
34
-
fn lexicon_doc_place_wisp_settings() -> ::jacquard_lexicon::lexicon::LexiconDoc<
35
-
'static,
36
-
> {
37
-
::jacquard_lexicon::lexicon::LexiconDoc {
38
-
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
39
-
id: ::jacquard_common::CowStr::new_static("place.wisp.settings"),
40
-
revision: None,
41
-
description: None,
42
-
defs: {
43
-
let mut map = ::std::collections::BTreeMap::new();
44
-
map.insert(
45
-
::jacquard_common::smol_str::SmolStr::new_static("customHeader"),
46
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
47
-
description: Some(
48
-
::jacquard_common::CowStr::new_static(
49
-
"Custom HTTP header configuration",
50
-
),
51
-
),
52
-
required: Some(
53
-
vec![
54
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
55
-
::jacquard_common::smol_str::SmolStr::new_static("value")
56
-
],
57
-
),
58
-
nullable: None,
59
-
properties: {
60
-
#[allow(unused_mut)]
61
-
let mut map = ::std::collections::BTreeMap::new();
62
-
map.insert(
63
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
64
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
65
-
description: Some(
66
-
::jacquard_common::CowStr::new_static(
67
-
"HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
68
-
),
69
-
),
70
-
format: None,
71
-
default: None,
72
-
min_length: None,
73
-
max_length: Some(100usize),
74
-
min_graphemes: None,
75
-
max_graphemes: None,
76
-
r#enum: None,
77
-
r#const: None,
78
-
known_values: None,
79
-
}),
80
-
);
81
-
map.insert(
82
-
::jacquard_common::smol_str::SmolStr::new_static("path"),
83
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
84
-
description: Some(
85
-
::jacquard_common::CowStr::new_static(
86
-
"Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
87
-
),
88
-
),
89
-
format: None,
90
-
default: None,
91
-
min_length: None,
92
-
max_length: Some(500usize),
93
-
min_graphemes: None,
94
-
max_graphemes: None,
95
-
r#enum: None,
96
-
r#const: None,
97
-
known_values: None,
98
-
}),
99
-
);
100
-
map.insert(
101
-
::jacquard_common::smol_str::SmolStr::new_static("value"),
102
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
103
-
description: Some(
104
-
::jacquard_common::CowStr::new_static("HTTP header value"),
105
-
),
106
-
format: None,
107
-
default: None,
108
-
min_length: None,
109
-
max_length: Some(1000usize),
110
-
min_graphemes: None,
111
-
max_graphemes: None,
112
-
r#enum: None,
113
-
r#const: None,
114
-
known_values: None,
115
-
}),
116
-
);
117
-
map
118
-
},
119
-
}),
120
-
);
121
-
map.insert(
122
-
::jacquard_common::smol_str::SmolStr::new_static("main"),
123
-
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
124
-
description: Some(
125
-
::jacquard_common::CowStr::new_static(
126
-
"Configuration settings for a static site hosted on wisp.place",
127
-
),
128
-
),
129
-
key: Some(::jacquard_common::CowStr::new_static("any")),
130
-
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
131
-
description: None,
132
-
required: None,
133
-
nullable: None,
134
-
properties: {
135
-
#[allow(unused_mut)]
136
-
let mut map = ::std::collections::BTreeMap::new();
137
-
map.insert(
138
-
::jacquard_common::smol_str::SmolStr::new_static(
139
-
"cleanUrls",
140
-
),
141
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
142
-
description: None,
143
-
default: None,
144
-
r#const: None,
145
-
}),
146
-
);
147
-
map.insert(
148
-
::jacquard_common::smol_str::SmolStr::new_static(
149
-
"custom404",
150
-
),
151
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
152
-
description: Some(
153
-
::jacquard_common::CowStr::new_static(
154
-
"Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
155
-
),
156
-
),
157
-
format: None,
158
-
default: None,
159
-
min_length: None,
160
-
max_length: Some(500usize),
161
-
min_graphemes: None,
162
-
max_graphemes: None,
163
-
r#enum: None,
164
-
r#const: None,
165
-
known_values: None,
166
-
}),
167
-
);
168
-
map.insert(
169
-
::jacquard_common::smol_str::SmolStr::new_static(
170
-
"directoryListing",
171
-
),
172
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
173
-
description: None,
174
-
default: None,
175
-
r#const: None,
176
-
}),
177
-
);
178
-
map.insert(
179
-
::jacquard_common::smol_str::SmolStr::new_static("headers"),
180
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
181
-
description: Some(
182
-
::jacquard_common::CowStr::new_static(
183
-
"Custom HTTP headers to set on responses",
184
-
),
185
-
),
186
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
187
-
description: None,
188
-
r#ref: ::jacquard_common::CowStr::new_static(
189
-
"#customHeader",
190
-
),
191
-
}),
192
-
min_length: None,
193
-
max_length: Some(50usize),
194
-
}),
195
-
);
196
-
map.insert(
197
-
::jacquard_common::smol_str::SmolStr::new_static(
198
-
"indexFiles",
199
-
),
200
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
201
-
description: Some(
202
-
::jacquard_common::CowStr::new_static(
203
-
"Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
204
-
),
205
-
),
206
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::String(::jacquard_lexicon::lexicon::LexString {
207
-
description: None,
208
-
format: None,
209
-
default: None,
210
-
min_length: None,
211
-
max_length: Some(255usize),
212
-
min_graphemes: None,
213
-
max_graphemes: None,
214
-
r#enum: None,
215
-
r#const: None,
216
-
known_values: None,
217
-
}),
218
-
min_length: None,
219
-
max_length: Some(10usize),
220
-
}),
221
-
);
222
-
map.insert(
223
-
::jacquard_common::smol_str::SmolStr::new_static("spaMode"),
224
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
225
-
description: Some(
226
-
::jacquard_common::CowStr::new_static(
227
-
"File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.",
228
-
),
229
-
),
230
-
format: None,
231
-
default: None,
232
-
min_length: None,
233
-
max_length: Some(500usize),
234
-
min_graphemes: None,
235
-
max_graphemes: None,
236
-
r#enum: None,
237
-
r#const: None,
238
-
known_values: None,
239
-
}),
240
-
);
241
-
map
242
-
},
243
-
}),
244
-
}),
245
-
);
246
-
map
247
-
},
248
-
}
249
-
}
250
-
251
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for CustomHeader<'a> {
252
-
fn nsid() -> &'static str {
253
-
"place.wisp.settings"
254
-
}
255
-
fn def_name() -> &'static str {
256
-
"customHeader"
257
-
}
258
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
259
-
lexicon_doc_place_wisp_settings()
260
-
}
261
-
fn validate(
262
-
&self,
263
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
264
-
{
265
-
let value = &self.name;
266
-
#[allow(unused_comparisons)]
267
-
if <str>::len(value.as_ref()) > 100usize {
268
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
269
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
270
-
"name",
271
-
),
272
-
max: 100usize,
273
-
actual: <str>::len(value.as_ref()),
274
-
});
275
-
}
276
-
}
277
-
if let Some(ref value) = self.path {
278
-
#[allow(unused_comparisons)]
279
-
if <str>::len(value.as_ref()) > 500usize {
280
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
281
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
282
-
"path",
283
-
),
284
-
max: 500usize,
285
-
actual: <str>::len(value.as_ref()),
286
-
});
287
-
}
288
-
}
289
-
{
290
-
let value = &self.value;
291
-
#[allow(unused_comparisons)]
292
-
if <str>::len(value.as_ref()) > 1000usize {
293
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
294
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
295
-
"value",
296
-
),
297
-
max: 1000usize,
298
-
actual: <str>::len(value.as_ref()),
299
-
});
300
-
}
301
-
}
302
-
Ok(())
303
-
}
304
-
}
305
-
306
-
/// Configuration settings for a static site hosted on wisp.place
307
-
#[jacquard_derive::lexicon]
308
-
#[derive(
309
-
serde::Serialize,
310
-
serde::Deserialize,
311
-
Debug,
312
-
Clone,
313
-
PartialEq,
314
-
Eq,
315
-
jacquard_derive::IntoStatic
316
-
)]
317
-
#[serde(rename_all = "camelCase")]
318
-
pub struct Settings<'a> {
319
-
/// Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.
320
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
321
-
pub clean_urls: std::option::Option<bool>,
322
-
/// Custom 404 error page file path. Incompatible with directoryListing and spaMode.
323
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
324
-
#[serde(borrow)]
325
-
pub custom404: std::option::Option<jacquard_common::CowStr<'a>>,
326
-
/// Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.
327
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
328
-
pub directory_listing: std::option::Option<bool>,
329
-
/// Custom HTTP headers to set on responses
330
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
331
-
#[serde(borrow)]
332
-
pub headers: std::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
333
-
/// Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.
334
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
335
-
#[serde(borrow)]
336
-
pub index_files: std::option::Option<Vec<jacquard_common::CowStr<'a>>>,
337
-
/// File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.
338
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
339
-
#[serde(borrow)]
340
-
pub spa_mode: std::option::Option<jacquard_common::CowStr<'a>>,
341
-
}
342
-
343
-
pub mod settings_state {
344
-
345
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
346
-
#[allow(unused)]
347
-
use ::core::marker::PhantomData;
348
-
mod sealed {
349
-
pub trait Sealed {}
350
-
}
351
-
/// State trait tracking which required fields have been set
352
-
pub trait State: sealed::Sealed {}
353
-
/// Empty state - all required fields are unset
354
-
pub struct Empty(());
355
-
impl sealed::Sealed for Empty {}
356
-
impl State for Empty {}
357
-
/// Marker types for field names
358
-
#[allow(non_camel_case_types)]
359
-
pub mod members {}
360
-
}
361
-
362
-
/// Builder for constructing an instance of this type
363
-
pub struct SettingsBuilder<'a, S: settings_state::State> {
364
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
365
-
__unsafe_private_named: (
366
-
::core::option::Option<bool>,
367
-
::core::option::Option<jacquard_common::CowStr<'a>>,
368
-
::core::option::Option<bool>,
369
-
::core::option::Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
370
-
::core::option::Option<Vec<jacquard_common::CowStr<'a>>>,
371
-
::core::option::Option<jacquard_common::CowStr<'a>>,
372
-
),
373
-
_phantom: ::core::marker::PhantomData<&'a ()>,
374
-
}
375
-
376
-
impl<'a> Settings<'a> {
377
-
/// Create a new builder for this type
378
-
pub fn new() -> SettingsBuilder<'a, settings_state::Empty> {
379
-
SettingsBuilder::new()
380
-
}
381
-
}
382
-
383
-
impl<'a> SettingsBuilder<'a, settings_state::Empty> {
384
-
/// Create a new builder with all fields unset
385
-
pub fn new() -> Self {
386
-
SettingsBuilder {
387
-
_phantom_state: ::core::marker::PhantomData,
388
-
__unsafe_private_named: (None, None, None, None, None, None),
389
-
_phantom: ::core::marker::PhantomData,
390
-
}
391
-
}
392
-
}
393
-
394
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
395
-
/// Set the `cleanUrls` field (optional)
396
-
pub fn clean_urls(mut self, value: impl Into<Option<bool>>) -> Self {
397
-
self.__unsafe_private_named.0 = value.into();
398
-
self
399
-
}
400
-
/// Set the `cleanUrls` field to an Option value (optional)
401
-
pub fn maybe_clean_urls(mut self, value: Option<bool>) -> Self {
402
-
self.__unsafe_private_named.0 = value;
403
-
self
404
-
}
405
-
}
406
-
407
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
408
-
/// Set the `custom404` field (optional)
409
-
pub fn custom404(
410
-
mut self,
411
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
412
-
) -> Self {
413
-
self.__unsafe_private_named.1 = value.into();
414
-
self
415
-
}
416
-
/// Set the `custom404` field to an Option value (optional)
417
-
pub fn maybe_custom404(
418
-
mut self,
419
-
value: Option<jacquard_common::CowStr<'a>>,
420
-
) -> Self {
421
-
self.__unsafe_private_named.1 = value;
422
-
self
423
-
}
424
-
}
425
-
426
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
427
-
/// Set the `directoryListing` field (optional)
428
-
pub fn directory_listing(mut self, value: impl Into<Option<bool>>) -> Self {
429
-
self.__unsafe_private_named.2 = value.into();
430
-
self
431
-
}
432
-
/// Set the `directoryListing` field to an Option value (optional)
433
-
pub fn maybe_directory_listing(mut self, value: Option<bool>) -> Self {
434
-
self.__unsafe_private_named.2 = value;
435
-
self
436
-
}
437
-
}
438
-
439
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
440
-
/// Set the `headers` field (optional)
441
-
pub fn headers(
442
-
mut self,
443
-
value: impl Into<Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>>,
444
-
) -> Self {
445
-
self.__unsafe_private_named.3 = value.into();
446
-
self
447
-
}
448
-
/// Set the `headers` field to an Option value (optional)
449
-
pub fn maybe_headers(
450
-
mut self,
451
-
value: Option<Vec<crate::place_wisp::settings::CustomHeader<'a>>>,
452
-
) -> Self {
453
-
self.__unsafe_private_named.3 = value;
454
-
self
455
-
}
456
-
}
457
-
458
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
459
-
/// Set the `indexFiles` field (optional)
460
-
pub fn index_files(
461
-
mut self,
462
-
value: impl Into<Option<Vec<jacquard_common::CowStr<'a>>>>,
463
-
) -> Self {
464
-
self.__unsafe_private_named.4 = value.into();
465
-
self
466
-
}
467
-
/// Set the `indexFiles` field to an Option value (optional)
468
-
pub fn maybe_index_files(
469
-
mut self,
470
-
value: Option<Vec<jacquard_common::CowStr<'a>>>,
471
-
) -> Self {
472
-
self.__unsafe_private_named.4 = value;
473
-
self
474
-
}
475
-
}
476
-
477
-
impl<'a, S: settings_state::State> SettingsBuilder<'a, S> {
478
-
/// Set the `spaMode` field (optional)
479
-
pub fn spa_mode(
480
-
mut self,
481
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
482
-
) -> Self {
483
-
self.__unsafe_private_named.5 = value.into();
484
-
self
485
-
}
486
-
/// Set the `spaMode` field to an Option value (optional)
487
-
pub fn maybe_spa_mode(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
488
-
self.__unsafe_private_named.5 = value;
489
-
self
490
-
}
491
-
}
492
-
493
-
impl<'a, S> SettingsBuilder<'a, S>
494
-
where
495
-
S: settings_state::State,
496
-
{
497
-
/// Build the final struct
498
-
pub fn build(self) -> Settings<'a> {
499
-
Settings {
500
-
clean_urls: self.__unsafe_private_named.0,
501
-
custom404: self.__unsafe_private_named.1,
502
-
directory_listing: self.__unsafe_private_named.2,
503
-
headers: self.__unsafe_private_named.3,
504
-
index_files: self.__unsafe_private_named.4,
505
-
spa_mode: self.__unsafe_private_named.5,
506
-
extra_data: Default::default(),
507
-
}
508
-
}
509
-
/// Build the final struct with custom extra_data
510
-
pub fn build_with_data(
511
-
self,
512
-
extra_data: std::collections::BTreeMap<
513
-
jacquard_common::smol_str::SmolStr,
514
-
jacquard_common::types::value::Data<'a>,
515
-
>,
516
-
) -> Settings<'a> {
517
-
Settings {
518
-
clean_urls: self.__unsafe_private_named.0,
519
-
custom404: self.__unsafe_private_named.1,
520
-
directory_listing: self.__unsafe_private_named.2,
521
-
headers: self.__unsafe_private_named.3,
522
-
index_files: self.__unsafe_private_named.4,
523
-
spa_mode: self.__unsafe_private_named.5,
524
-
extra_data: Some(extra_data),
525
-
}
526
-
}
527
-
}
528
-
529
-
impl<'a> Settings<'a> {
530
-
pub fn uri(
531
-
uri: impl Into<jacquard_common::CowStr<'a>>,
532
-
) -> Result<
533
-
jacquard_common::types::uri::RecordUri<'a, SettingsRecord>,
534
-
jacquard_common::types::uri::UriError,
535
-
> {
536
-
jacquard_common::types::uri::RecordUri::try_from_uri(
537
-
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
538
-
)
539
-
}
540
-
}
541
-
542
-
/// Typed wrapper for GetRecord response with this collection's record type.
543
-
#[derive(
544
-
serde::Serialize,
545
-
serde::Deserialize,
546
-
Debug,
547
-
Clone,
548
-
PartialEq,
549
-
Eq,
550
-
jacquard_derive::IntoStatic
551
-
)]
552
-
#[serde(rename_all = "camelCase")]
553
-
pub struct SettingsGetRecordOutput<'a> {
554
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
555
-
#[serde(borrow)]
556
-
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
557
-
#[serde(borrow)]
558
-
pub uri: jacquard_common::types::string::AtUri<'a>,
559
-
#[serde(borrow)]
560
-
pub value: Settings<'a>,
561
-
}
562
-
563
-
impl From<SettingsGetRecordOutput<'_>> for Settings<'_> {
564
-
fn from(output: SettingsGetRecordOutput<'_>) -> Self {
565
-
use jacquard_common::IntoStatic;
566
-
output.value.into_static()
567
-
}
568
-
}
569
-
570
-
impl jacquard_common::types::collection::Collection for Settings<'_> {
571
-
const NSID: &'static str = "place.wisp.settings";
572
-
type Record = SettingsRecord;
573
-
}
574
-
575
-
/// Marker type for deserializing records from this collection.
576
-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
577
-
pub struct SettingsRecord;
578
-
impl jacquard_common::xrpc::XrpcResp for SettingsRecord {
579
-
const NSID: &'static str = "place.wisp.settings";
580
-
const ENCODING: &'static str = "application/json";
581
-
type Output<'de> = SettingsGetRecordOutput<'de>;
582
-
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
583
-
}
584
-
585
-
impl jacquard_common::types::collection::Collection for SettingsRecord {
586
-
const NSID: &'static str = "place.wisp.settings";
587
-
type Record = SettingsRecord;
588
-
}
589
-
590
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Settings<'a> {
591
-
fn nsid() -> &'static str {
592
-
"place.wisp.settings"
593
-
}
594
-
fn def_name() -> &'static str {
595
-
"main"
596
-
}
597
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
598
-
lexicon_doc_place_wisp_settings()
599
-
}
600
-
fn validate(
601
-
&self,
602
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
603
-
if let Some(ref value) = self.custom404 {
604
-
#[allow(unused_comparisons)]
605
-
if <str>::len(value.as_ref()) > 500usize {
606
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
607
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
608
-
"custom404",
609
-
),
610
-
max: 500usize,
611
-
actual: <str>::len(value.as_ref()),
612
-
});
613
-
}
614
-
}
615
-
if let Some(ref value) = self.headers {
616
-
#[allow(unused_comparisons)]
617
-
if value.len() > 50usize {
618
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
619
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
620
-
"headers",
621
-
),
622
-
max: 50usize,
623
-
actual: value.len(),
624
-
});
625
-
}
626
-
}
627
-
if let Some(ref value) = self.index_files {
628
-
#[allow(unused_comparisons)]
629
-
if value.len() > 10usize {
630
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
631
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
632
-
"index_files",
633
-
),
634
-
max: 10usize,
635
-
actual: value.len(),
636
-
});
637
-
}
638
-
}
639
-
if let Some(ref value) = self.spa_mode {
640
-
#[allow(unused_comparisons)]
641
-
if <str>::len(value.as_ref()) > 500usize {
642
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
643
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
644
-
"spa_mode",
645
-
),
646
-
max: 500usize,
647
-
actual: <str>::len(value.as_ref()),
648
-
});
649
-
}
650
-
}
651
-
Ok(())
652
-
}
653
-
}
-1408
cli/src/place_wisp/subfs.rs
-1408
cli/src/place_wisp/subfs.rs
···
1
-
// @generated by jacquard-lexicon. DO NOT EDIT.
2
-
//
3
-
// Lexicon: place.wisp.subfs
4
-
//
5
-
// This file was automatically generated from Lexicon schemas.
6
-
// Any manual changes will be overwritten on the next regeneration.
7
-
8
-
#[jacquard_derive::lexicon]
9
-
#[derive(
10
-
serde::Serialize,
11
-
serde::Deserialize,
12
-
Debug,
13
-
Clone,
14
-
PartialEq,
15
-
Eq,
16
-
jacquard_derive::IntoStatic
17
-
)]
18
-
#[serde(rename_all = "camelCase")]
19
-
pub struct Directory<'a> {
20
-
#[serde(borrow)]
21
-
pub entries: Vec<crate::place_wisp::subfs::Entry<'a>>,
22
-
#[serde(borrow)]
23
-
pub r#type: jacquard_common::CowStr<'a>,
24
-
}
25
-
26
-
pub mod directory_state {
27
-
28
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
29
-
#[allow(unused)]
30
-
use ::core::marker::PhantomData;
31
-
mod sealed {
32
-
pub trait Sealed {}
33
-
}
34
-
/// State trait tracking which required fields have been set
35
-
pub trait State: sealed::Sealed {
36
-
type Type;
37
-
type Entries;
38
-
}
39
-
/// Empty state - all required fields are unset
40
-
pub struct Empty(());
41
-
impl sealed::Sealed for Empty {}
42
-
impl State for Empty {
43
-
type Type = Unset;
44
-
type Entries = Unset;
45
-
}
46
-
///State transition - sets the `type` field to Set
47
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
48
-
impl<S: State> sealed::Sealed for SetType<S> {}
49
-
impl<S: State> State for SetType<S> {
50
-
type Type = Set<members::r#type>;
51
-
type Entries = S::Entries;
52
-
}
53
-
///State transition - sets the `entries` field to Set
54
-
pub struct SetEntries<S: State = Empty>(PhantomData<fn() -> S>);
55
-
impl<S: State> sealed::Sealed for SetEntries<S> {}
56
-
impl<S: State> State for SetEntries<S> {
57
-
type Type = S::Type;
58
-
type Entries = Set<members::entries>;
59
-
}
60
-
/// Marker types for field names
61
-
#[allow(non_camel_case_types)]
62
-
pub mod members {
63
-
///Marker type for the `type` field
64
-
pub struct r#type(());
65
-
///Marker type for the `entries` field
66
-
pub struct entries(());
67
-
}
68
-
}
69
-
70
-
/// Builder for constructing an instance of this type
71
-
pub struct DirectoryBuilder<'a, S: directory_state::State> {
72
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
73
-
__unsafe_private_named: (
74
-
::core::option::Option<Vec<crate::place_wisp::subfs::Entry<'a>>>,
75
-
::core::option::Option<jacquard_common::CowStr<'a>>,
76
-
),
77
-
_phantom: ::core::marker::PhantomData<&'a ()>,
78
-
}
79
-
80
-
impl<'a> Directory<'a> {
81
-
/// Create a new builder for this type
82
-
pub fn new() -> DirectoryBuilder<'a, directory_state::Empty> {
83
-
DirectoryBuilder::new()
84
-
}
85
-
}
86
-
87
-
impl<'a> DirectoryBuilder<'a, directory_state::Empty> {
88
-
/// Create a new builder with all fields unset
89
-
pub fn new() -> Self {
90
-
DirectoryBuilder {
91
-
_phantom_state: ::core::marker::PhantomData,
92
-
__unsafe_private_named: (None, None),
93
-
_phantom: ::core::marker::PhantomData,
94
-
}
95
-
}
96
-
}
97
-
98
-
impl<'a, S> DirectoryBuilder<'a, S>
99
-
where
100
-
S: directory_state::State,
101
-
S::Entries: directory_state::IsUnset,
102
-
{
103
-
/// Set the `entries` field (required)
104
-
pub fn entries(
105
-
mut self,
106
-
value: impl Into<Vec<crate::place_wisp::subfs::Entry<'a>>>,
107
-
) -> DirectoryBuilder<'a, directory_state::SetEntries<S>> {
108
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
109
-
DirectoryBuilder {
110
-
_phantom_state: ::core::marker::PhantomData,
111
-
__unsafe_private_named: self.__unsafe_private_named,
112
-
_phantom: ::core::marker::PhantomData,
113
-
}
114
-
}
115
-
}
116
-
117
-
impl<'a, S> DirectoryBuilder<'a, S>
118
-
where
119
-
S: directory_state::State,
120
-
S::Type: directory_state::IsUnset,
121
-
{
122
-
/// Set the `type` field (required)
123
-
pub fn r#type(
124
-
mut self,
125
-
value: impl Into<jacquard_common::CowStr<'a>>,
126
-
) -> DirectoryBuilder<'a, directory_state::SetType<S>> {
127
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
128
-
DirectoryBuilder {
129
-
_phantom_state: ::core::marker::PhantomData,
130
-
__unsafe_private_named: self.__unsafe_private_named,
131
-
_phantom: ::core::marker::PhantomData,
132
-
}
133
-
}
134
-
}
135
-
136
-
impl<'a, S> DirectoryBuilder<'a, S>
137
-
where
138
-
S: directory_state::State,
139
-
S::Type: directory_state::IsSet,
140
-
S::Entries: directory_state::IsSet,
141
-
{
142
-
/// Build the final struct
143
-
pub fn build(self) -> Directory<'a> {
144
-
Directory {
145
-
entries: self.__unsafe_private_named.0.unwrap(),
146
-
r#type: self.__unsafe_private_named.1.unwrap(),
147
-
extra_data: Default::default(),
148
-
}
149
-
}
150
-
/// Build the final struct with custom extra_data
151
-
pub fn build_with_data(
152
-
self,
153
-
extra_data: std::collections::BTreeMap<
154
-
jacquard_common::smol_str::SmolStr,
155
-
jacquard_common::types::value::Data<'a>,
156
-
>,
157
-
) -> Directory<'a> {
158
-
Directory {
159
-
entries: self.__unsafe_private_named.0.unwrap(),
160
-
r#type: self.__unsafe_private_named.1.unwrap(),
161
-
extra_data: Some(extra_data),
162
-
}
163
-
}
164
-
}
165
-
166
-
fn lexicon_doc_place_wisp_subfs() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
167
-
::jacquard_lexicon::lexicon::LexiconDoc {
168
-
lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1,
169
-
id: ::jacquard_common::CowStr::new_static("place.wisp.subfs"),
170
-
revision: None,
171
-
description: None,
172
-
defs: {
173
-
let mut map = ::std::collections::BTreeMap::new();
174
-
map.insert(
175
-
::jacquard_common::smol_str::SmolStr::new_static("directory"),
176
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
177
-
description: None,
178
-
required: Some(
179
-
vec![
180
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
181
-
::jacquard_common::smol_str::SmolStr::new_static("entries")
182
-
],
183
-
),
184
-
nullable: None,
185
-
properties: {
186
-
#[allow(unused_mut)]
187
-
let mut map = ::std::collections::BTreeMap::new();
188
-
map.insert(
189
-
::jacquard_common::smol_str::SmolStr::new_static("entries"),
190
-
::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray {
191
-
description: None,
192
-
items: ::jacquard_lexicon::lexicon::LexArrayItem::Ref(::jacquard_lexicon::lexicon::LexRef {
193
-
description: None,
194
-
r#ref: ::jacquard_common::CowStr::new_static("#entry"),
195
-
}),
196
-
min_length: None,
197
-
max_length: Some(500usize),
198
-
}),
199
-
);
200
-
map.insert(
201
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
202
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
203
-
description: None,
204
-
format: None,
205
-
default: None,
206
-
min_length: None,
207
-
max_length: None,
208
-
min_graphemes: None,
209
-
max_graphemes: None,
210
-
r#enum: None,
211
-
r#const: None,
212
-
known_values: None,
213
-
}),
214
-
);
215
-
map
216
-
},
217
-
}),
218
-
);
219
-
map.insert(
220
-
::jacquard_common::smol_str::SmolStr::new_static("entry"),
221
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
222
-
description: None,
223
-
required: Some(
224
-
vec![
225
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
226
-
::jacquard_common::smol_str::SmolStr::new_static("node")
227
-
],
228
-
),
229
-
nullable: None,
230
-
properties: {
231
-
#[allow(unused_mut)]
232
-
let mut map = ::std::collections::BTreeMap::new();
233
-
map.insert(
234
-
::jacquard_common::smol_str::SmolStr::new_static("name"),
235
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
236
-
description: None,
237
-
format: None,
238
-
default: None,
239
-
min_length: None,
240
-
max_length: Some(255usize),
241
-
min_graphemes: None,
242
-
max_graphemes: None,
243
-
r#enum: None,
244
-
r#const: None,
245
-
known_values: None,
246
-
}),
247
-
);
248
-
map.insert(
249
-
::jacquard_common::smol_str::SmolStr::new_static("node"),
250
-
::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion {
251
-
description: None,
252
-
refs: vec![
253
-
::jacquard_common::CowStr::new_static("#file"),
254
-
::jacquard_common::CowStr::new_static("#directory"),
255
-
::jacquard_common::CowStr::new_static("#subfs")
256
-
],
257
-
closed: None,
258
-
}),
259
-
);
260
-
map
261
-
},
262
-
}),
263
-
);
264
-
map.insert(
265
-
::jacquard_common::smol_str::SmolStr::new_static("file"),
266
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
267
-
description: None,
268
-
required: Some(
269
-
vec![
270
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
271
-
::jacquard_common::smol_str::SmolStr::new_static("blob")
272
-
],
273
-
),
274
-
nullable: None,
275
-
properties: {
276
-
#[allow(unused_mut)]
277
-
let mut map = ::std::collections::BTreeMap::new();
278
-
map.insert(
279
-
::jacquard_common::smol_str::SmolStr::new_static("base64"),
280
-
::jacquard_lexicon::lexicon::LexObjectProperty::Boolean(::jacquard_lexicon::lexicon::LexBoolean {
281
-
description: None,
282
-
default: None,
283
-
r#const: None,
284
-
}),
285
-
);
286
-
map.insert(
287
-
::jacquard_common::smol_str::SmolStr::new_static("blob"),
288
-
::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob {
289
-
description: None,
290
-
accept: None,
291
-
max_size: None,
292
-
}),
293
-
);
294
-
map.insert(
295
-
::jacquard_common::smol_str::SmolStr::new_static("encoding"),
296
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
297
-
description: Some(
298
-
::jacquard_common::CowStr::new_static(
299
-
"Content encoding (e.g., gzip for compressed files)",
300
-
),
301
-
),
302
-
format: None,
303
-
default: None,
304
-
min_length: None,
305
-
max_length: None,
306
-
min_graphemes: None,
307
-
max_graphemes: None,
308
-
r#enum: None,
309
-
r#const: None,
310
-
known_values: None,
311
-
}),
312
-
);
313
-
map.insert(
314
-
::jacquard_common::smol_str::SmolStr::new_static("mimeType"),
315
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
316
-
description: Some(
317
-
::jacquard_common::CowStr::new_static(
318
-
"Original MIME type before compression",
319
-
),
320
-
),
321
-
format: None,
322
-
default: None,
323
-
min_length: None,
324
-
max_length: None,
325
-
min_graphemes: None,
326
-
max_graphemes: None,
327
-
r#enum: None,
328
-
r#const: None,
329
-
known_values: None,
330
-
}),
331
-
);
332
-
map.insert(
333
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
334
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
335
-
description: None,
336
-
format: None,
337
-
default: None,
338
-
min_length: None,
339
-
max_length: None,
340
-
min_graphemes: None,
341
-
max_graphemes: None,
342
-
r#enum: None,
343
-
r#const: None,
344
-
known_values: None,
345
-
}),
346
-
);
347
-
map
348
-
},
349
-
}),
350
-
);
351
-
map.insert(
352
-
::jacquard_common::smol_str::SmolStr::new_static("main"),
353
-
::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord {
354
-
description: Some(
355
-
::jacquard_common::CowStr::new_static(
356
-
"Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.",
357
-
),
358
-
),
359
-
key: None,
360
-
record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject {
361
-
description: None,
362
-
required: Some(
363
-
vec![
364
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
365
-
::jacquard_common::smol_str::SmolStr::new_static("createdAt")
366
-
],
367
-
),
368
-
nullable: None,
369
-
properties: {
370
-
#[allow(unused_mut)]
371
-
let mut map = ::std::collections::BTreeMap::new();
372
-
map.insert(
373
-
::jacquard_common::smol_str::SmolStr::new_static(
374
-
"createdAt",
375
-
),
376
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
377
-
description: None,
378
-
format: Some(
379
-
::jacquard_lexicon::lexicon::LexStringFormat::Datetime,
380
-
),
381
-
default: None,
382
-
min_length: None,
383
-
max_length: None,
384
-
min_graphemes: None,
385
-
max_graphemes: None,
386
-
r#enum: None,
387
-
r#const: None,
388
-
known_values: None,
389
-
}),
390
-
);
391
-
map.insert(
392
-
::jacquard_common::smol_str::SmolStr::new_static(
393
-
"fileCount",
394
-
),
395
-
::jacquard_lexicon::lexicon::LexObjectProperty::Integer(::jacquard_lexicon::lexicon::LexInteger {
396
-
description: None,
397
-
default: None,
398
-
minimum: Some(0i64),
399
-
maximum: Some(1000i64),
400
-
r#enum: None,
401
-
r#const: None,
402
-
}),
403
-
);
404
-
map.insert(
405
-
::jacquard_common::smol_str::SmolStr::new_static("root"),
406
-
::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef {
407
-
description: None,
408
-
r#ref: ::jacquard_common::CowStr::new_static("#directory"),
409
-
}),
410
-
);
411
-
map
412
-
},
413
-
}),
414
-
}),
415
-
);
416
-
map.insert(
417
-
::jacquard_common::smol_str::SmolStr::new_static("subfs"),
418
-
::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject {
419
-
description: None,
420
-
required: Some(
421
-
vec![
422
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
423
-
::jacquard_common::smol_str::SmolStr::new_static("subject")
424
-
],
425
-
),
426
-
nullable: None,
427
-
properties: {
428
-
#[allow(unused_mut)]
429
-
let mut map = ::std::collections::BTreeMap::new();
430
-
map.insert(
431
-
::jacquard_common::smol_str::SmolStr::new_static("subject"),
432
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
433
-
description: Some(
434
-
::jacquard_common::CowStr::new_static(
435
-
"AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.",
436
-
),
437
-
),
438
-
format: Some(
439
-
::jacquard_lexicon::lexicon::LexStringFormat::AtUri,
440
-
),
441
-
default: None,
442
-
min_length: None,
443
-
max_length: None,
444
-
min_graphemes: None,
445
-
max_graphemes: None,
446
-
r#enum: None,
447
-
r#const: None,
448
-
known_values: None,
449
-
}),
450
-
);
451
-
map.insert(
452
-
::jacquard_common::smol_str::SmolStr::new_static("type"),
453
-
::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString {
454
-
description: None,
455
-
format: None,
456
-
default: None,
457
-
min_length: None,
458
-
max_length: None,
459
-
min_graphemes: None,
460
-
max_graphemes: None,
461
-
r#enum: None,
462
-
r#const: None,
463
-
known_values: None,
464
-
}),
465
-
);
466
-
map
467
-
},
468
-
}),
469
-
);
470
-
map
471
-
},
472
-
}
473
-
}
474
-
475
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Directory<'a> {
476
-
fn nsid() -> &'static str {
477
-
"place.wisp.subfs"
478
-
}
479
-
fn def_name() -> &'static str {
480
-
"directory"
481
-
}
482
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
483
-
lexicon_doc_place_wisp_subfs()
484
-
}
485
-
fn validate(
486
-
&self,
487
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
488
-
{
489
-
let value = &self.entries;
490
-
#[allow(unused_comparisons)]
491
-
if value.len() > 500usize {
492
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
493
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
494
-
"entries",
495
-
),
496
-
max: 500usize,
497
-
actual: value.len(),
498
-
});
499
-
}
500
-
}
501
-
Ok(())
502
-
}
503
-
}
504
-
505
-
#[jacquard_derive::lexicon]
506
-
#[derive(
507
-
serde::Serialize,
508
-
serde::Deserialize,
509
-
Debug,
510
-
Clone,
511
-
PartialEq,
512
-
Eq,
513
-
jacquard_derive::IntoStatic
514
-
)]
515
-
#[serde(rename_all = "camelCase")]
516
-
pub struct Entry<'a> {
517
-
#[serde(borrow)]
518
-
pub name: jacquard_common::CowStr<'a>,
519
-
#[serde(borrow)]
520
-
pub node: EntryNode<'a>,
521
-
}
522
-
523
-
pub mod entry_state {
524
-
525
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
526
-
#[allow(unused)]
527
-
use ::core::marker::PhantomData;
528
-
mod sealed {
529
-
pub trait Sealed {}
530
-
}
531
-
/// State trait tracking which required fields have been set
532
-
pub trait State: sealed::Sealed {
533
-
type Name;
534
-
type Node;
535
-
}
536
-
/// Empty state - all required fields are unset
537
-
pub struct Empty(());
538
-
impl sealed::Sealed for Empty {}
539
-
impl State for Empty {
540
-
type Name = Unset;
541
-
type Node = Unset;
542
-
}
543
-
///State transition - sets the `name` field to Set
544
-
pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
545
-
impl<S: State> sealed::Sealed for SetName<S> {}
546
-
impl<S: State> State for SetName<S> {
547
-
type Name = Set<members::name>;
548
-
type Node = S::Node;
549
-
}
550
-
///State transition - sets the `node` field to Set
551
-
pub struct SetNode<S: State = Empty>(PhantomData<fn() -> S>);
552
-
impl<S: State> sealed::Sealed for SetNode<S> {}
553
-
impl<S: State> State for SetNode<S> {
554
-
type Name = S::Name;
555
-
type Node = Set<members::node>;
556
-
}
557
-
/// Marker types for field names
558
-
#[allow(non_camel_case_types)]
559
-
pub mod members {
560
-
///Marker type for the `name` field
561
-
pub struct name(());
562
-
///Marker type for the `node` field
563
-
pub struct node(());
564
-
}
565
-
}
566
-
567
-
/// Builder for constructing an instance of this type
568
-
pub struct EntryBuilder<'a, S: entry_state::State> {
569
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
570
-
__unsafe_private_named: (
571
-
::core::option::Option<jacquard_common::CowStr<'a>>,
572
-
::core::option::Option<EntryNode<'a>>,
573
-
),
574
-
_phantom: ::core::marker::PhantomData<&'a ()>,
575
-
}
576
-
577
-
impl<'a> Entry<'a> {
578
-
/// Create a new builder for this type
579
-
pub fn new() -> EntryBuilder<'a, entry_state::Empty> {
580
-
EntryBuilder::new()
581
-
}
582
-
}
583
-
584
-
impl<'a> EntryBuilder<'a, entry_state::Empty> {
585
-
/// Create a new builder with all fields unset
586
-
pub fn new() -> Self {
587
-
EntryBuilder {
588
-
_phantom_state: ::core::marker::PhantomData,
589
-
__unsafe_private_named: (None, None),
590
-
_phantom: ::core::marker::PhantomData,
591
-
}
592
-
}
593
-
}
594
-
595
-
impl<'a, S> EntryBuilder<'a, S>
596
-
where
597
-
S: entry_state::State,
598
-
S::Name: entry_state::IsUnset,
599
-
{
600
-
/// Set the `name` field (required)
601
-
pub fn name(
602
-
mut self,
603
-
value: impl Into<jacquard_common::CowStr<'a>>,
604
-
) -> EntryBuilder<'a, entry_state::SetName<S>> {
605
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
606
-
EntryBuilder {
607
-
_phantom_state: ::core::marker::PhantomData,
608
-
__unsafe_private_named: self.__unsafe_private_named,
609
-
_phantom: ::core::marker::PhantomData,
610
-
}
611
-
}
612
-
}
613
-
614
-
impl<'a, S> EntryBuilder<'a, S>
615
-
where
616
-
S: entry_state::State,
617
-
S::Node: entry_state::IsUnset,
618
-
{
619
-
/// Set the `node` field (required)
620
-
pub fn node(
621
-
mut self,
622
-
value: impl Into<EntryNode<'a>>,
623
-
) -> EntryBuilder<'a, entry_state::SetNode<S>> {
624
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
625
-
EntryBuilder {
626
-
_phantom_state: ::core::marker::PhantomData,
627
-
__unsafe_private_named: self.__unsafe_private_named,
628
-
_phantom: ::core::marker::PhantomData,
629
-
}
630
-
}
631
-
}
632
-
633
-
impl<'a, S> EntryBuilder<'a, S>
634
-
where
635
-
S: entry_state::State,
636
-
S::Name: entry_state::IsSet,
637
-
S::Node: entry_state::IsSet,
638
-
{
639
-
/// Build the final struct
640
-
pub fn build(self) -> Entry<'a> {
641
-
Entry {
642
-
name: self.__unsafe_private_named.0.unwrap(),
643
-
node: self.__unsafe_private_named.1.unwrap(),
644
-
extra_data: Default::default(),
645
-
}
646
-
}
647
-
/// Build the final struct with custom extra_data
648
-
pub fn build_with_data(
649
-
self,
650
-
extra_data: std::collections::BTreeMap<
651
-
jacquard_common::smol_str::SmolStr,
652
-
jacquard_common::types::value::Data<'a>,
653
-
>,
654
-
) -> Entry<'a> {
655
-
Entry {
656
-
name: self.__unsafe_private_named.0.unwrap(),
657
-
node: self.__unsafe_private_named.1.unwrap(),
658
-
extra_data: Some(extra_data),
659
-
}
660
-
}
661
-
}
662
-
663
-
#[jacquard_derive::open_union]
664
-
#[derive(
665
-
serde::Serialize,
666
-
serde::Deserialize,
667
-
Debug,
668
-
Clone,
669
-
PartialEq,
670
-
Eq,
671
-
jacquard_derive::IntoStatic
672
-
)]
673
-
#[serde(tag = "$type")]
674
-
#[serde(bound(deserialize = "'de: 'a"))]
675
-
pub enum EntryNode<'a> {
676
-
#[serde(rename = "place.wisp.subfs#file")]
677
-
File(Box<crate::place_wisp::subfs::File<'a>>),
678
-
#[serde(rename = "place.wisp.subfs#directory")]
679
-
Directory(Box<crate::place_wisp::subfs::Directory<'a>>),
680
-
#[serde(rename = "place.wisp.subfs#subfs")]
681
-
Subfs(Box<crate::place_wisp::subfs::Subfs<'a>>),
682
-
}
683
-
684
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Entry<'a> {
685
-
fn nsid() -> &'static str {
686
-
"place.wisp.subfs"
687
-
}
688
-
fn def_name() -> &'static str {
689
-
"entry"
690
-
}
691
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
692
-
lexicon_doc_place_wisp_subfs()
693
-
}
694
-
fn validate(
695
-
&self,
696
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
697
-
{
698
-
let value = &self.name;
699
-
#[allow(unused_comparisons)]
700
-
if <str>::len(value.as_ref()) > 255usize {
701
-
return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength {
702
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
703
-
"name",
704
-
),
705
-
max: 255usize,
706
-
actual: <str>::len(value.as_ref()),
707
-
});
708
-
}
709
-
}
710
-
Ok(())
711
-
}
712
-
}
713
-
714
-
#[jacquard_derive::lexicon]
715
-
#[derive(
716
-
serde::Serialize,
717
-
serde::Deserialize,
718
-
Debug,
719
-
Clone,
720
-
PartialEq,
721
-
Eq,
722
-
jacquard_derive::IntoStatic
723
-
)]
724
-
#[serde(rename_all = "camelCase")]
725
-
pub struct File<'a> {
726
-
/// True if blob content is base64-encoded (used to bypass PDS content sniffing)
727
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
728
-
pub base64: Option<bool>,
729
-
/// Content blob ref
730
-
#[serde(borrow)]
731
-
pub blob: jacquard_common::types::blob::BlobRef<'a>,
732
-
/// Content encoding (e.g., gzip for compressed files)
733
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
734
-
#[serde(borrow)]
735
-
pub encoding: Option<jacquard_common::CowStr<'a>>,
736
-
/// Original MIME type before compression
737
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
738
-
#[serde(borrow)]
739
-
pub mime_type: Option<jacquard_common::CowStr<'a>>,
740
-
#[serde(borrow)]
741
-
pub r#type: jacquard_common::CowStr<'a>,
742
-
}
743
-
744
-
pub mod file_state {
745
-
746
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
747
-
#[allow(unused)]
748
-
use ::core::marker::PhantomData;
749
-
mod sealed {
750
-
pub trait Sealed {}
751
-
}
752
-
/// State trait tracking which required fields have been set
753
-
pub trait State: sealed::Sealed {
754
-
type Type;
755
-
type Blob;
756
-
}
757
-
/// Empty state - all required fields are unset
758
-
pub struct Empty(());
759
-
impl sealed::Sealed for Empty {}
760
-
impl State for Empty {
761
-
type Type = Unset;
762
-
type Blob = Unset;
763
-
}
764
-
///State transition - sets the `type` field to Set
765
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
766
-
impl<S: State> sealed::Sealed for SetType<S> {}
767
-
impl<S: State> State for SetType<S> {
768
-
type Type = Set<members::r#type>;
769
-
type Blob = S::Blob;
770
-
}
771
-
///State transition - sets the `blob` field to Set
772
-
pub struct SetBlob<S: State = Empty>(PhantomData<fn() -> S>);
773
-
impl<S: State> sealed::Sealed for SetBlob<S> {}
774
-
impl<S: State> State for SetBlob<S> {
775
-
type Type = S::Type;
776
-
type Blob = Set<members::blob>;
777
-
}
778
-
/// Marker types for field names
779
-
#[allow(non_camel_case_types)]
780
-
pub mod members {
781
-
///Marker type for the `type` field
782
-
pub struct r#type(());
783
-
///Marker type for the `blob` field
784
-
pub struct blob(());
785
-
}
786
-
}
787
-
788
-
/// Builder for constructing an instance of this type
789
-
pub struct FileBuilder<'a, S: file_state::State> {
790
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
791
-
__unsafe_private_named: (
792
-
::core::option::Option<bool>,
793
-
::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>,
794
-
::core::option::Option<jacquard_common::CowStr<'a>>,
795
-
::core::option::Option<jacquard_common::CowStr<'a>>,
796
-
::core::option::Option<jacquard_common::CowStr<'a>>,
797
-
),
798
-
_phantom: ::core::marker::PhantomData<&'a ()>,
799
-
}
800
-
801
-
impl<'a> File<'a> {
802
-
/// Create a new builder for this type
803
-
pub fn new() -> FileBuilder<'a, file_state::Empty> {
804
-
FileBuilder::new()
805
-
}
806
-
}
807
-
808
-
impl<'a> FileBuilder<'a, file_state::Empty> {
809
-
/// Create a new builder with all fields unset
810
-
pub fn new() -> Self {
811
-
FileBuilder {
812
-
_phantom_state: ::core::marker::PhantomData,
813
-
__unsafe_private_named: (None, None, None, None, None),
814
-
_phantom: ::core::marker::PhantomData,
815
-
}
816
-
}
817
-
}
818
-
819
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
820
-
/// Set the `base64` field (optional)
821
-
pub fn base64(mut self, value: impl Into<Option<bool>>) -> Self {
822
-
self.__unsafe_private_named.0 = value.into();
823
-
self
824
-
}
825
-
/// Set the `base64` field to an Option value (optional)
826
-
pub fn maybe_base64(mut self, value: Option<bool>) -> Self {
827
-
self.__unsafe_private_named.0 = value;
828
-
self
829
-
}
830
-
}
831
-
832
-
impl<'a, S> FileBuilder<'a, S>
833
-
where
834
-
S: file_state::State,
835
-
S::Blob: file_state::IsUnset,
836
-
{
837
-
/// Set the `blob` field (required)
838
-
pub fn blob(
839
-
mut self,
840
-
value: impl Into<jacquard_common::types::blob::BlobRef<'a>>,
841
-
) -> FileBuilder<'a, file_state::SetBlob<S>> {
842
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
843
-
FileBuilder {
844
-
_phantom_state: ::core::marker::PhantomData,
845
-
__unsafe_private_named: self.__unsafe_private_named,
846
-
_phantom: ::core::marker::PhantomData,
847
-
}
848
-
}
849
-
}
850
-
851
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
852
-
/// Set the `encoding` field (optional)
853
-
pub fn encoding(
854
-
mut self,
855
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
856
-
) -> Self {
857
-
self.__unsafe_private_named.2 = value.into();
858
-
self
859
-
}
860
-
/// Set the `encoding` field to an Option value (optional)
861
-
pub fn maybe_encoding(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self {
862
-
self.__unsafe_private_named.2 = value;
863
-
self
864
-
}
865
-
}
866
-
867
-
impl<'a, S: file_state::State> FileBuilder<'a, S> {
868
-
/// Set the `mimeType` field (optional)
869
-
pub fn mime_type(
870
-
mut self,
871
-
value: impl Into<Option<jacquard_common::CowStr<'a>>>,
872
-
) -> Self {
873
-
self.__unsafe_private_named.3 = value.into();
874
-
self
875
-
}
876
-
/// Set the `mimeType` field to an Option value (optional)
877
-
pub fn maybe_mime_type(
878
-
mut self,
879
-
value: Option<jacquard_common::CowStr<'a>>,
880
-
) -> Self {
881
-
self.__unsafe_private_named.3 = value;
882
-
self
883
-
}
884
-
}
885
-
886
-
impl<'a, S> FileBuilder<'a, S>
887
-
where
888
-
S: file_state::State,
889
-
S::Type: file_state::IsUnset,
890
-
{
891
-
/// Set the `type` field (required)
892
-
pub fn r#type(
893
-
mut self,
894
-
value: impl Into<jacquard_common::CowStr<'a>>,
895
-
) -> FileBuilder<'a, file_state::SetType<S>> {
896
-
self.__unsafe_private_named.4 = ::core::option::Option::Some(value.into());
897
-
FileBuilder {
898
-
_phantom_state: ::core::marker::PhantomData,
899
-
__unsafe_private_named: self.__unsafe_private_named,
900
-
_phantom: ::core::marker::PhantomData,
901
-
}
902
-
}
903
-
}
904
-
905
-
impl<'a, S> FileBuilder<'a, S>
906
-
where
907
-
S: file_state::State,
908
-
S::Type: file_state::IsSet,
909
-
S::Blob: file_state::IsSet,
910
-
{
911
-
/// Build the final struct
912
-
pub fn build(self) -> File<'a> {
913
-
File {
914
-
base64: self.__unsafe_private_named.0,
915
-
blob: self.__unsafe_private_named.1.unwrap(),
916
-
encoding: self.__unsafe_private_named.2,
917
-
mime_type: self.__unsafe_private_named.3,
918
-
r#type: self.__unsafe_private_named.4.unwrap(),
919
-
extra_data: Default::default(),
920
-
}
921
-
}
922
-
/// Build the final struct with custom extra_data
923
-
pub fn build_with_data(
924
-
self,
925
-
extra_data: std::collections::BTreeMap<
926
-
jacquard_common::smol_str::SmolStr,
927
-
jacquard_common::types::value::Data<'a>,
928
-
>,
929
-
) -> File<'a> {
930
-
File {
931
-
base64: self.__unsafe_private_named.0,
932
-
blob: self.__unsafe_private_named.1.unwrap(),
933
-
encoding: self.__unsafe_private_named.2,
934
-
mime_type: self.__unsafe_private_named.3,
935
-
r#type: self.__unsafe_private_named.4.unwrap(),
936
-
extra_data: Some(extra_data),
937
-
}
938
-
}
939
-
}
940
-
941
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for File<'a> {
942
-
fn nsid() -> &'static str {
943
-
"place.wisp.subfs"
944
-
}
945
-
fn def_name() -> &'static str {
946
-
"file"
947
-
}
948
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
949
-
lexicon_doc_place_wisp_subfs()
950
-
}
951
-
fn validate(
952
-
&self,
953
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
954
-
Ok(())
955
-
}
956
-
}
957
-
958
-
/// Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.
959
-
#[jacquard_derive::lexicon]
960
-
#[derive(
961
-
serde::Serialize,
962
-
serde::Deserialize,
963
-
Debug,
964
-
Clone,
965
-
PartialEq,
966
-
Eq,
967
-
jacquard_derive::IntoStatic
968
-
)]
969
-
#[serde(rename_all = "camelCase")]
970
-
pub struct SubfsRecord<'a> {
971
-
pub created_at: jacquard_common::types::string::Datetime,
972
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
973
-
pub file_count: Option<i64>,
974
-
#[serde(borrow)]
975
-
pub root: crate::place_wisp::subfs::Directory<'a>,
976
-
}
977
-
978
-
pub mod subfs_record_state {
979
-
980
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
981
-
#[allow(unused)]
982
-
use ::core::marker::PhantomData;
983
-
mod sealed {
984
-
pub trait Sealed {}
985
-
}
986
-
/// State trait tracking which required fields have been set
987
-
pub trait State: sealed::Sealed {
988
-
type Root;
989
-
type CreatedAt;
990
-
}
991
-
/// Empty state - all required fields are unset
992
-
pub struct Empty(());
993
-
impl sealed::Sealed for Empty {}
994
-
impl State for Empty {
995
-
type Root = Unset;
996
-
type CreatedAt = Unset;
997
-
}
998
-
///State transition - sets the `root` field to Set
999
-
pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
1000
-
impl<S: State> sealed::Sealed for SetRoot<S> {}
1001
-
impl<S: State> State for SetRoot<S> {
1002
-
type Root = Set<members::root>;
1003
-
type CreatedAt = S::CreatedAt;
1004
-
}
1005
-
///State transition - sets the `created_at` field to Set
1006
-
pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
1007
-
impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
1008
-
impl<S: State> State for SetCreatedAt<S> {
1009
-
type Root = S::Root;
1010
-
type CreatedAt = Set<members::created_at>;
1011
-
}
1012
-
/// Marker types for field names
1013
-
#[allow(non_camel_case_types)]
1014
-
pub mod members {
1015
-
///Marker type for the `root` field
1016
-
pub struct root(());
1017
-
///Marker type for the `created_at` field
1018
-
pub struct created_at(());
1019
-
}
1020
-
}
1021
-
1022
-
/// Builder for constructing an instance of this type
1023
-
pub struct SubfsRecordBuilder<'a, S: subfs_record_state::State> {
1024
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1025
-
__unsafe_private_named: (
1026
-
::core::option::Option<jacquard_common::types::string::Datetime>,
1027
-
::core::option::Option<i64>,
1028
-
::core::option::Option<crate::place_wisp::subfs::Directory<'a>>,
1029
-
),
1030
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1031
-
}
1032
-
1033
-
impl<'a> SubfsRecord<'a> {
1034
-
/// Create a new builder for this type
1035
-
pub fn new() -> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1036
-
SubfsRecordBuilder::new()
1037
-
}
1038
-
}
1039
-
1040
-
impl<'a> SubfsRecordBuilder<'a, subfs_record_state::Empty> {
1041
-
/// Create a new builder with all fields unset
1042
-
pub fn new() -> Self {
1043
-
SubfsRecordBuilder {
1044
-
_phantom_state: ::core::marker::PhantomData,
1045
-
__unsafe_private_named: (None, None, None),
1046
-
_phantom: ::core::marker::PhantomData,
1047
-
}
1048
-
}
1049
-
}
1050
-
1051
-
impl<'a, S> SubfsRecordBuilder<'a, S>
1052
-
where
1053
-
S: subfs_record_state::State,
1054
-
S::CreatedAt: subfs_record_state::IsUnset,
1055
-
{
1056
-
/// Set the `createdAt` field (required)
1057
-
pub fn created_at(
1058
-
mut self,
1059
-
value: impl Into<jacquard_common::types::string::Datetime>,
1060
-
) -> SubfsRecordBuilder<'a, subfs_record_state::SetCreatedAt<S>> {
1061
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1062
-
SubfsRecordBuilder {
1063
-
_phantom_state: ::core::marker::PhantomData,
1064
-
__unsafe_private_named: self.__unsafe_private_named,
1065
-
_phantom: ::core::marker::PhantomData,
1066
-
}
1067
-
}
1068
-
}
1069
-
1070
-
impl<'a, S: subfs_record_state::State> SubfsRecordBuilder<'a, S> {
1071
-
/// Set the `fileCount` field (optional)
1072
-
pub fn file_count(mut self, value: impl Into<Option<i64>>) -> Self {
1073
-
self.__unsafe_private_named.1 = value.into();
1074
-
self
1075
-
}
1076
-
/// Set the `fileCount` field to an Option value (optional)
1077
-
pub fn maybe_file_count(mut self, value: Option<i64>) -> Self {
1078
-
self.__unsafe_private_named.1 = value;
1079
-
self
1080
-
}
1081
-
}
1082
-
1083
-
impl<'a, S> SubfsRecordBuilder<'a, S>
1084
-
where
1085
-
S: subfs_record_state::State,
1086
-
S::Root: subfs_record_state::IsUnset,
1087
-
{
1088
-
/// Set the `root` field (required)
1089
-
pub fn root(
1090
-
mut self,
1091
-
value: impl Into<crate::place_wisp::subfs::Directory<'a>>,
1092
-
) -> SubfsRecordBuilder<'a, subfs_record_state::SetRoot<S>> {
1093
-
self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into());
1094
-
SubfsRecordBuilder {
1095
-
_phantom_state: ::core::marker::PhantomData,
1096
-
__unsafe_private_named: self.__unsafe_private_named,
1097
-
_phantom: ::core::marker::PhantomData,
1098
-
}
1099
-
}
1100
-
}
1101
-
1102
-
impl<'a, S> SubfsRecordBuilder<'a, S>
1103
-
where
1104
-
S: subfs_record_state::State,
1105
-
S::Root: subfs_record_state::IsSet,
1106
-
S::CreatedAt: subfs_record_state::IsSet,
1107
-
{
1108
-
/// Build the final struct
1109
-
pub fn build(self) -> SubfsRecord<'a> {
1110
-
SubfsRecord {
1111
-
created_at: self.__unsafe_private_named.0.unwrap(),
1112
-
file_count: self.__unsafe_private_named.1,
1113
-
root: self.__unsafe_private_named.2.unwrap(),
1114
-
extra_data: Default::default(),
1115
-
}
1116
-
}
1117
-
/// Build the final struct with custom extra_data
1118
-
pub fn build_with_data(
1119
-
self,
1120
-
extra_data: std::collections::BTreeMap<
1121
-
jacquard_common::smol_str::SmolStr,
1122
-
jacquard_common::types::value::Data<'a>,
1123
-
>,
1124
-
) -> SubfsRecord<'a> {
1125
-
SubfsRecord {
1126
-
created_at: self.__unsafe_private_named.0.unwrap(),
1127
-
file_count: self.__unsafe_private_named.1,
1128
-
root: self.__unsafe_private_named.2.unwrap(),
1129
-
extra_data: Some(extra_data),
1130
-
}
1131
-
}
1132
-
}
1133
-
1134
-
impl<'a> SubfsRecord<'a> {
1135
-
pub fn uri(
1136
-
uri: impl Into<jacquard_common::CowStr<'a>>,
1137
-
) -> Result<
1138
-
jacquard_common::types::uri::RecordUri<'a, SubfsRecordRecord>,
1139
-
jacquard_common::types::uri::UriError,
1140
-
> {
1141
-
jacquard_common::types::uri::RecordUri::try_from_uri(
1142
-
jacquard_common::types::string::AtUri::new_cow(uri.into())?,
1143
-
)
1144
-
}
1145
-
}
1146
-
1147
-
/// Typed wrapper for GetRecord response with this collection's record type.
1148
-
#[derive(
1149
-
serde::Serialize,
1150
-
serde::Deserialize,
1151
-
Debug,
1152
-
Clone,
1153
-
PartialEq,
1154
-
Eq,
1155
-
jacquard_derive::IntoStatic
1156
-
)]
1157
-
#[serde(rename_all = "camelCase")]
1158
-
pub struct SubfsRecordGetRecordOutput<'a> {
1159
-
#[serde(skip_serializing_if = "std::option::Option::is_none")]
1160
-
#[serde(borrow)]
1161
-
pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>,
1162
-
#[serde(borrow)]
1163
-
pub uri: jacquard_common::types::string::AtUri<'a>,
1164
-
#[serde(borrow)]
1165
-
pub value: SubfsRecord<'a>,
1166
-
}
1167
-
1168
-
impl From<SubfsRecordGetRecordOutput<'_>> for SubfsRecord<'_> {
1169
-
fn from(output: SubfsRecordGetRecordOutput<'_>) -> Self {
1170
-
use jacquard_common::IntoStatic;
1171
-
output.value.into_static()
1172
-
}
1173
-
}
1174
-
1175
-
impl jacquard_common::types::collection::Collection for SubfsRecord<'_> {
1176
-
const NSID: &'static str = "place.wisp.subfs";
1177
-
type Record = SubfsRecordRecord;
1178
-
}
1179
-
1180
-
/// Marker type for deserializing records from this collection.
1181
-
#[derive(Debug, serde::Serialize, serde::Deserialize)]
1182
-
pub struct SubfsRecordRecord;
1183
-
impl jacquard_common::xrpc::XrpcResp for SubfsRecordRecord {
1184
-
const NSID: &'static str = "place.wisp.subfs";
1185
-
const ENCODING: &'static str = "application/json";
1186
-
type Output<'de> = SubfsRecordGetRecordOutput<'de>;
1187
-
type Err<'de> = jacquard_common::types::collection::RecordError<'de>;
1188
-
}
1189
-
1190
-
impl jacquard_common::types::collection::Collection for SubfsRecordRecord {
1191
-
const NSID: &'static str = "place.wisp.subfs";
1192
-
type Record = SubfsRecordRecord;
1193
-
}
1194
-
1195
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for SubfsRecord<'a> {
1196
-
fn nsid() -> &'static str {
1197
-
"place.wisp.subfs"
1198
-
}
1199
-
fn def_name() -> &'static str {
1200
-
"main"
1201
-
}
1202
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1203
-
lexicon_doc_place_wisp_subfs()
1204
-
}
1205
-
fn validate(
1206
-
&self,
1207
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1208
-
if let Some(ref value) = self.file_count {
1209
-
if *value > 1000i64 {
1210
-
return Err(::jacquard_lexicon::validation::ConstraintError::Maximum {
1211
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1212
-
"file_count",
1213
-
),
1214
-
max: 1000i64,
1215
-
actual: *value,
1216
-
});
1217
-
}
1218
-
}
1219
-
if let Some(ref value) = self.file_count {
1220
-
if *value < 0i64 {
1221
-
return Err(::jacquard_lexicon::validation::ConstraintError::Minimum {
1222
-
path: ::jacquard_lexicon::validation::ValidationPath::from_field(
1223
-
"file_count",
1224
-
),
1225
-
min: 0i64,
1226
-
actual: *value,
1227
-
});
1228
-
}
1229
-
}
1230
-
Ok(())
1231
-
}
1232
-
}
1233
-
1234
-
#[jacquard_derive::lexicon]
1235
-
#[derive(
1236
-
serde::Serialize,
1237
-
serde::Deserialize,
1238
-
Debug,
1239
-
Clone,
1240
-
PartialEq,
1241
-
Eq,
1242
-
jacquard_derive::IntoStatic
1243
-
)]
1244
-
#[serde(rename_all = "camelCase")]
1245
-
pub struct Subfs<'a> {
1246
-
/// AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.
1247
-
#[serde(borrow)]
1248
-
pub subject: jacquard_common::types::string::AtUri<'a>,
1249
-
#[serde(borrow)]
1250
-
pub r#type: jacquard_common::CowStr<'a>,
1251
-
}
1252
-
1253
-
pub mod subfs_state {
1254
-
1255
-
pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1256
-
#[allow(unused)]
1257
-
use ::core::marker::PhantomData;
1258
-
mod sealed {
1259
-
pub trait Sealed {}
1260
-
}
1261
-
/// State trait tracking which required fields have been set
1262
-
pub trait State: sealed::Sealed {
1263
-
type Type;
1264
-
type Subject;
1265
-
}
1266
-
/// Empty state - all required fields are unset
1267
-
pub struct Empty(());
1268
-
impl sealed::Sealed for Empty {}
1269
-
impl State for Empty {
1270
-
type Type = Unset;
1271
-
type Subject = Unset;
1272
-
}
1273
-
///State transition - sets the `type` field to Set
1274
-
pub struct SetType<S: State = Empty>(PhantomData<fn() -> S>);
1275
-
impl<S: State> sealed::Sealed for SetType<S> {}
1276
-
impl<S: State> State for SetType<S> {
1277
-
type Type = Set<members::r#type>;
1278
-
type Subject = S::Subject;
1279
-
}
1280
-
///State transition - sets the `subject` field to Set
1281
-
pub struct SetSubject<S: State = Empty>(PhantomData<fn() -> S>);
1282
-
impl<S: State> sealed::Sealed for SetSubject<S> {}
1283
-
impl<S: State> State for SetSubject<S> {
1284
-
type Type = S::Type;
1285
-
type Subject = Set<members::subject>;
1286
-
}
1287
-
/// Marker types for field names
1288
-
#[allow(non_camel_case_types)]
1289
-
pub mod members {
1290
-
///Marker type for the `type` field
1291
-
pub struct r#type(());
1292
-
///Marker type for the `subject` field
1293
-
pub struct subject(());
1294
-
}
1295
-
}
1296
-
1297
-
/// Builder for constructing an instance of this type
1298
-
pub struct SubfsBuilder<'a, S: subfs_state::State> {
1299
-
_phantom_state: ::core::marker::PhantomData<fn() -> S>,
1300
-
__unsafe_private_named: (
1301
-
::core::option::Option<jacquard_common::types::string::AtUri<'a>>,
1302
-
::core::option::Option<jacquard_common::CowStr<'a>>,
1303
-
),
1304
-
_phantom: ::core::marker::PhantomData<&'a ()>,
1305
-
}
1306
-
1307
-
impl<'a> Subfs<'a> {
1308
-
/// Create a new builder for this type
1309
-
pub fn new() -> SubfsBuilder<'a, subfs_state::Empty> {
1310
-
SubfsBuilder::new()
1311
-
}
1312
-
}
1313
-
1314
-
impl<'a> SubfsBuilder<'a, subfs_state::Empty> {
1315
-
/// Create a new builder with all fields unset
1316
-
pub fn new() -> Self {
1317
-
SubfsBuilder {
1318
-
_phantom_state: ::core::marker::PhantomData,
1319
-
__unsafe_private_named: (None, None),
1320
-
_phantom: ::core::marker::PhantomData,
1321
-
}
1322
-
}
1323
-
}
1324
-
1325
-
impl<'a, S> SubfsBuilder<'a, S>
1326
-
where
1327
-
S: subfs_state::State,
1328
-
S::Subject: subfs_state::IsUnset,
1329
-
{
1330
-
/// Set the `subject` field (required)
1331
-
pub fn subject(
1332
-
mut self,
1333
-
value: impl Into<jacquard_common::types::string::AtUri<'a>>,
1334
-
) -> SubfsBuilder<'a, subfs_state::SetSubject<S>> {
1335
-
self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into());
1336
-
SubfsBuilder {
1337
-
_phantom_state: ::core::marker::PhantomData,
1338
-
__unsafe_private_named: self.__unsafe_private_named,
1339
-
_phantom: ::core::marker::PhantomData,
1340
-
}
1341
-
}
1342
-
}
1343
-
1344
-
impl<'a, S> SubfsBuilder<'a, S>
1345
-
where
1346
-
S: subfs_state::State,
1347
-
S::Type: subfs_state::IsUnset,
1348
-
{
1349
-
/// Set the `type` field (required)
1350
-
pub fn r#type(
1351
-
mut self,
1352
-
value: impl Into<jacquard_common::CowStr<'a>>,
1353
-
) -> SubfsBuilder<'a, subfs_state::SetType<S>> {
1354
-
self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into());
1355
-
SubfsBuilder {
1356
-
_phantom_state: ::core::marker::PhantomData,
1357
-
__unsafe_private_named: self.__unsafe_private_named,
1358
-
_phantom: ::core::marker::PhantomData,
1359
-
}
1360
-
}
1361
-
}
1362
-
1363
-
impl<'a, S> SubfsBuilder<'a, S>
1364
-
where
1365
-
S: subfs_state::State,
1366
-
S::Type: subfs_state::IsSet,
1367
-
S::Subject: subfs_state::IsSet,
1368
-
{
1369
-
/// Build the final struct
1370
-
pub fn build(self) -> Subfs<'a> {
1371
-
Subfs {
1372
-
subject: self.__unsafe_private_named.0.unwrap(),
1373
-
r#type: self.__unsafe_private_named.1.unwrap(),
1374
-
extra_data: Default::default(),
1375
-
}
1376
-
}
1377
-
/// Build the final struct with custom extra_data
1378
-
pub fn build_with_data(
1379
-
self,
1380
-
extra_data: std::collections::BTreeMap<
1381
-
jacquard_common::smol_str::SmolStr,
1382
-
jacquard_common::types::value::Data<'a>,
1383
-
>,
1384
-
) -> Subfs<'a> {
1385
-
Subfs {
1386
-
subject: self.__unsafe_private_named.0.unwrap(),
1387
-
r#type: self.__unsafe_private_named.1.unwrap(),
1388
-
extra_data: Some(extra_data),
1389
-
}
1390
-
}
1391
-
}
1392
-
1393
-
impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subfs<'a> {
1394
-
fn nsid() -> &'static str {
1395
-
"place.wisp.subfs"
1396
-
}
1397
-
fn def_name() -> &'static str {
1398
-
"subfs"
1399
-
}
1400
-
fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> {
1401
-
lexicon_doc_place_wisp_subfs()
1402
-
}
1403
-
fn validate(
1404
-
&self,
1405
-
) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> {
1406
-
Ok(())
1407
-
}
1408
-
}
-8
cli/src/place_wisp.rs
-8
cli/src/place_wisp.rs
+12
-12
cli/src/pull.rs
+12
-12
cli/src/pull.rs
···
1
1
use crate::blob_map;
2
2
use crate::download;
3
3
use crate::metadata::SiteMetadata;
4
-
use crate::place_wisp::fs::*;
4
+
use wisp_lexicons::place_wisp::fs::*;
5
5
use crate::subfs_utils;
6
6
use jacquard::CowStr;
7
7
use jacquard::prelude::IdentityResolver;
···
410
410
) -> miette::Result<Directory<'static>> {
411
411
use jacquard_common::IntoStatic;
412
412
use jacquard_common::types::value::from_data;
413
-
use crate::place_wisp::subfs::SubfsRecord;
413
+
use wisp_lexicons::place_wisp::subfs::SubfsRecord;
414
414
415
-
let mut all_subfs_map: HashMap<String, crate::place_wisp::subfs::Directory> = HashMap::new();
415
+
let mut all_subfs_map: HashMap<String, wisp_lexicons::place_wisp::subfs::Directory> = HashMap::new();
416
416
let mut to_fetch = subfs_utils::extract_subfs_uris(directory, String::new());
417
417
418
418
if to_fetch.is_empty() {
···
516
516
517
517
/// Extract subfs URIs from a subfs::Directory (helper for pull)
518
518
fn extract_subfs_uris_from_subfs_dir(
519
-
directory: &crate::place_wisp::subfs::Directory,
519
+
directory: &wisp_lexicons::place_wisp::subfs::Directory,
520
520
current_path: String,
521
521
) -> Vec<(String, String)> {
522
522
let mut uris = Vec::new();
···
529
529
};
530
530
531
531
match &entry.node {
532
-
crate::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
532
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
533
533
uris.push((subfs_node.subject.to_string(), full_path.clone()));
534
534
}
535
-
crate::place_wisp::subfs::EntryNode::Directory(subdir) => {
535
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => {
536
536
let nested = extract_subfs_uris_from_subfs_dir(subdir, full_path);
537
537
uris.extend(nested);
538
538
}
···
546
546
/// Recursively replace subfs nodes with their actual content
547
547
fn replace_subfs_with_content(
548
548
directory: Directory,
549
-
subfs_map: &HashMap<String, crate::place_wisp::subfs::Directory>,
549
+
subfs_map: &HashMap<String, wisp_lexicons::place_wisp::subfs::Directory>,
550
550
current_path: String,
551
551
) -> Directory<'static> {
552
552
use jacquard_common::IntoStatic;
···
628
628
}
629
629
630
630
/// Convert a subfs entry to a fs entry (they have the same structure but different types)
631
-
fn convert_subfs_entry_to_fs(subfs_entry: crate::place_wisp::subfs::Entry<'static>) -> Entry<'static> {
631
+
fn convert_subfs_entry_to_fs(subfs_entry: wisp_lexicons::place_wisp::subfs::Entry<'static>) -> Entry<'static> {
632
632
use jacquard_common::IntoStatic;
633
633
634
634
let node = match subfs_entry.node {
635
-
crate::place_wisp::subfs::EntryNode::File(file) => {
635
+
wisp_lexicons::place_wisp::subfs::EntryNode::File(file) => {
636
636
EntryNode::File(Box::new(
637
637
File::new()
638
638
.r#type(file.r#type.into_static())
···
643
643
.build()
644
644
))
645
645
}
646
-
crate::place_wisp::subfs::EntryNode::Directory(dir) => {
646
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(dir) => {
647
647
let converted_entries: Vec<Entry<'static>> = dir
648
648
.entries
649
649
.into_iter()
···
657
657
.build()
658
658
))
659
659
}
660
-
crate::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
660
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
661
661
// Nested subfs should have been expanded already - if we get here, it means expansion failed
662
662
// Treat it like a directory reference that should have been expanded
663
663
eprintln!(" โ ๏ธ Warning: unexpanded nested subfs at path, treating as empty directory");
···
668
668
.build()
669
669
))
670
670
}
671
-
crate::place_wisp::subfs::EntryNode::Unknown(unknown) => {
671
+
wisp_lexicons::place_wisp::subfs::EntryNode::Unknown(unknown) => {
672
672
EntryNode::Unknown(unknown)
673
673
}
674
674
};
+1
-1
cli/src/serve.rs
+1
-1
cli/src/serve.rs
+14
-14
cli/src/subfs_utils.rs
+14
-14
cli/src/subfs_utils.rs
···
6
6
use miette::IntoDiagnostic;
7
7
use std::collections::HashMap;
8
8
9
-
use crate::place_wisp::fs::{Directory as FsDirectory, EntryNode as FsEntryNode};
10
-
use crate::place_wisp::subfs::SubfsRecord;
9
+
use wisp_lexicons::place_wisp::fs::{Directory as FsDirectory, EntryNode as FsEntryNode};
10
+
use wisp_lexicons::place_wisp::subfs::SubfsRecord;
11
11
12
12
/// Extract all subfs URIs from a directory tree with their mount paths
13
13
pub fn extract_subfs_uris(directory: &FsDirectory, current_path: String) -> Vec<(String, String)> {
···
145
145
146
146
/// Extract subfs URIs from a subfs::Directory
147
147
fn extract_subfs_uris_from_subfs_dir(
148
-
directory: &crate::place_wisp::subfs::Directory,
148
+
directory: &wisp_lexicons::place_wisp::subfs::Directory,
149
149
current_path: String,
150
150
) -> Vec<(String, String)> {
151
151
let mut uris = Vec::new();
152
152
153
153
for entry in &directory.entries {
154
154
match &entry.node {
155
-
crate::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
155
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(subfs_node) => {
156
156
// Check if this is a chunk entry (chunk0, chunk1, etc.)
157
157
// Chunks should be flat-merged, so use the parent's path
158
158
let mount_path = if entry.name.starts_with("chunk") &&
···
171
171
172
172
uris.push((subfs_node.subject.to_string(), mount_path));
173
173
}
174
-
crate::place_wisp::subfs::EntryNode::Directory(subdir) => {
174
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => {
175
175
let full_path = if current_path.is_empty() {
176
176
entry.name.to_string()
177
177
} else {
···
204
204
for (mount_path, subfs_record) in all_subfs {
205
205
// Check if this record only contains chunk subfs references (no files)
206
206
let only_has_chunks = subfs_record.root.entries.iter().all(|e| {
207
-
matches!(&e.node, crate::place_wisp::subfs::EntryNode::Subfs(_)) &&
207
+
matches!(&e.node, wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_)) &&
208
208
e.name.starts_with("chunk") &&
209
209
e.name.chars().skip(5).all(|c| c.is_ascii_digit())
210
210
});
···
232
232
/// Extract blobs from a subfs directory (works with subfs::Directory)
233
233
/// Returns a map of file paths to their blob refs and CIDs
234
234
fn extract_subfs_blobs(
235
-
directory: &crate::place_wisp::subfs::Directory,
235
+
directory: &wisp_lexicons::place_wisp::subfs::Directory,
236
236
current_path: String,
237
237
) -> HashMap<String, (BlobRef<'static>, String)> {
238
238
let mut blob_map = HashMap::new();
···
245
245
};
246
246
247
247
match &entry.node {
248
-
crate::place_wisp::subfs::EntryNode::File(file_node) => {
248
+
wisp_lexicons::place_wisp::subfs::EntryNode::File(file_node) => {
249
249
let blob_ref = &file_node.blob;
250
250
let cid_string = blob_ref.blob().r#ref.to_string();
251
251
blob_map.insert(
···
253
253
(blob_ref.clone().into_static(), cid_string)
254
254
);
255
255
}
256
-
crate::place_wisp::subfs::EntryNode::Directory(subdir) => {
256
+
wisp_lexicons::place_wisp::subfs::EntryNode::Directory(subdir) => {
257
257
let sub_map = extract_subfs_blobs(subdir, full_path);
258
258
blob_map.extend(sub_map);
259
259
}
260
-
crate::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
260
+
wisp_lexicons::place_wisp::subfs::EntryNode::Subfs(_nested_subfs) => {
261
261
// Nested subfs - these should be resolved recursively in the main flow
262
262
// For now, we skip them (they'll be fetched separately)
263
263
eprintln!(" โ ๏ธ Found nested subfs at {}, skipping (should be fetched separately)", full_path);
264
264
}
265
-
crate::place_wisp::subfs::EntryNode::Unknown(_) => {
265
+
wisp_lexicons::place_wisp::subfs::EntryNode::Unknown(_) => {
266
266
// Skip unknown nodes
267
267
}
268
268
}
···
352
352
flat: bool,
353
353
) -> miette::Result<FsDirectory<'static>> {
354
354
use jacquard_common::CowStr;
355
-
use crate::place_wisp::fs::{Entry, Subfs};
355
+
use wisp_lexicons::place_wisp::fs::{Entry, Subfs};
356
356
357
357
let path_parts: Vec<&str> = target_path.split('/').collect();
358
358
···
430
430
431
431
// Construct AT-URI and convert to RecordUri
432
432
let at_uri = AtUri::new(uri).into_diagnostic()?;
433
-
let record_uri: RecordUri<'_, crate::place_wisp::subfs::SubfsRecordRecord> = RecordUri::try_from_uri(at_uri).into_diagnostic()?;
433
+
let record_uri: RecordUri<'_, wisp_lexicons::place_wisp::subfs::SubfsRecordRecord> = RecordUri::try_from_uri(at_uri).into_diagnostic()?;
434
434
435
435
let rkey = record_uri.rkey()
436
436
.ok_or_else(|| miette::miette!("Invalid subfs URI: missing rkey"))?
···
489
489
}
490
490
491
491
/// Estimate the JSON size of a single entry
492
-
fn estimate_entry_size(entry: &crate::place_wisp::fs::Entry) -> usize {
492
+
fn estimate_entry_size(entry: &wisp_lexicons::place_wisp::fs::Entry) -> usize {
493
493
match serde_json::to_string(entry) {
494
494
Ok(json) => json.len(),
495
495
Err(_) => 500, // Conservative estimate if serialization fails
+21
docker-compose.yml
+21
docker-compose.yml
···
1
+
services:
2
+
postgres:
3
+
image: postgres:16-alpine
4
+
container_name: wisp-postgres
5
+
restart: unless-stopped
6
+
environment:
7
+
POSTGRES_USER: postgres
8
+
POSTGRES_PASSWORD: postgres
9
+
POSTGRES_DB: wisp
10
+
ports:
11
+
- "5432:5432"
12
+
volumes:
13
+
- postgres_data:/var/lib/postgresql/data
14
+
healthcheck:
15
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
16
+
interval: 5s
17
+
timeout: 5s
18
+
retries: 5
19
+
20
+
volumes:
21
+
postgres_data:
+4
-1
docs/astro.config.mjs
+4
-1
docs/astro.config.mjs
···
7
7
integrations: [
8
8
starlight({
9
9
title: 'Wisp.place Docs',
10
-
social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/tangled-org/wisp.place' }],
10
+
components: {
11
+
SocialIcons: './src/components/SocialIcons.astro',
12
+
},
11
13
sidebar: [
12
14
{
13
15
label: 'Getting Started',
···
24
26
label: 'Guides',
25
27
items: [
26
28
{ label: 'Self-Hosting', slug: 'deployment' },
29
+
{ label: 'Monitoring & Metrics', slug: 'monitoring' },
27
30
{ label: 'Redirects & Rewrites', slug: 'redirects' },
28
31
],
29
32
},
+9
docs/src/assets/tangled-icon.svg
+9
docs/src/assets/tangled-icon.svg
···
1
+
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1" id="svg1" width="25" height="25" viewBox="0 0 25 25" sodipodi:docname="tangled_dolly_silhouette.png">
2
+
<defs id="defs1"/>
3
+
<sodipodi:namedview id="namedview1" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="true" inkscape:deskcolor="#d1d1d1">
4
+
<inkscape:page x="0" y="0" width="25" height="25" id="page2" margin="0" bleed="0"/>
5
+
</sodipodi:namedview>
6
+
<g inkscape:groupmode="layer" inkscape:label="Image" id="g1">
7
+
<path style="fill:#000000;stroke-width:1.12248" d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z" id="path1"/>
8
+
</g>
9
+
</svg>
+26
docs/src/components/SocialIcons.astro
+26
docs/src/components/SocialIcons.astro
···
1
+
---
2
+
// Custom social icons component to use the Tangled icon
3
+
---
4
+
5
+
<div class="sl-flex">
6
+
<a
7
+
href="https://tangled.org/nekomimi.pet/wisp.place-monorepo"
8
+
rel="me"
9
+
class="sl-flex"
10
+
aria-label="Tangled"
11
+
>
12
+
<svg
13
+
xmlns="http://www.w3.org/2000/svg"
14
+
viewBox="0 0 25 25"
15
+
width="16"
16
+
height="16"
17
+
aria-hidden="true"
18
+
focusable="false"
19
+
>
20
+
<path
21
+
style="fill:currentColor;stroke-width:1.12248"
22
+
d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z"
23
+
></path>
24
+
</svg>
25
+
</a>
26
+
</div>
+6
-11
docs/src/content/docs/cli.md
+6
-11
docs/src/content/docs/cli.md
···
71
71
72
72
engine: 'nixery'
73
73
74
-
clone:
75
-
skip: false
76
-
depth: 1
77
-
submodules: false
78
-
79
74
dependencies:
80
75
nixpkgs:
81
76
- nodejs
···
141
136
# Pull a site to a specific directory
142
137
wisp-cli pull your-handle.bsky.social \
143
138
--site my-site \
144
-
--output ./my-site
139
+
--path ./my-site
145
140
146
141
# Pull to current directory
147
142
wisp-cli pull your-handle.bsky.social \
···
238
233
### Pull Command
239
234
240
235
```bash
241
-
wisp-cli pull [OPTIONS] <INPUT>
236
+
wisp-cli pull [OPTIONS] --site <SITE> <INPUT>
242
237
243
238
Arguments:
244
239
<INPUT> Handle or DID
245
240
246
241
Options:
247
242
-s, --site <SITE> Site name to download
248
-
-o, --output <OUTPUT> Output directory [default: .]
243
+
-p, --path <PATH> Output directory [default: .]
249
244
-h, --help Print help
250
245
```
251
246
252
247
### Serve Command
253
248
254
249
```bash
255
-
wisp-cli serve [OPTIONS] <INPUT>
250
+
wisp-cli serve [OPTIONS] --site <SITE> <INPUT>
256
251
257
252
Arguments:
258
253
<INPUT> Handle or DID
259
254
260
255
Options:
261
256
-s, --site <SITE> Site name to serve
262
-
-o, --output <OUTPUT> Site files directory [default: .]
263
-
-p, --port <PORT> Port to serve on [default: 8080]
257
+
-p, --path <PATH> Site files directory [default: .]
258
+
-P, --port <PORT> Port to serve on [default: 8080]
264
259
--spa Enable SPA mode (serve index.html for all routes)
265
260
--directory Enable directory listing mode for paths without index files
266
261
-h, --help Print help
+85
docs/src/content/docs/guides/grafana-setup.md
+85
docs/src/content/docs/guides/grafana-setup.md
···
1
+
---
2
+
title: Grafana Setup Example
3
+
description: Quick setup for Grafana Cloud monitoring
4
+
---
5
+
6
+
Example setup for monitoring Wisp.place with Grafana Cloud.
7
+
8
+
## 1. Create Grafana Cloud Account
9
+
10
+
Sign up at [grafana.com](https://grafana.com) for a free tier account.
11
+
12
+
## 2. Get Credentials
13
+
14
+
Navigate to your stack and find:
15
+
16
+
**Loki** (Connections โ Loki โ Details):
17
+
- Push endpoint: `https://logs-prod-XXX.grafana.net`
18
+
- Create API token with write permissions
19
+
20
+
**Prometheus** (Connections โ Prometheus โ Details):
21
+
- Remote Write endpoint: `https://prometheus-prod-XXX.grafana.net/api/prom`
22
+
- Create API token with write permissions
23
+
24
+
## 3. Configure Wisp.place
25
+
26
+
Add to your `.env`:
27
+
28
+
```bash
29
+
GRAFANA_LOKI_URL=https://logs-prod-XXX.grafana.net
30
+
GRAFANA_LOKI_TOKEN=glc_eyJ...
31
+
32
+
GRAFANA_PROMETHEUS_URL=https://prometheus-prod-XXX.grafana.net/api/prom
33
+
GRAFANA_PROMETHEUS_TOKEN=glc_eyJ...
34
+
```
35
+
36
+
## 4. Create Dashboard
37
+
38
+
Import this dashboard JSON or build your own:
39
+
40
+
```json
41
+
{
42
+
"panels": [
43
+
{
44
+
"title": "Request Rate",
45
+
"targets": [{
46
+
"expr": "sum(rate(http_requests_total[1m])) by (service)"
47
+
}]
48
+
},
49
+
{
50
+
"title": "P95 Latency",
51
+
"targets": [{
52
+
"expr": "histogram_quantile(0.95, rate(http_request_duration_ms_bucket[5m]))"
53
+
}]
54
+
},
55
+
{
56
+
"title": "Error Rate",
57
+
"targets": [{
58
+
"expr": "sum(rate(errors_total[5m])) / sum(rate(http_requests_total[5m]))"
59
+
}]
60
+
}
61
+
]
62
+
}
63
+
```
64
+
65
+
## 5. Set Alerts
66
+
67
+
Example alert for high error rate:
68
+
69
+
```yaml
70
+
alert: HighErrorRate
71
+
expr: |
72
+
sum(rate(errors_total[5m])) by (service) /
73
+
sum(rate(http_requests_total[5m])) by (service) > 0.05
74
+
for: 5m
75
+
annotations:
76
+
summary: "High error rate in {{ $labels.service }}"
77
+
```
78
+
79
+
## Verify Data Flow
80
+
81
+
Check Grafana Explore:
82
+
- Loki: `{job="main-app"} | json`
83
+
- Prometheus: `http_requests_total`
84
+
85
+
Data should appear within 30 seconds of service startup.
+156
docs/src/content/docs/monitoring.md
+156
docs/src/content/docs/monitoring.md
···
1
+
---
2
+
title: Monitoring & Metrics
3
+
description: Track performance and debug issues with Grafana integration
4
+
---
5
+
6
+
Wisp.place includes built-in observability with automatic Grafana integration for logs and metrics. Monitor request performance, track errors, and analyze usage patterns across both the main backend and hosting service.
7
+
8
+
## Quick Start
9
+
10
+
Set environment variables to enable Grafana export:
11
+
12
+
```bash
13
+
# Grafana Cloud
14
+
GRAFANA_LOKI_URL=https://logs-prod-xxx.grafana.net
15
+
GRAFANA_LOKI_TOKEN=glc_xxx
16
+
17
+
GRAFANA_PROMETHEUS_URL=https://prometheus-prod-xxx.grafana.net/api/prom
18
+
GRAFANA_PROMETHEUS_TOKEN=glc_xxx
19
+
20
+
# Self-hosted Grafana
21
+
GRAFANA_LOKI_USERNAME=your-username
22
+
GRAFANA_LOKI_PASSWORD=your-password
23
+
```
24
+
25
+
Restart services. Metrics and logs now flow to Grafana automatically.
26
+
27
+
## Metrics Collected
28
+
29
+
### HTTP Requests
30
+
- `http_requests_total` - Total request count by path, method, status
31
+
- `http_request_duration_ms` - Request duration histogram
32
+
- `errors_total` - Error count by service
33
+
34
+
### Performance Stats
35
+
- P50, P95, P99 response times
36
+
- Requests per minute
37
+
- Error rates
38
+
- Average duration by endpoint
39
+
40
+
## Log Aggregation
41
+
42
+
Logs are sent to Loki with automatic categorization:
43
+
44
+
```
45
+
{job="main-app"} |= "error" # OAuth and upload errors
46
+
{job="hosting-service"} |= "cache" # Cache operations
47
+
{service="hosting-service", level="warn"} # Warnings only
48
+
```
49
+
50
+
## Service Identification
51
+
52
+
Each service is tagged separately:
53
+
- `main-app` - OAuth, uploads, domain management
54
+
- `hosting-service` - Firehose, caching, content serving
55
+
56
+
## Configuration Options
57
+
58
+
### Environment Variables
59
+
60
+
```bash
61
+
# Required
62
+
GRAFANA_LOKI_URL # Loki endpoint
63
+
GRAFANA_PROMETHEUS_URL # Prometheus endpoint (add /api/prom for OTLP)
64
+
65
+
# Authentication (use one)
66
+
GRAFANA_LOKI_TOKEN # Bearer token (Grafana Cloud)
67
+
GRAFANA_LOKI_USERNAME # Basic auth (self-hosted)
68
+
GRAFANA_LOKI_PASSWORD
69
+
70
+
# Optional
71
+
GRAFANA_BATCH_SIZE=100 # Batch size before flush
72
+
GRAFANA_FLUSH_INTERVAL=5000 # Flush interval in ms
73
+
```
74
+
75
+
### Programmatic Setup
76
+
77
+
```typescript
78
+
import { initializeGrafanaExporters } from '@wisp/observability'
79
+
80
+
initializeGrafanaExporters({
81
+
lokiUrl: 'https://logs.grafana.net',
82
+
lokiAuth: { bearerToken: 'token' },
83
+
prometheusUrl: 'https://prometheus.grafana.net/api/prom',
84
+
prometheusAuth: { bearerToken: 'token' },
85
+
serviceName: 'my-service',
86
+
batchSize: 100,
87
+
flushIntervalMs: 5000
88
+
})
89
+
```
90
+
91
+
## Grafana Dashboard Queries
92
+
93
+
### Request Performance
94
+
```promql
95
+
# Average response time by endpoint
96
+
avg by (path) (
97
+
rate(http_request_duration_ms_sum[5m]) /
98
+
rate(http_request_duration_ms_count[5m])
99
+
)
100
+
101
+
# Request rate
102
+
sum(rate(http_requests_total[1m])) by (service)
103
+
104
+
# Error rate
105
+
sum(rate(errors_total[5m])) by (service) /
106
+
sum(rate(http_requests_total[5m])) by (service)
107
+
```
108
+
109
+
### Log Analysis
110
+
```logql
111
+
# Recent errors
112
+
{job="main-app"} |= "error" | json
113
+
114
+
# Slow requests (>1s)
115
+
{job="hosting-service"} |~ "duration.*[1-9][0-9]{3,}"
116
+
117
+
# Failed OAuth attempts
118
+
{job="main-app"} |= "OAuth" |= "failed"
119
+
```
120
+
121
+
## Troubleshooting
122
+
123
+
### Logs not appearing
124
+
- Check `GRAFANA_LOKI_URL` is correct (no trailing `/loki/api/v1/push`)
125
+
- Verify authentication token/credentials
126
+
- Look for connection errors in service logs
127
+
128
+
### Metrics missing
129
+
- Ensure `GRAFANA_PROMETHEUS_URL` includes `/api/prom` suffix
130
+
- Check firewall rules allow outbound HTTPS
131
+
- Verify OpenTelemetry export errors in logs
132
+
133
+
### High memory usage
134
+
- Reduce `GRAFANA_BATCH_SIZE` (default: 100)
135
+
- Lower `GRAFANA_FLUSH_INTERVAL` to flush more frequently
136
+
137
+
## Local Development
138
+
139
+
Metrics and logs are stored in-memory when Grafana isn't configured. Access them via:
140
+
141
+
- `http://localhost:8000/api/observability/logs`
142
+
- `http://localhost:8000/api/observability/metrics`
143
+
- `http://localhost:8000/api/observability/errors`
144
+
145
+
## Testing Integration
146
+
147
+
Run integration tests to verify setup:
148
+
149
+
```bash
150
+
cd packages/@wisp/observability
151
+
bun test src/integration-test.test.ts
152
+
153
+
# Test with live Grafana
154
+
GRAFANA_LOKI_URL=... GRAFANA_LOKI_USERNAME=... GRAFANA_LOKI_PASSWORD=... \
155
+
bun test src/integration-test.test.ts
156
+
```
+15
-15
docs/src/styles/custom.css
+15
-15
docs/src/styles/custom.css
···
5
5
/* Increase base font size by 10% */
6
6
font-size: 110%;
7
7
8
-
/* Light theme - Warm beige background from app */
9
-
--sl-color-bg: oklch(0.90 0.012 35);
10
-
--sl-color-bg-sidebar: oklch(0.93 0.01 35);
11
-
--sl-color-bg-nav: oklch(0.93 0.01 35);
12
-
--sl-color-text: oklch(0.18 0.01 30);
13
-
--sl-color-text-accent: oklch(0.78 0.15 345);
14
-
--sl-color-accent: oklch(0.78 0.15 345);
15
-
--sl-color-accent-low: oklch(0.95 0.03 345);
16
-
--sl-color-border: oklch(0.75 0.015 30);
17
-
--sl-color-gray-1: oklch(0.52 0.015 30);
18
-
--sl-color-gray-2: oklch(0.42 0.015 30);
19
-
--sl-color-gray-3: oklch(0.33 0.015 30);
20
-
--sl-color-gray-4: oklch(0.25 0.015 30);
21
-
--sl-color-gray-5: oklch(0.75 0.015 30);
8
+
/* Light theme - Warm beige with improved contrast */
9
+
--sl-color-bg: oklch(0.92 0.012 35);
10
+
--sl-color-bg-sidebar: oklch(0.95 0.008 35);
11
+
--sl-color-bg-nav: oklch(0.95 0.008 35);
12
+
--sl-color-text: oklch(0.15 0.015 30);
13
+
--sl-color-text-accent: oklch(0.65 0.18 345);
14
+
--sl-color-accent: oklch(0.65 0.18 345);
15
+
--sl-color-accent-low: oklch(0.92 0.05 345);
16
+
--sl-color-border: oklch(0.65 0.02 30);
17
+
--sl-color-gray-1: oklch(0.45 0.02 30);
18
+
--sl-color-gray-2: oklch(0.35 0.02 30);
19
+
--sl-color-gray-3: oklch(0.28 0.02 30);
20
+
--sl-color-gray-4: oklch(0.20 0.015 30);
21
+
--sl-color-gray-5: oklch(0.65 0.02 30);
22
22
--sl-color-bg-accent: oklch(0.88 0.01 35);
23
23
}
24
24
···
70
70
/* Sidebar active/hover state text contrast fix */
71
71
.sidebar a[aria-current="page"],
72
72
.sidebar a[aria-current="page"] span {
73
-
color: oklch(0.23 0.015 285) !important;
73
+
color: oklch(0.15 0.015 30) !important;
74
74
}
75
75
76
76
[data-theme="dark"] .sidebar a[aria-current="page"],
-318
flake.lock
-318
flake.lock
···
1
-
{
2
-
"nodes": {
3
-
"crane": {
4
-
"flake": false,
5
-
"locked": {
6
-
"lastModified": 1758758545,
7
-
"narHash": "sha256-NU5WaEdfwF6i8faJ2Yh+jcK9vVFrofLcwlD/mP65JrI=",
8
-
"owner": "ipetkov",
9
-
"repo": "crane",
10
-
"rev": "95d528a5f54eaba0d12102249ce42f4d01f4e364",
11
-
"type": "github"
12
-
},
13
-
"original": {
14
-
"owner": "ipetkov",
15
-
"ref": "v0.21.1",
16
-
"repo": "crane",
17
-
"type": "github"
18
-
}
19
-
},
20
-
"dream2nix": {
21
-
"inputs": {
22
-
"nixpkgs": [
23
-
"nci",
24
-
"nixpkgs"
25
-
],
26
-
"purescript-overlay": "purescript-overlay",
27
-
"pyproject-nix": "pyproject-nix"
28
-
},
29
-
"locked": {
30
-
"lastModified": 1754978539,
31
-
"narHash": "sha256-nrDovydywSKRbWim9Ynmgj8SBm8LK3DI2WuhIqzOHYI=",
32
-
"owner": "nix-community",
33
-
"repo": "dream2nix",
34
-
"rev": "fbec3263cb4895ac86ee9506cdc4e6919a1a2214",
35
-
"type": "github"
36
-
},
37
-
"original": {
38
-
"owner": "nix-community",
39
-
"repo": "dream2nix",
40
-
"type": "github"
41
-
}
42
-
},
43
-
"fenix": {
44
-
"inputs": {
45
-
"nixpkgs": [
46
-
"nixpkgs"
47
-
],
48
-
"rust-analyzer-src": "rust-analyzer-src"
49
-
},
50
-
"locked": {
51
-
"lastModified": 1762584108,
52
-
"narHash": "sha256-wZUW7dlXMXaRdvNbaADqhF8gg9bAfFiMV+iyFQiDv+Y=",
53
-
"owner": "nix-community",
54
-
"repo": "fenix",
55
-
"rev": "32f3ad3b6c690061173e1ac16708874975ec6056",
56
-
"type": "github"
57
-
},
58
-
"original": {
59
-
"owner": "nix-community",
60
-
"repo": "fenix",
61
-
"type": "github"
62
-
}
63
-
},
64
-
"flake-compat": {
65
-
"flake": false,
66
-
"locked": {
67
-
"lastModified": 1696426674,
68
-
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
69
-
"owner": "edolstra",
70
-
"repo": "flake-compat",
71
-
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
72
-
"type": "github"
73
-
},
74
-
"original": {
75
-
"owner": "edolstra",
76
-
"repo": "flake-compat",
77
-
"type": "github"
78
-
}
79
-
},
80
-
"mk-naked-shell": {
81
-
"flake": false,
82
-
"locked": {
83
-
"lastModified": 1681286841,
84
-
"narHash": "sha256-3XlJrwlR0nBiREnuogoa5i1b4+w/XPe0z8bbrJASw0g=",
85
-
"owner": "90-008",
86
-
"repo": "mk-naked-shell",
87
-
"rev": "7612f828dd6f22b7fb332cc69440e839d7ffe6bd",
88
-
"type": "github"
89
-
},
90
-
"original": {
91
-
"owner": "90-008",
92
-
"repo": "mk-naked-shell",
93
-
"type": "github"
94
-
}
95
-
},
96
-
"nci": {
97
-
"inputs": {
98
-
"crane": "crane",
99
-
"dream2nix": "dream2nix",
100
-
"mk-naked-shell": "mk-naked-shell",
101
-
"nixpkgs": [
102
-
"nixpkgs"
103
-
],
104
-
"parts": "parts",
105
-
"rust-overlay": "rust-overlay",
106
-
"treefmt": "treefmt"
107
-
},
108
-
"locked": {
109
-
"lastModified": 1762582646,
110
-
"narHash": "sha256-MMzE4xccG+8qbLhdaZoeFDUKWUOn3B4lhp5dZmgukmM=",
111
-
"owner": "90-008",
112
-
"repo": "nix-cargo-integration",
113
-
"rev": "0993c449377049fa8868a664e8290ac6658e0b9a",
114
-
"type": "github"
115
-
},
116
-
"original": {
117
-
"owner": "90-008",
118
-
"repo": "nix-cargo-integration",
119
-
"type": "github"
120
-
}
121
-
},
122
-
"nixpkgs": {
123
-
"locked": {
124
-
"lastModified": 1762361079,
125
-
"narHash": "sha256-lz718rr1BDpZBYk7+G8cE6wee3PiBUpn8aomG/vLLiY=",
126
-
"owner": "nixos",
127
-
"repo": "nixpkgs",
128
-
"rev": "ffcdcf99d65c61956d882df249a9be53e5902ea5",
129
-
"type": "github"
130
-
},
131
-
"original": {
132
-
"owner": "nixos",
133
-
"ref": "nixpkgs-unstable",
134
-
"repo": "nixpkgs",
135
-
"type": "github"
136
-
}
137
-
},
138
-
"parts": {
139
-
"inputs": {
140
-
"nixpkgs-lib": [
141
-
"nci",
142
-
"nixpkgs"
143
-
]
144
-
},
145
-
"locked": {
146
-
"lastModified": 1762440070,
147
-
"narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=",
148
-
"owner": "hercules-ci",
149
-
"repo": "flake-parts",
150
-
"rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8",
151
-
"type": "github"
152
-
},
153
-
"original": {
154
-
"owner": "hercules-ci",
155
-
"repo": "flake-parts",
156
-
"type": "github"
157
-
}
158
-
},
159
-
"parts_2": {
160
-
"inputs": {
161
-
"nixpkgs-lib": [
162
-
"nixpkgs"
163
-
]
164
-
},
165
-
"locked": {
166
-
"lastModified": 1762440070,
167
-
"narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=",
168
-
"owner": "hercules-ci",
169
-
"repo": "flake-parts",
170
-
"rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8",
171
-
"type": "github"
172
-
},
173
-
"original": {
174
-
"owner": "hercules-ci",
175
-
"repo": "flake-parts",
176
-
"type": "github"
177
-
}
178
-
},
179
-
"purescript-overlay": {
180
-
"inputs": {
181
-
"flake-compat": "flake-compat",
182
-
"nixpkgs": [
183
-
"nci",
184
-
"dream2nix",
185
-
"nixpkgs"
186
-
],
187
-
"slimlock": "slimlock"
188
-
},
189
-
"locked": {
190
-
"lastModified": 1728546539,
191
-
"narHash": "sha256-Sws7w0tlnjD+Bjck1nv29NjC5DbL6nH5auL9Ex9Iz2A=",
192
-
"owner": "thomashoneyman",
193
-
"repo": "purescript-overlay",
194
-
"rev": "4ad4c15d07bd899d7346b331f377606631eb0ee4",
195
-
"type": "github"
196
-
},
197
-
"original": {
198
-
"owner": "thomashoneyman",
199
-
"repo": "purescript-overlay",
200
-
"type": "github"
201
-
}
202
-
},
203
-
"pyproject-nix": {
204
-
"inputs": {
205
-
"nixpkgs": [
206
-
"nci",
207
-
"dream2nix",
208
-
"nixpkgs"
209
-
]
210
-
},
211
-
"locked": {
212
-
"lastModified": 1752481895,
213
-
"narHash": "sha256-luVj97hIMpCbwhx3hWiRwjP2YvljWy8FM+4W9njDhLA=",
214
-
"owner": "pyproject-nix",
215
-
"repo": "pyproject.nix",
216
-
"rev": "16ee295c25107a94e59a7fc7f2e5322851781162",
217
-
"type": "github"
218
-
},
219
-
"original": {
220
-
"owner": "pyproject-nix",
221
-
"repo": "pyproject.nix",
222
-
"type": "github"
223
-
}
224
-
},
225
-
"root": {
226
-
"inputs": {
227
-
"fenix": "fenix",
228
-
"nci": "nci",
229
-
"nixpkgs": "nixpkgs",
230
-
"parts": "parts_2"
231
-
}
232
-
},
233
-
"rust-analyzer-src": {
234
-
"flake": false,
235
-
"locked": {
236
-
"lastModified": 1762438844,
237
-
"narHash": "sha256-ApIKJf6CcMsV2nYBXhGF95BmZMO/QXPhgfSnkA/rVUo=",
238
-
"owner": "rust-lang",
239
-
"repo": "rust-analyzer",
240
-
"rev": "4bf516ee5a960c1e2eee9fedd9b1c9e976a19c86",
241
-
"type": "github"
242
-
},
243
-
"original": {
244
-
"owner": "rust-lang",
245
-
"ref": "nightly",
246
-
"repo": "rust-analyzer",
247
-
"type": "github"
248
-
}
249
-
},
250
-
"rust-overlay": {
251
-
"inputs": {
252
-
"nixpkgs": [
253
-
"nci",
254
-
"nixpkgs"
255
-
]
256
-
},
257
-
"locked": {
258
-
"lastModified": 1762569282,
259
-
"narHash": "sha256-vINZAJpXQTZd5cfh06Rcw7hesH7sGSvi+Tn+HUieJn8=",
260
-
"owner": "oxalica",
261
-
"repo": "rust-overlay",
262
-
"rev": "a35a6144b976f70827c2fe2f5c89d16d8f9179d8",
263
-
"type": "github"
264
-
},
265
-
"original": {
266
-
"owner": "oxalica",
267
-
"repo": "rust-overlay",
268
-
"type": "github"
269
-
}
270
-
},
271
-
"slimlock": {
272
-
"inputs": {
273
-
"nixpkgs": [
274
-
"nci",
275
-
"dream2nix",
276
-
"purescript-overlay",
277
-
"nixpkgs"
278
-
]
279
-
},
280
-
"locked": {
281
-
"lastModified": 1688756706,
282
-
"narHash": "sha256-xzkkMv3neJJJ89zo3o2ojp7nFeaZc2G0fYwNXNJRFlo=",
283
-
"owner": "thomashoneyman",
284
-
"repo": "slimlock",
285
-
"rev": "cf72723f59e2340d24881fd7bf61cb113b4c407c",
286
-
"type": "github"
287
-
},
288
-
"original": {
289
-
"owner": "thomashoneyman",
290
-
"repo": "slimlock",
291
-
"type": "github"
292
-
}
293
-
},
294
-
"treefmt": {
295
-
"inputs": {
296
-
"nixpkgs": [
297
-
"nci",
298
-
"nixpkgs"
299
-
]
300
-
},
301
-
"locked": {
302
-
"lastModified": 1762410071,
303
-
"narHash": "sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g+mjR/p5TEg=",
304
-
"owner": "numtide",
305
-
"repo": "treefmt-nix",
306
-
"rev": "97a30861b13c3731a84e09405414398fbf3e109f",
307
-
"type": "github"
308
-
},
309
-
"original": {
310
-
"owner": "numtide",
311
-
"repo": "treefmt-nix",
312
-
"type": "github"
313
-
}
314
-
}
315
-
},
316
-
"root": "root",
317
-
"version": 7
318
-
}
-59
flake.nix
-59
flake.nix
···
1
-
{
2
-
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
3
-
inputs.nci.url = "github:90-008/nix-cargo-integration";
4
-
inputs.nci.inputs.nixpkgs.follows = "nixpkgs";
5
-
inputs.parts.url = "github:hercules-ci/flake-parts";
6
-
inputs.parts.inputs.nixpkgs-lib.follows = "nixpkgs";
7
-
inputs.fenix = {
8
-
url = "github:nix-community/fenix";
9
-
inputs.nixpkgs.follows = "nixpkgs";
10
-
};
11
-
12
-
outputs = inputs @ {
13
-
parts,
14
-
nci,
15
-
...
16
-
}:
17
-
parts.lib.mkFlake {inherit inputs;} {
18
-
systems = ["x86_64-linux" "aarch64-darwin"];
19
-
imports = [
20
-
nci.flakeModule
21
-
./crates.nix
22
-
];
23
-
perSystem = {
24
-
pkgs,
25
-
config,
26
-
...
27
-
}: let
28
-
crateOutputs = config.nci.outputs."wisp-cli";
29
-
mkRenamedPackage = name: pkg: isWindows: pkgs.runCommand name {} ''
30
-
mkdir -p $out/bin
31
-
if [ -f ${pkg}/bin/wisp-cli.exe ]; then
32
-
cp ${pkg}/bin/wisp-cli.exe $out/bin/${name}
33
-
elif [ -f ${pkg}/bin/wisp-cli ]; then
34
-
cp ${pkg}/bin/wisp-cli $out/bin/${name}
35
-
else
36
-
echo "Error: Could not find wisp-cli binary in ${pkg}/bin/"
37
-
ls -la ${pkg}/bin/ || true
38
-
exit 1
39
-
fi
40
-
'';
41
-
in {
42
-
devShells.default = crateOutputs.devShell;
43
-
packages.default = crateOutputs.packages.release;
44
-
packages.wisp-cli-x86_64-linux = mkRenamedPackage "wisp-cli-x86_64-linux" crateOutputs.packages.release false;
45
-
packages.wisp-cli-aarch64-linux = mkRenamedPackage "wisp-cli-aarch64-linux" crateOutputs.allTargets."aarch64-unknown-linux-gnu".packages.release false;
46
-
packages.wisp-cli-x86_64-windows = mkRenamedPackage "wisp-cli-x86_64-windows.exe" crateOutputs.allTargets."x86_64-pc-windows-gnu".packages.release true;
47
-
packages.wisp-cli-aarch64-darwin = mkRenamedPackage "wisp-cli-aarch64-darwin" crateOutputs.allTargets."aarch64-apple-darwin".packages.release false;
48
-
packages.all = pkgs.symlinkJoin {
49
-
name = "wisp-cli-all";
50
-
paths = [
51
-
config.packages.wisp-cli-x86_64-linux
52
-
config.packages.wisp-cli-aarch64-linux
53
-
config.packages.wisp-cli-x86_64-windows
54
-
config.packages.wisp-cli-aarch64-darwin
55
-
];
56
-
};
57
-
};
58
-
};
59
-
}
+59
lexicons/fs.json
+59
lexicons/fs.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "place.wisp.fs",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "Virtual filesystem manifest for a Wisp site",
8
+
"record": {
9
+
"type": "object",
10
+
"required": ["site", "root", "createdAt"],
11
+
"properties": {
12
+
"site": { "type": "string" },
13
+
"root": { "type": "ref", "ref": "#directory" },
14
+
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
15
+
"createdAt": { "type": "string", "format": "datetime" }
16
+
}
17
+
}
18
+
},
19
+
"file": {
20
+
"type": "object",
21
+
"required": ["type", "blob"],
22
+
"properties": {
23
+
"type": { "type": "string", "const": "file" },
24
+
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
25
+
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
26
+
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
27
+
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" } }
28
+
},
29
+
"directory": {
30
+
"type": "object",
31
+
"required": ["type", "entries"],
32
+
"properties": {
33
+
"type": { "type": "string", "const": "directory" },
34
+
"entries": {
35
+
"type": "array",
36
+
"maxLength": 500,
37
+
"items": { "type": "ref", "ref": "#entry" }
38
+
}
39
+
}
40
+
},
41
+
"entry": {
42
+
"type": "object",
43
+
"required": ["name", "node"],
44
+
"properties": {
45
+
"name": { "type": "string", "maxLength": 255 },
46
+
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
+
}
48
+
},
49
+
"subfs": {
50
+
"type": "object",
51
+
"required": ["type", "subject"],
52
+
"properties": {
53
+
"type": { "type": "string", "const": "subfs" },
54
+
"subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to a place.wisp.subfs record containing this subtree." },
55
+
"flat": { "type": "boolean", "description": "If true (default), the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false, the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure." }
56
+
}
57
+
}
58
+
}
59
+
}
+76
lexicons/settings.json
+76
lexicons/settings.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "place.wisp.settings",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "Configuration settings for a static site hosted on wisp.place",
8
+
"key": "any",
9
+
"record": {
10
+
"type": "object",
11
+
"properties": {
12
+
"directoryListing": {
13
+
"type": "boolean",
14
+
"description": "Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.",
15
+
"default": false
16
+
},
17
+
"spaMode": {
18
+
"type": "string",
19
+
"description": "File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.",
20
+
"maxLength": 500
21
+
},
22
+
"custom404": {
23
+
"type": "string",
24
+
"description": "Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
25
+
"maxLength": 500
26
+
},
27
+
"indexFiles": {
28
+
"type": "array",
29
+
"description": "Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
30
+
"items": {
31
+
"type": "string",
32
+
"maxLength": 255
33
+
},
34
+
"maxLength": 10
35
+
},
36
+
"cleanUrls": {
37
+
"type": "boolean",
38
+
"description": "Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.",
39
+
"default": false
40
+
},
41
+
"headers": {
42
+
"type": "array",
43
+
"description": "Custom HTTP headers to set on responses",
44
+
"items": {
45
+
"type": "ref",
46
+
"ref": "#customHeader"
47
+
},
48
+
"maxLength": 50
49
+
}
50
+
}
51
+
}
52
+
},
53
+
"customHeader": {
54
+
"type": "object",
55
+
"description": "Custom HTTP header configuration",
56
+
"required": ["name", "value"],
57
+
"properties": {
58
+
"name": {
59
+
"type": "string",
60
+
"description": "HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
61
+
"maxLength": 100
62
+
},
63
+
"value": {
64
+
"type": "string",
65
+
"description": "HTTP header value",
66
+
"maxLength": 1000
67
+
},
68
+
"path": {
69
+
"type": "string",
70
+
"description": "Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
71
+
"maxLength": 500
72
+
}
73
+
}
74
+
}
75
+
}
76
+
}
+59
lexicons/subfs.json
+59
lexicons/subfs.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "place.wisp.subfs",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.",
8
+
"record": {
9
+
"type": "object",
10
+
"required": ["root", "createdAt"],
11
+
"properties": {
12
+
"root": { "type": "ref", "ref": "#directory" },
13
+
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
14
+
"createdAt": { "type": "string", "format": "datetime" }
15
+
}
16
+
}
17
+
},
18
+
"file": {
19
+
"type": "object",
20
+
"required": ["type", "blob"],
21
+
"properties": {
22
+
"type": { "type": "string", "const": "file" },
23
+
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
24
+
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
25
+
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
26
+
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" }
27
+
}
28
+
},
29
+
"directory": {
30
+
"type": "object",
31
+
"required": ["type", "entries"],
32
+
"properties": {
33
+
"type": { "type": "string", "const": "directory" },
34
+
"entries": {
35
+
"type": "array",
36
+
"maxLength": 500,
37
+
"items": { "type": "ref", "ref": "#entry" }
38
+
}
39
+
}
40
+
},
41
+
"entry": {
42
+
"type": "object",
43
+
"required": ["name", "node"],
44
+
"properties": {
45
+
"name": { "type": "string", "maxLength": 255 },
46
+
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
+
}
48
+
},
49
+
"subfs": {
50
+
"type": "object",
51
+
"required": ["type", "subject"],
52
+
"properties": {
53
+
"type": { "type": "string", "const": "subfs" },
54
+
"subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures." }
55
+
}
56
+
}
57
+
}
58
+
}
59
+
+7
-2
package.json
+7
-2
package.json
···
11
11
"@tailwindcss/cli": "^4.1.17",
12
12
"atproto-ui": "^0.12.0",
13
13
"bun-plugin-tailwind": "^0.1.2",
14
+
"elysia": "^1.4.18",
14
15
"tailwindcss": "^4.1.17"
15
16
},
16
17
"scripts": {
···
23
24
"check": "cd apps/main-app && npm run check && cd ../hosting-service && npm run check",
24
25
"screenshot": "bun run apps/main-app/scripts/screenshot-sites.ts",
25
26
"hosting:dev": "cd apps/hosting-service && npm run dev",
26
-
"hosting:start": "cd apps/hosting-service && npm run start"
27
+
"hosting:start": "cd apps/hosting-service && npm run start",
28
+
"codegen": "./scripts/codegen.sh"
27
29
},
28
30
"trustedDependencies": [
29
31
"@parcel/watcher",
30
32
"bun",
31
33
"esbuild"
32
-
]
34
+
],
35
+
"devDependencies": {
36
+
"@types/bun": "^1.3.5"
37
+
}
33
38
}
+244
packages/@wisp/fs-utils/src/tree.test.ts
+244
packages/@wisp/fs-utils/src/tree.test.ts
···
1
+
import { describe, test, expect } from 'bun:test'
2
+
import { processUploadedFiles, type UploadedFile } from './tree'
3
+
4
+
describe('processUploadedFiles', () => {
5
+
test('should preserve nested directory structure', () => {
6
+
const files: UploadedFile[] = [
7
+
{
8
+
name: 'mysite/index.html',
9
+
content: Buffer.from('<html>'),
10
+
mimeType: 'text/html',
11
+
size: 6
12
+
},
13
+
{
14
+
name: 'mysite/_astro/main.js',
15
+
content: Buffer.from('console.log()'),
16
+
mimeType: 'application/javascript',
17
+
size: 13
18
+
},
19
+
{
20
+
name: 'mysite/_astro/styles.css',
21
+
content: Buffer.from('body {}'),
22
+
mimeType: 'text/css',
23
+
size: 7
24
+
},
25
+
{
26
+
name: 'mysite/images/logo.png',
27
+
content: Buffer.from([0x89, 0x50, 0x4e, 0x47]),
28
+
mimeType: 'image/png',
29
+
size: 4
30
+
}
31
+
]
32
+
33
+
const result = processUploadedFiles(files)
34
+
35
+
expect(result.fileCount).toBe(4)
36
+
expect(result.directory.entries).toHaveLength(3) // index.html, _astro/, images/
37
+
38
+
// Check _astro directory exists
39
+
const astroEntry = result.directory.entries.find(e => e.name === '_astro')
40
+
expect(astroEntry).toBeTruthy()
41
+
expect('type' in astroEntry!.node && astroEntry!.node.type).toBe('directory')
42
+
43
+
if ('entries' in astroEntry!.node) {
44
+
const astroDir = astroEntry!.node
45
+
expect(astroDir.entries).toHaveLength(2) // main.js, styles.css
46
+
expect(astroDir.entries.find(e => e.name === 'main.js')).toBeTruthy()
47
+
expect(astroDir.entries.find(e => e.name === 'styles.css')).toBeTruthy()
48
+
}
49
+
50
+
// Check images directory exists
51
+
const imagesEntry = result.directory.entries.find(e => e.name === 'images')
52
+
expect(imagesEntry).toBeTruthy()
53
+
expect('type' in imagesEntry!.node && imagesEntry!.node.type).toBe('directory')
54
+
55
+
if ('entries' in imagesEntry!.node) {
56
+
const imagesDir = imagesEntry!.node
57
+
expect(imagesDir.entries).toHaveLength(1) // logo.png
58
+
expect(imagesDir.entries.find(e => e.name === 'logo.png')).toBeTruthy()
59
+
}
60
+
})
61
+
62
+
test('should handle deeply nested directories', () => {
63
+
const files: UploadedFile[] = [
64
+
{
65
+
name: 'site/a/b/c/d/deep.txt',
66
+
content: Buffer.from('deep'),
67
+
mimeType: 'text/plain',
68
+
size: 4
69
+
}
70
+
]
71
+
72
+
const result = processUploadedFiles(files)
73
+
74
+
expect(result.fileCount).toBe(1)
75
+
76
+
// Navigate through nested structure
77
+
const aEntry = result.directory.entries.find(e => e.name === 'a')
78
+
expect(aEntry).toBeTruthy()
79
+
expect('type' in aEntry!.node && aEntry!.node.type).toBe('directory')
80
+
81
+
if ('entries' in aEntry!.node) {
82
+
const bEntry = aEntry!.node.entries.find(e => e.name === 'b')
83
+
expect(bEntry).toBeTruthy()
84
+
expect('type' in bEntry!.node && bEntry!.node.type).toBe('directory')
85
+
86
+
if ('entries' in bEntry!.node) {
87
+
const cEntry = bEntry!.node.entries.find(e => e.name === 'c')
88
+
expect(cEntry).toBeTruthy()
89
+
expect('type' in cEntry!.node && cEntry!.node.type).toBe('directory')
90
+
91
+
if ('entries' in cEntry!.node) {
92
+
const dEntry = cEntry!.node.entries.find(e => e.name === 'd')
93
+
expect(dEntry).toBeTruthy()
94
+
expect('type' in dEntry!.node && dEntry!.node.type).toBe('directory')
95
+
96
+
if ('entries' in dEntry!.node) {
97
+
const fileEntry = dEntry!.node.entries.find(e => e.name === 'deep.txt')
98
+
expect(fileEntry).toBeTruthy()
99
+
expect('type' in fileEntry!.node && fileEntry!.node.type).toBe('file')
100
+
}
101
+
}
102
+
}
103
+
}
104
+
})
105
+
106
+
test('should handle files at root level', () => {
107
+
const files: UploadedFile[] = [
108
+
{
109
+
name: 'mysite/index.html',
110
+
content: Buffer.from('<html>'),
111
+
mimeType: 'text/html',
112
+
size: 6
113
+
},
114
+
{
115
+
name: 'mysite/robots.txt',
116
+
content: Buffer.from('User-agent: *'),
117
+
mimeType: 'text/plain',
118
+
size: 13
119
+
}
120
+
]
121
+
122
+
const result = processUploadedFiles(files)
123
+
124
+
expect(result.fileCount).toBe(2)
125
+
expect(result.directory.entries).toHaveLength(2)
126
+
expect(result.directory.entries.find(e => e.name === 'index.html')).toBeTruthy()
127
+
expect(result.directory.entries.find(e => e.name === 'robots.txt')).toBeTruthy()
128
+
})
129
+
130
+
test('should skip .git directories', () => {
131
+
const files: UploadedFile[] = [
132
+
{
133
+
name: 'mysite/index.html',
134
+
content: Buffer.from('<html>'),
135
+
mimeType: 'text/html',
136
+
size: 6
137
+
},
138
+
{
139
+
name: 'mysite/.git/config',
140
+
content: Buffer.from('[core]'),
141
+
mimeType: 'text/plain',
142
+
size: 6
143
+
},
144
+
{
145
+
name: 'mysite/.gitignore',
146
+
content: Buffer.from('node_modules'),
147
+
mimeType: 'text/plain',
148
+
size: 12
149
+
}
150
+
]
151
+
152
+
const result = processUploadedFiles(files)
153
+
154
+
expect(result.fileCount).toBe(2) // Only index.html and .gitignore
155
+
expect(result.directory.entries).toHaveLength(2)
156
+
expect(result.directory.entries.find(e => e.name === 'index.html')).toBeTruthy()
157
+
expect(result.directory.entries.find(e => e.name === '.gitignore')).toBeTruthy()
158
+
expect(result.directory.entries.find(e => e.name === '.git')).toBeFalsy()
159
+
})
160
+
161
+
test('should handle mixed root and nested files', () => {
162
+
const files: UploadedFile[] = [
163
+
{
164
+
name: 'mysite/index.html',
165
+
content: Buffer.from('<html>'),
166
+
mimeType: 'text/html',
167
+
size: 6
168
+
},
169
+
{
170
+
name: 'mysite/about/index.html',
171
+
content: Buffer.from('<html>'),
172
+
mimeType: 'text/html',
173
+
size: 6
174
+
},
175
+
{
176
+
name: 'mysite/about/team.html',
177
+
content: Buffer.from('<html>'),
178
+
mimeType: 'text/html',
179
+
size: 6
180
+
},
181
+
{
182
+
name: 'mysite/robots.txt',
183
+
content: Buffer.from('User-agent: *'),
184
+
mimeType: 'text/plain',
185
+
size: 13
186
+
}
187
+
]
188
+
189
+
const result = processUploadedFiles(files)
190
+
191
+
expect(result.fileCount).toBe(4)
192
+
expect(result.directory.entries).toHaveLength(3) // index.html, about/, robots.txt
193
+
194
+
const aboutEntry = result.directory.entries.find(e => e.name === 'about')
195
+
expect(aboutEntry).toBeTruthy()
196
+
expect('type' in aboutEntry!.node && aboutEntry!.node.type).toBe('directory')
197
+
198
+
if ('entries' in aboutEntry!.node) {
199
+
const aboutDir = aboutEntry!.node
200
+
expect(aboutDir.entries).toHaveLength(2) // index.html, team.html
201
+
expect(aboutDir.entries.find(e => e.name === 'index.html')).toBeTruthy()
202
+
expect(aboutDir.entries.find(e => e.name === 'team.html')).toBeTruthy()
203
+
}
204
+
})
205
+
206
+
test('should handle empty file array', () => {
207
+
const files: UploadedFile[] = []
208
+
209
+
const result = processUploadedFiles(files)
210
+
211
+
expect(result.fileCount).toBe(0)
212
+
expect(result.directory.entries).toHaveLength(0)
213
+
})
214
+
215
+
test('should strip base folder name from paths', () => {
216
+
// This tests the behavior where file.name includes the base folder
217
+
// e.g., "mysite/index.html" should become "index.html" at root
218
+
const files: UploadedFile[] = [
219
+
{
220
+
name: 'build-output/index.html',
221
+
content: Buffer.from('<html>'),
222
+
mimeType: 'text/html',
223
+
size: 6
224
+
},
225
+
{
226
+
name: 'build-output/assets/main.js',
227
+
content: Buffer.from('console.log()'),
228
+
mimeType: 'application/javascript',
229
+
size: 13
230
+
}
231
+
]
232
+
233
+
const result = processUploadedFiles(files)
234
+
235
+
expect(result.fileCount).toBe(2)
236
+
237
+
// Should have index.html at root and assets/ directory
238
+
expect(result.directory.entries.find(e => e.name === 'index.html')).toBeTruthy()
239
+
expect(result.directory.entries.find(e => e.name === 'assets')).toBeTruthy()
240
+
241
+
// Should NOT have 'build-output' directory
242
+
expect(result.directory.entries.find(e => e.name === 'build-output')).toBeFalsy()
243
+
})
244
+
})
-59
packages/@wisp/lexicons/lexicons/fs.json
-59
packages/@wisp/lexicons/lexicons/fs.json
···
1
-
{
2
-
"lexicon": 1,
3
-
"id": "place.wisp.fs",
4
-
"defs": {
5
-
"main": {
6
-
"type": "record",
7
-
"description": "Virtual filesystem manifest for a Wisp site",
8
-
"record": {
9
-
"type": "object",
10
-
"required": ["site", "root", "createdAt"],
11
-
"properties": {
12
-
"site": { "type": "string" },
13
-
"root": { "type": "ref", "ref": "#directory" },
14
-
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
15
-
"createdAt": { "type": "string", "format": "datetime" }
16
-
}
17
-
}
18
-
},
19
-
"file": {
20
-
"type": "object",
21
-
"required": ["type", "blob"],
22
-
"properties": {
23
-
"type": { "type": "string", "const": "file" },
24
-
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
25
-
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
26
-
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
27
-
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" } }
28
-
},
29
-
"directory": {
30
-
"type": "object",
31
-
"required": ["type", "entries"],
32
-
"properties": {
33
-
"type": { "type": "string", "const": "directory" },
34
-
"entries": {
35
-
"type": "array",
36
-
"maxLength": 500,
37
-
"items": { "type": "ref", "ref": "#entry" }
38
-
}
39
-
}
40
-
},
41
-
"entry": {
42
-
"type": "object",
43
-
"required": ["name", "node"],
44
-
"properties": {
45
-
"name": { "type": "string", "maxLength": 255 },
46
-
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
-
}
48
-
},
49
-
"subfs": {
50
-
"type": "object",
51
-
"required": ["type", "subject"],
52
-
"properties": {
53
-
"type": { "type": "string", "const": "subfs" },
54
-
"subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to a place.wisp.subfs record containing this subtree." },
55
-
"flat": { "type": "boolean", "description": "If true (default), the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false, the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure." }
56
-
}
57
-
}
58
-
}
59
-
}
-76
packages/@wisp/lexicons/lexicons/settings.json
-76
packages/@wisp/lexicons/lexicons/settings.json
···
1
-
{
2
-
"lexicon": 1,
3
-
"id": "place.wisp.settings",
4
-
"defs": {
5
-
"main": {
6
-
"type": "record",
7
-
"description": "Configuration settings for a static site hosted on wisp.place",
8
-
"key": "any",
9
-
"record": {
10
-
"type": "object",
11
-
"properties": {
12
-
"directoryListing": {
13
-
"type": "boolean",
14
-
"description": "Enable directory listing mode for paths that resolve to directories without an index file. Incompatible with spaMode.",
15
-
"default": false
16
-
},
17
-
"spaMode": {
18
-
"type": "string",
19
-
"description": "File to serve for all routes (e.g., 'index.html'). When set, enables SPA mode where all non-file requests are routed to this file. Incompatible with directoryListing and custom404.",
20
-
"maxLength": 500
21
-
},
22
-
"custom404": {
23
-
"type": "string",
24
-
"description": "Custom 404 error page file path. Incompatible with directoryListing and spaMode.",
25
-
"maxLength": 500
26
-
},
27
-
"indexFiles": {
28
-
"type": "array",
29
-
"description": "Ordered list of files to try when serving a directory. Defaults to ['index.html'] if not specified.",
30
-
"items": {
31
-
"type": "string",
32
-
"maxLength": 255
33
-
},
34
-
"maxLength": 10
35
-
},
36
-
"cleanUrls": {
37
-
"type": "boolean",
38
-
"description": "Enable clean URL routing. When enabled, '/about' will attempt to serve '/about.html' or '/about/index.html' automatically.",
39
-
"default": false
40
-
},
41
-
"headers": {
42
-
"type": "array",
43
-
"description": "Custom HTTP headers to set on responses",
44
-
"items": {
45
-
"type": "ref",
46
-
"ref": "#customHeader"
47
-
},
48
-
"maxLength": 50
49
-
}
50
-
}
51
-
}
52
-
},
53
-
"customHeader": {
54
-
"type": "object",
55
-
"description": "Custom HTTP header configuration",
56
-
"required": ["name", "value"],
57
-
"properties": {
58
-
"name": {
59
-
"type": "string",
60
-
"description": "HTTP header name (e.g., 'Cache-Control', 'X-Frame-Options')",
61
-
"maxLength": 100
62
-
},
63
-
"value": {
64
-
"type": "string",
65
-
"description": "HTTP header value",
66
-
"maxLength": 1000
67
-
},
68
-
"path": {
69
-
"type": "string",
70
-
"description": "Optional glob pattern to apply this header to specific paths (e.g., '*.html', '/assets/*'). If not specified, applies to all paths.",
71
-
"maxLength": 500
72
-
}
73
-
}
74
-
}
75
-
}
76
-
}
-59
packages/@wisp/lexicons/lexicons/subfs.json
-59
packages/@wisp/lexicons/lexicons/subfs.json
···
1
-
{
2
-
"lexicon": 1,
3
-
"id": "place.wisp.subfs",
4
-
"defs": {
5
-
"main": {
6
-
"type": "record",
7
-
"description": "Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.",
8
-
"record": {
9
-
"type": "object",
10
-
"required": ["root", "createdAt"],
11
-
"properties": {
12
-
"root": { "type": "ref", "ref": "#directory" },
13
-
"fileCount": { "type": "integer", "minimum": 0, "maximum": 1000 },
14
-
"createdAt": { "type": "string", "format": "datetime" }
15
-
}
16
-
}
17
-
},
18
-
"file": {
19
-
"type": "object",
20
-
"required": ["type", "blob"],
21
-
"properties": {
22
-
"type": { "type": "string", "const": "file" },
23
-
"blob": { "type": "blob", "accept": ["*/*"], "maxSize": 1000000000, "description": "Content blob ref" },
24
-
"encoding": { "type": "string", "enum": ["gzip"], "description": "Content encoding (e.g., gzip for compressed files)" },
25
-
"mimeType": { "type": "string", "description": "Original MIME type before compression" },
26
-
"base64": { "type": "boolean", "description": "True if blob content is base64-encoded (used to bypass PDS content sniffing)" }
27
-
}
28
-
},
29
-
"directory": {
30
-
"type": "object",
31
-
"required": ["type", "entries"],
32
-
"properties": {
33
-
"type": { "type": "string", "const": "directory" },
34
-
"entries": {
35
-
"type": "array",
36
-
"maxLength": 500,
37
-
"items": { "type": "ref", "ref": "#entry" }
38
-
}
39
-
}
40
-
},
41
-
"entry": {
42
-
"type": "object",
43
-
"required": ["name", "node"],
44
-
"properties": {
45
-
"name": { "type": "string", "maxLength": 255 },
46
-
"node": { "type": "union", "refs": ["#file", "#directory", "#subfs"] }
47
-
}
48
-
},
49
-
"subfs": {
50
-
"type": "object",
51
-
"required": ["type", "subject"],
52
-
"properties": {
53
-
"type": { "type": "string", "const": "subfs" },
54
-
"subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures." }
55
-
}
56
-
}
57
-
}
58
-
}
59
-
+1
-1
packages/@wisp/lexicons/package.json
+1
-1
packages/@wisp/lexicons/package.json
+1
-1
packages/@wisp/lexicons/src/index.ts
+1
-1
packages/@wisp/lexicons/src/index.ts
···
9
9
type MethodConfigOrHandler,
10
10
createServer as createXrpcServer,
11
11
} from '@atproto/xrpc-server'
12
-
import { schemas } from './lexicons'
12
+
import { schemas } from './lexicons.js'
13
13
14
14
export function createServer(options?: XrpcOptions): Server {
15
15
return new Server(options)
+1
-1
packages/@wisp/lexicons/src/lexicons.ts
+1
-1
packages/@wisp/lexicons/src/lexicons.ts
+33
packages/@wisp/observability/.env.example
+33
packages/@wisp/observability/.env.example
···
1
+
# Grafana Cloud Configuration for @wisp/observability
2
+
# Copy this file to .env and fill in your actual values
3
+
4
+
# ============================================================================
5
+
# Grafana Loki (for logs)
6
+
# ============================================================================
7
+
GRAFANA_LOKI_URL=https://logs-prod-xxx.grafana.net
8
+
9
+
# Authentication Option 1: Bearer Token (Grafana Cloud)
10
+
GRAFANA_LOKI_TOKEN=glc_xxx
11
+
12
+
# Authentication Option 2: Username/Password (Self-hosted or some Grafana setups)
13
+
# GRAFANA_LOKI_USERNAME=your-username
14
+
# GRAFANA_LOKI_PASSWORD=your-password
15
+
16
+
# ============================================================================
17
+
# Grafana Prometheus (for metrics)
18
+
# ============================================================================
19
+
# Note: Add /api/prom to the base URL for OTLP export
20
+
GRAFANA_PROMETHEUS_URL=https://prometheus-prod-xxx.grafana.net/api/prom
21
+
22
+
# Authentication Option 1: Bearer Token (Grafana Cloud)
23
+
GRAFANA_PROMETHEUS_TOKEN=glc_xxx
24
+
25
+
# Authentication Option 2: Username/Password (Self-hosted or some Grafana setups)
26
+
# GRAFANA_PROMETHEUS_USERNAME=your-username
27
+
# GRAFANA_PROMETHEUS_PASSWORD=your-password
28
+
29
+
# ============================================================================
30
+
# Optional: Override service metadata
31
+
# ============================================================================
32
+
# SERVICE_NAME=wisp-app
33
+
# SERVICE_VERSION=1.0.0
+217
packages/@wisp/observability/README.md
+217
packages/@wisp/observability/README.md
···
1
+
# @wisp/observability
2
+
3
+
Framework-agnostic observability package with Grafana integration for logs and metrics persistence.
4
+
5
+
## Features
6
+
7
+
- **In-memory storage** for local development
8
+
- **Grafana Loki** integration for log persistence
9
+
- **Prometheus/OTLP** integration for metrics
10
+
- Framework middleware for Elysia and Hono
11
+
- Automatic batching and buffering for efficient data transmission
12
+
13
+
## Installation
14
+
15
+
```bash
16
+
bun add @wisp/observability
17
+
```
18
+
19
+
## Basic Usage
20
+
21
+
### Without Grafana (In-Memory Only)
22
+
23
+
```typescript
24
+
import { createLogger, metricsCollector } from '@wisp/observability'
25
+
26
+
const logger = createLogger('my-service')
27
+
28
+
// Log messages
29
+
logger.info('Server started')
30
+
logger.error('Failed to connect', new Error('Connection refused'))
31
+
32
+
// Record metrics
33
+
metricsCollector.recordRequest('/api/users', 'GET', 200, 45, 'my-service')
34
+
```
35
+
36
+
### With Grafana Integration
37
+
38
+
```typescript
39
+
import { initializeGrafanaExporters, createLogger } from '@wisp/observability'
40
+
41
+
// Initialize at application startup
42
+
initializeGrafanaExporters({
43
+
lokiUrl: 'https://logs-prod.grafana.net',
44
+
lokiAuth: {
45
+
bearerToken: 'your-loki-api-key'
46
+
},
47
+
prometheusUrl: 'https://prometheus-prod.grafana.net',
48
+
prometheusAuth: {
49
+
bearerToken: 'your-prometheus-api-key'
50
+
},
51
+
serviceName: 'wisp-app',
52
+
serviceVersion: '1.0.0',
53
+
batchSize: 100,
54
+
flushIntervalMs: 5000
55
+
})
56
+
57
+
// Now all logs and metrics will be sent to Grafana automatically
58
+
const logger = createLogger('my-service')
59
+
logger.info('This will be sent to Grafana Loki')
60
+
```
61
+
62
+
## Configuration
63
+
64
+
### Environment Variables
65
+
66
+
You can configure Grafana integration using environment variables:
67
+
68
+
```bash
69
+
# Loki configuration
70
+
GRAFANA_LOKI_URL=https://logs-prod.grafana.net
71
+
72
+
# Authentication Option 1: Bearer Token (Grafana Cloud)
73
+
GRAFANA_LOKI_TOKEN=your-loki-api-key
74
+
75
+
# Authentication Option 2: Username/Password (Self-hosted or some Grafana setups)
76
+
GRAFANA_LOKI_USERNAME=your-username
77
+
GRAFANA_LOKI_PASSWORD=your-password
78
+
79
+
# Prometheus configuration
80
+
GRAFANA_PROMETHEUS_URL=https://prometheus-prod.grafana.net/api/prom
81
+
82
+
# Authentication Option 1: Bearer Token (Grafana Cloud)
83
+
GRAFANA_PROMETHEUS_TOKEN=your-prometheus-api-key
84
+
85
+
# Authentication Option 2: Username/Password (Self-hosted or some Grafana setups)
86
+
GRAFANA_PROMETHEUS_USERNAME=your-username
87
+
GRAFANA_PROMETHEUS_PASSWORD=your-password
88
+
```
89
+
90
+
### Programmatic Configuration
91
+
92
+
```typescript
93
+
import { initializeGrafanaExporters } from '@wisp/observability'
94
+
95
+
initializeGrafanaExporters({
96
+
// Loki configuration for logs
97
+
lokiUrl: 'https://logs-prod.grafana.net',
98
+
lokiAuth: {
99
+
// Option 1: Bearer token (recommended for Grafana Cloud)
100
+
bearerToken: 'your-api-key',
101
+
102
+
// Option 2: Basic auth
103
+
username: 'your-username',
104
+
password: 'your-password'
105
+
},
106
+
107
+
// Prometheus/OTLP configuration for metrics
108
+
prometheusUrl: 'https://prometheus-prod.grafana.net',
109
+
prometheusAuth: {
110
+
bearerToken: 'your-api-key'
111
+
},
112
+
113
+
// Service metadata
114
+
serviceName: 'wisp-app',
115
+
serviceVersion: '1.0.0',
116
+
117
+
// Batching configuration
118
+
batchSize: 100, // Flush after this many entries
119
+
flushIntervalMs: 5000, // Flush every 5 seconds
120
+
121
+
// Enable/disable exporters
122
+
enabled: true
123
+
})
124
+
```
125
+
126
+
## Middleware Integration
127
+
128
+
### Elysia
129
+
130
+
```typescript
131
+
import { Elysia } from 'elysia'
132
+
import { observabilityMiddleware } from '@wisp/observability/middleware/elysia'
133
+
import { initializeGrafanaExporters } from '@wisp/observability'
134
+
135
+
// Initialize Grafana exporters
136
+
initializeGrafanaExporters({
137
+
lokiUrl: process.env.GRAFANA_LOKI_URL,
138
+
lokiAuth: { bearerToken: process.env.GRAFANA_LOKI_TOKEN }
139
+
})
140
+
141
+
const app = new Elysia()
142
+
.use(observabilityMiddleware({ service: 'main-app' }))
143
+
.get('/', () => 'Hello World')
144
+
.listen(3000)
145
+
```
146
+
147
+
### Hono
148
+
149
+
```typescript
150
+
import { Hono } from 'hono'
151
+
import { observabilityMiddleware, observabilityErrorHandler } from '@wisp/observability/middleware/hono'
152
+
import { initializeGrafanaExporters } from '@wisp/observability'
153
+
154
+
// Initialize Grafana exporters
155
+
initializeGrafanaExporters({
156
+
lokiUrl: process.env.GRAFANA_LOKI_URL,
157
+
lokiAuth: { bearerToken: process.env.GRAFANA_LOKI_TOKEN }
158
+
})
159
+
160
+
const app = new Hono()
161
+
app.use('*', observabilityMiddleware({ service: 'hosting-service' }))
162
+
app.onError(observabilityErrorHandler({ service: 'hosting-service' }))
163
+
```
164
+
165
+
## Grafana Cloud Setup
166
+
167
+
1. **Create a Grafana Cloud account** at https://grafana.com/
168
+
169
+
2. **Get your Loki credentials:**
170
+
- Go to your Grafana Cloud portal
171
+
- Navigate to "Loki" โ "Details"
172
+
- Copy the Push endpoint URL and create an API key
173
+
174
+
3. **Get your Prometheus credentials:**
175
+
- Navigate to "Prometheus" โ "Details"
176
+
- Copy the Remote Write endpoint and create an API key
177
+
178
+
4. **Configure your application:**
179
+
```typescript
180
+
initializeGrafanaExporters({
181
+
lokiUrl: 'https://logs-prod-xxx.grafana.net',
182
+
lokiAuth: { bearerToken: 'glc_xxx' },
183
+
prometheusUrl: 'https://prometheus-prod-xxx.grafana.net/api/prom',
184
+
prometheusAuth: { bearerToken: 'glc_xxx' }
185
+
})
186
+
```
187
+
188
+
## Data Flow
189
+
190
+
1. **Logs** โ Buffered โ Batched โ Sent to Grafana Loki
191
+
2. **Metrics** โ Aggregated โ Exported via OTLP โ Sent to Prometheus
192
+
3. **Errors** โ Deduplicated โ Sent to Loki with error tag
193
+
194
+
## Performance Considerations
195
+
196
+
- Logs and metrics are batched to reduce network overhead
197
+
- Default batch size: 100 entries
198
+
- Default flush interval: 5 seconds
199
+
- Failed exports are logged but don't block application
200
+
- In-memory buffers are capped to prevent memory leaks
201
+
202
+
## Graceful Shutdown
203
+
204
+
The exporters automatically register shutdown handlers:
205
+
206
+
```typescript
207
+
import { shutdownGrafanaExporters } from '@wisp/observability'
208
+
209
+
// Manual shutdown if needed
210
+
process.on('beforeExit', async () => {
211
+
await shutdownGrafanaExporters()
212
+
})
213
+
```
214
+
215
+
## License
216
+
217
+
MIT
+13
-1
packages/@wisp/observability/package.json
+13
-1
packages/@wisp/observability/package.json
···
24
24
}
25
25
},
26
26
"peerDependencies": {
27
-
"hono": "^4.0.0"
27
+
"hono": "^4.10.7"
28
28
},
29
29
"peerDependenciesMeta": {
30
30
"hono": {
31
31
"optional": true
32
32
}
33
+
},
34
+
"dependencies": {
35
+
"@opentelemetry/api": "^1.9.0",
36
+
"@opentelemetry/sdk-metrics": "^1.29.0",
37
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.56.0",
38
+
"@opentelemetry/resources": "^1.29.0",
39
+
"@opentelemetry/semantic-conventions": "^1.29.0"
40
+
},
41
+
"devDependencies": {
42
+
"@hono/node-server": "^1.19.6",
43
+
"bun-types": "^1.3.3",
44
+
"typescript": "^5.9.3"
33
45
}
34
46
}
+12
-2
packages/@wisp/observability/src/core.ts
+12
-2
packages/@wisp/observability/src/core.ts
···
3
3
* Framework-agnostic logging, error tracking, and metrics collection
4
4
*/
5
5
6
+
import { lokiExporter, metricsExporter } from './exporters'
7
+
6
8
// ============================================================================
7
9
// Types
8
10
// ============================================================================
···
128
130
logs.splice(MAX_LOGS)
129
131
}
130
132
133
+
// Send to Loki exporter
134
+
lokiExporter.pushLog(entry)
135
+
131
136
// Also log to console for compatibility
132
137
const contextStr = context ? ` ${JSON.stringify(context)}` : ''
133
138
const traceStr = traceId ? ` [trace:${traceId}]` : ''
···
163
168
},
164
169
165
170
debug(message: string, service: string, context?: Record<string, any>, traceId?: string) {
166
-
const env = typeof Bun !== 'undefined' ? Bun.env.NODE_ENV : process.env.NODE_ENV;
167
-
if (env !== 'production') {
171
+
if (process.env.NODE_ENV !== 'production') {
168
172
this.log('debug', message, service, context, traceId)
169
173
}
170
174
},
···
233
237
234
238
errors.set(key, entry)
235
239
240
+
// Send to Loki exporter
241
+
lokiExporter.pushError(entry)
242
+
236
243
// Rotate if needed
237
244
if (errors.size > MAX_ERRORS) {
238
245
const oldest = Array.from(errors.keys())[0]
···
284
291
}
285
292
286
293
metrics.unshift(entry)
294
+
295
+
// Send to Prometheus/OTLP exporter
296
+
metricsExporter.recordMetric(entry)
287
297
288
298
// Rotate if needed
289
299
if (metrics.length > MAX_METRICS) {
+433
packages/@wisp/observability/src/exporters.ts
+433
packages/@wisp/observability/src/exporters.ts
···
1
+
/**
2
+
* Grafana exporters for logs and metrics
3
+
* Integrates with Grafana Loki for logs and Prometheus/OTLP for metrics
4
+
*/
5
+
6
+
import type { LogEntry, ErrorEntry, MetricEntry } from './core'
7
+
import { metrics, type MeterProvider } from '@opentelemetry/api'
8
+
import { MeterProvider as SdkMeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
9
+
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
10
+
import { Resource } from '@opentelemetry/resources'
11
+
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'
12
+
13
+
// ============================================================================
14
+
// Types
15
+
// ============================================================================
16
+
17
+
export interface GrafanaConfig {
18
+
lokiUrl?: string
19
+
lokiAuth?: {
20
+
username?: string
21
+
password?: string
22
+
bearerToken?: string
23
+
}
24
+
prometheusUrl?: string
25
+
prometheusAuth?: {
26
+
username?: string
27
+
password?: string
28
+
bearerToken?: string
29
+
}
30
+
serviceName?: string
31
+
serviceVersion?: string
32
+
batchSize?: number
33
+
flushIntervalMs?: number
34
+
enabled?: boolean
35
+
}
36
+
37
+
interface LokiStream {
38
+
stream: Record<string, string>
39
+
values: Array<[string, string]>
40
+
}
41
+
42
+
interface LokiBatch {
43
+
streams: LokiStream[]
44
+
}
45
+
46
+
// ============================================================================
47
+
// Configuration
48
+
// ============================================================================
49
+
50
+
class GrafanaExporterConfig {
51
+
private config: GrafanaConfig = {
52
+
enabled: false,
53
+
batchSize: 100,
54
+
flushIntervalMs: 5000,
55
+
serviceName: 'wisp-app',
56
+
serviceVersion: '1.0.0'
57
+
}
58
+
59
+
initialize(config: GrafanaConfig) {
60
+
this.config = { ...this.config, ...config }
61
+
62
+
// Load from environment variables if not provided
63
+
if (!this.config.lokiUrl) {
64
+
this.config.lokiUrl = process.env.GRAFANA_LOKI_URL
65
+
}
66
+
67
+
if (!this.config.prometheusUrl) {
68
+
this.config.prometheusUrl = process.env.GRAFANA_PROMETHEUS_URL
69
+
}
70
+
71
+
// Load Loki authentication from environment
72
+
if (!this.config.lokiAuth?.bearerToken && !this.config.lokiAuth?.username) {
73
+
const token = process.env.GRAFANA_LOKI_TOKEN
74
+
const username = process.env.GRAFANA_LOKI_USERNAME
75
+
const password = process.env.GRAFANA_LOKI_PASSWORD
76
+
77
+
if (token) {
78
+
this.config.lokiAuth = { ...this.config.lokiAuth, bearerToken: token }
79
+
} else if (username && password) {
80
+
this.config.lokiAuth = { ...this.config.lokiAuth, username, password }
81
+
}
82
+
}
83
+
84
+
// Load Prometheus authentication from environment
85
+
if (!this.config.prometheusAuth?.bearerToken && !this.config.prometheusAuth?.username) {
86
+
const token = process.env.GRAFANA_PROMETHEUS_TOKEN
87
+
const username = process.env.GRAFANA_PROMETHEUS_USERNAME
88
+
const password = process.env.GRAFANA_PROMETHEUS_PASSWORD
89
+
90
+
if (token) {
91
+
this.config.prometheusAuth = { ...this.config.prometheusAuth, bearerToken: token }
92
+
} else if (username && password) {
93
+
this.config.prometheusAuth = { ...this.config.prometheusAuth, username, password }
94
+
}
95
+
}
96
+
97
+
// Enable if URLs are configured
98
+
if (this.config.lokiUrl || this.config.prometheusUrl) {
99
+
this.config.enabled = true
100
+
}
101
+
102
+
return this
103
+
}
104
+
105
+
getConfig(): GrafanaConfig {
106
+
return { ...this.config }
107
+
}
108
+
109
+
isEnabled(): boolean {
110
+
return this.config.enabled === true
111
+
}
112
+
}
113
+
114
+
export const grafanaConfig = new GrafanaExporterConfig()
115
+
116
+
// ============================================================================
117
+
// Loki Exporter for Logs
118
+
// ============================================================================
119
+
120
+
class LokiExporter {
121
+
private buffer: LogEntry[] = []
122
+
private errorBuffer: ErrorEntry[] = []
123
+
private flushTimer?: NodeJS.Timeout
124
+
private config: GrafanaConfig = {}
125
+
126
+
initialize(config: GrafanaConfig) {
127
+
this.config = config
128
+
129
+
if (this.config.enabled && this.config.lokiUrl) {
130
+
this.startBatching()
131
+
}
132
+
}
133
+
134
+
private startBatching() {
135
+
const interval = this.config.flushIntervalMs || 5000
136
+
137
+
this.flushTimer = setInterval(() => {
138
+
this.flush()
139
+
}, interval)
140
+
}
141
+
142
+
stop() {
143
+
if (this.flushTimer) {
144
+
clearInterval(this.flushTimer)
145
+
this.flushTimer = undefined
146
+
}
147
+
// Final flush
148
+
this.flush()
149
+
}
150
+
151
+
pushLog(entry: LogEntry) {
152
+
if (!this.config.enabled || !this.config.lokiUrl) return
153
+
154
+
this.buffer.push(entry)
155
+
156
+
const batchSize = this.config.batchSize || 100
157
+
if (this.buffer.length >= batchSize) {
158
+
this.flush()
159
+
}
160
+
}
161
+
162
+
pushError(entry: ErrorEntry) {
163
+
if (!this.config.enabled || !this.config.lokiUrl) return
164
+
165
+
this.errorBuffer.push(entry)
166
+
167
+
const batchSize = this.config.batchSize || 100
168
+
if (this.errorBuffer.length >= batchSize) {
169
+
this.flush()
170
+
}
171
+
}
172
+
173
+
private async flush() {
174
+
if (!this.config.lokiUrl) return
175
+
176
+
const logsToSend = [...this.buffer]
177
+
const errorsToSend = [...this.errorBuffer]
178
+
179
+
this.buffer = []
180
+
this.errorBuffer = []
181
+
182
+
if (logsToSend.length === 0 && errorsToSend.length === 0) return
183
+
184
+
try {
185
+
const batch = this.createLokiBatch(logsToSend, errorsToSend)
186
+
await this.sendToLoki(batch)
187
+
} catch (error) {
188
+
console.error('[LokiExporter] Failed to send logs to Loki:', error)
189
+
// Optionally re-queue failed logs
190
+
}
191
+
}
192
+
193
+
private createLokiBatch(logs: LogEntry[], errors: ErrorEntry[]): LokiBatch {
194
+
const streams: LokiStream[] = []
195
+
196
+
// Group logs by service and level
197
+
const logGroups = new Map<string, LogEntry[]>()
198
+
199
+
for (const log of logs) {
200
+
const key = `${log.service}-${log.level}`
201
+
const group = logGroups.get(key) || []
202
+
group.push(log)
203
+
logGroups.set(key, group)
204
+
}
205
+
206
+
// Create streams for logs
207
+
for (const [key, entries] of logGroups) {
208
+
const [service, level] = key.split('-')
209
+
const values: Array<[string, string]> = entries.map(entry => {
210
+
const logLine = JSON.stringify({
211
+
message: entry.message,
212
+
context: entry.context,
213
+
traceId: entry.traceId,
214
+
eventType: entry.eventType
215
+
})
216
+
217
+
// Loki expects nanosecond timestamp as string
218
+
const nanoTimestamp = String(entry.timestamp.getTime() * 1000000)
219
+
return [nanoTimestamp, logLine]
220
+
})
221
+
222
+
streams.push({
223
+
stream: {
224
+
service: service || 'unknown',
225
+
level: level || 'info',
226
+
job: this.config.serviceName || 'wisp-app'
227
+
},
228
+
values
229
+
})
230
+
}
231
+
232
+
// Create streams for errors
233
+
if (errors.length > 0) {
234
+
const errorValues: Array<[string, string]> = errors.map(entry => {
235
+
const logLine = JSON.stringify({
236
+
message: entry.message,
237
+
stack: entry.stack,
238
+
context: entry.context,
239
+
count: entry.count
240
+
})
241
+
242
+
const nanoTimestamp = String(entry.timestamp.getTime() * 1000000)
243
+
return [nanoTimestamp, logLine]
244
+
})
245
+
246
+
streams.push({
247
+
stream: {
248
+
service: errors[0]?.service || 'unknown',
249
+
level: 'error',
250
+
job: this.config.serviceName || 'wisp-app',
251
+
type: 'aggregated_error'
252
+
},
253
+
values: errorValues
254
+
})
255
+
}
256
+
257
+
return { streams }
258
+
}
259
+
260
+
private async sendToLoki(batch: LokiBatch) {
261
+
if (!this.config.lokiUrl) return
262
+
263
+
const headers: Record<string, string> = {
264
+
'Content-Type': 'application/json'
265
+
}
266
+
267
+
// Add authentication
268
+
if (this.config.lokiAuth?.bearerToken) {
269
+
headers['Authorization'] = `Bearer ${this.config.lokiAuth.bearerToken}`
270
+
} else if (this.config.lokiAuth?.username && this.config.lokiAuth?.password) {
271
+
const auth = Buffer.from(`${this.config.lokiAuth.username}:${this.config.lokiAuth.password}`).toString('base64')
272
+
headers['Authorization'] = `Basic ${auth}`
273
+
}
274
+
275
+
const response = await fetch(`${this.config.lokiUrl}/loki/api/v1/push`, {
276
+
method: 'POST',
277
+
headers,
278
+
body: JSON.stringify(batch)
279
+
})
280
+
281
+
if (!response.ok) {
282
+
const text = await response.text()
283
+
throw new Error(`Loki push failed: ${response.status} - ${text}`)
284
+
}
285
+
}
286
+
}
287
+
288
+
// ============================================================================
289
+
// OpenTelemetry Metrics Exporter
290
+
// ============================================================================
291
+
292
+
class MetricsExporter {
293
+
private meterProvider?: MeterProvider
294
+
private requestCounter?: any
295
+
private requestDuration?: any
296
+
private errorCounter?: any
297
+
private config: GrafanaConfig = {}
298
+
299
+
initialize(config: GrafanaConfig) {
300
+
this.config = config
301
+
302
+
if (!this.config.enabled || !this.config.prometheusUrl) return
303
+
304
+
// Create OTLP exporter with Prometheus endpoint
305
+
const exporter = new OTLPMetricExporter({
306
+
url: `${this.config.prometheusUrl}/v1/metrics`,
307
+
headers: this.getAuthHeaders(),
308
+
timeoutMillis: 10000
309
+
})
310
+
311
+
// Create meter provider with periodic exporting
312
+
const meterProvider = new SdkMeterProvider({
313
+
resource: new Resource({
314
+
[ATTR_SERVICE_NAME]: this.config.serviceName || 'wisp-app',
315
+
[ATTR_SERVICE_VERSION]: this.config.serviceVersion || '1.0.0'
316
+
}),
317
+
readers: [
318
+
new PeriodicExportingMetricReader({
319
+
exporter,
320
+
exportIntervalMillis: this.config.flushIntervalMs || 5000
321
+
})
322
+
]
323
+
})
324
+
325
+
// Set global meter provider
326
+
metrics.setGlobalMeterProvider(meterProvider)
327
+
this.meterProvider = meterProvider
328
+
329
+
// Create metrics instruments
330
+
const meter = metrics.getMeter(this.config.serviceName || 'wisp-app')
331
+
332
+
this.requestCounter = meter.createCounter('http_requests_total', {
333
+
description: 'Total number of HTTP requests'
334
+
})
335
+
336
+
this.requestDuration = meter.createHistogram('http_request_duration_ms', {
337
+
description: 'HTTP request duration in milliseconds',
338
+
unit: 'ms'
339
+
})
340
+
341
+
this.errorCounter = meter.createCounter('errors_total', {
342
+
description: 'Total number of errors'
343
+
})
344
+
}
345
+
346
+
private getAuthHeaders(): Record<string, string> {
347
+
const headers: Record<string, string> = {}
348
+
349
+
if (this.config.prometheusAuth?.bearerToken) {
350
+
headers['Authorization'] = `Bearer ${this.config.prometheusAuth.bearerToken}`
351
+
} else if (this.config.prometheusAuth?.username && this.config.prometheusAuth?.password) {
352
+
const auth = Buffer.from(`${this.config.prometheusAuth.username}:${this.config.prometheusAuth.password}`).toString('base64')
353
+
headers['Authorization'] = `Basic ${auth}`
354
+
}
355
+
356
+
return headers
357
+
}
358
+
359
+
recordMetric(entry: MetricEntry) {
360
+
if (!this.config.enabled) return
361
+
362
+
const attributes = {
363
+
method: entry.method,
364
+
path: entry.path,
365
+
status: String(entry.statusCode),
366
+
service: entry.service
367
+
}
368
+
369
+
// Record request count
370
+
this.requestCounter?.add(1, attributes)
371
+
372
+
// Record request duration
373
+
this.requestDuration?.record(entry.duration, attributes)
374
+
375
+
// Record errors
376
+
if (entry.statusCode >= 400) {
377
+
this.errorCounter?.add(1, attributes)
378
+
}
379
+
}
380
+
381
+
async shutdown() {
382
+
if (this.meterProvider && 'shutdown' in this.meterProvider) {
383
+
await (this.meterProvider as SdkMeterProvider).shutdown()
384
+
}
385
+
}
386
+
}
387
+
388
+
// ============================================================================
389
+
// Singleton Instances
390
+
// ============================================================================
391
+
392
+
export const lokiExporter = new LokiExporter()
393
+
export const metricsExporter = new MetricsExporter()
394
+
395
+
// ============================================================================
396
+
// Initialization
397
+
// ============================================================================
398
+
399
+
export function initializeGrafanaExporters(config?: GrafanaConfig) {
400
+
const finalConfig = grafanaConfig.initialize(config || {}).getConfig()
401
+
402
+
if (finalConfig.enabled) {
403
+
console.log('[Observability] Initializing Grafana exporters', {
404
+
lokiEnabled: !!finalConfig.lokiUrl,
405
+
prometheusEnabled: !!finalConfig.prometheusUrl,
406
+
serviceName: finalConfig.serviceName
407
+
})
408
+
409
+
lokiExporter.initialize(finalConfig)
410
+
metricsExporter.initialize(finalConfig)
411
+
}
412
+
413
+
return {
414
+
lokiExporter,
415
+
metricsExporter,
416
+
config: finalConfig
417
+
}
418
+
}
419
+
420
+
// ============================================================================
421
+
// Cleanup
422
+
// ============================================================================
423
+
424
+
export async function shutdownGrafanaExporters() {
425
+
lokiExporter.stop()
426
+
await metricsExporter.shutdown()
427
+
}
428
+
429
+
// Graceful shutdown handlers
430
+
if (typeof process !== 'undefined') {
431
+
process.on('SIGTERM', shutdownGrafanaExporters)
432
+
process.on('SIGINT', shutdownGrafanaExporters)
433
+
}
+8
packages/@wisp/observability/src/index.ts
+8
packages/@wisp/observability/src/index.ts
···
6
6
// Export everything from core
7
7
export * from './core'
8
8
9
+
// Export Grafana integration
10
+
export {
11
+
initializeGrafanaExporters,
12
+
shutdownGrafanaExporters,
13
+
grafanaConfig,
14
+
type GrafanaConfig
15
+
} from './exporters'
16
+
9
17
// Note: Middleware should be imported from specific subpaths:
10
18
// - import { observabilityMiddleware } from '@wisp/observability/middleware/elysia'
11
19
// - import { observabilityMiddleware, observabilityErrorHandler } from '@wisp/observability/middleware/hono'
+336
packages/@wisp/observability/src/integration-test.test.ts
+336
packages/@wisp/observability/src/integration-test.test.ts
···
1
+
/**
2
+
* Integration tests for Grafana exporters
3
+
* Tests both mock server and live server connections
4
+
*/
5
+
6
+
import { describe, test, expect, beforeAll, afterAll } from 'bun:test'
7
+
import { createLogger, metricsCollector, initializeGrafanaExporters, shutdownGrafanaExporters } from './index'
8
+
import { Hono } from 'hono'
9
+
import { serve } from '@hono/node-server'
10
+
import type { ServerType } from '@hono/node-server'
11
+
12
+
// ============================================================================
13
+
// Mock Grafana Server
14
+
// ============================================================================
15
+
16
+
interface MockRequest {
17
+
method: string
18
+
path: string
19
+
headers: Record<string, string>
20
+
body: any
21
+
}
22
+
23
+
class MockGrafanaServer {
24
+
private app: Hono
25
+
private server?: ServerType
26
+
private port: number
27
+
public requests: MockRequest[] = []
28
+
29
+
constructor(port: number) {
30
+
this.port = port
31
+
this.app = new Hono()
32
+
33
+
// Mock Loki endpoint
34
+
this.app.post('/loki/api/v1/push', async (c) => {
35
+
const body = await c.req.json()
36
+
this.requests.push({
37
+
method: 'POST',
38
+
path: '/loki/api/v1/push',
39
+
headers: Object.fromEntries(c.req.raw.headers.entries()),
40
+
body
41
+
})
42
+
return c.json({ status: 'success' })
43
+
})
44
+
45
+
// Mock Prometheus/OTLP endpoint
46
+
this.app.post('/v1/metrics', async (c) => {
47
+
const body = await c.req.json()
48
+
this.requests.push({
49
+
method: 'POST',
50
+
path: '/v1/metrics',
51
+
headers: Object.fromEntries(c.req.raw.headers.entries()),
52
+
body
53
+
})
54
+
return c.json({ status: 'success' })
55
+
})
56
+
57
+
// Health check
58
+
this.app.get('/health', (c) => c.json({ status: 'ok' }))
59
+
}
60
+
61
+
async start() {
62
+
this.server = serve({
63
+
fetch: this.app.fetch,
64
+
port: this.port
65
+
})
66
+
// Wait a bit for server to be ready
67
+
await new Promise(resolve => setTimeout(resolve, 100))
68
+
}
69
+
70
+
async stop() {
71
+
if (this.server) {
72
+
this.server.close()
73
+
this.server = undefined
74
+
}
75
+
}
76
+
77
+
clearRequests() {
78
+
this.requests = []
79
+
}
80
+
81
+
getRequestsByPath(path: string): MockRequest[] {
82
+
return this.requests.filter(r => r.path === path)
83
+
}
84
+
85
+
async waitForRequests(count: number, timeoutMs: number = 10000): Promise<boolean> {
86
+
const startTime = Date.now()
87
+
while (this.requests.length < count) {
88
+
if (Date.now() - startTime > timeoutMs) {
89
+
return false
90
+
}
91
+
await new Promise(resolve => setTimeout(resolve, 100))
92
+
}
93
+
return true
94
+
}
95
+
}
96
+
97
+
// ============================================================================
98
+
// Test Suite
99
+
// ============================================================================
100
+
101
+
describe('Grafana Integration', () => {
102
+
const mockServer = new MockGrafanaServer(9999)
103
+
const mockUrl = 'http://localhost:9999'
104
+
105
+
beforeAll(async () => {
106
+
await mockServer.start()
107
+
})
108
+
109
+
afterAll(async () => {
110
+
await mockServer.stop()
111
+
await shutdownGrafanaExporters()
112
+
})
113
+
114
+
test('should initialize with username/password auth', () => {
115
+
const config = initializeGrafanaExporters({
116
+
lokiUrl: mockUrl,
117
+
lokiAuth: {
118
+
username: 'testuser',
119
+
password: 'testpass'
120
+
},
121
+
prometheusUrl: mockUrl,
122
+
prometheusAuth: {
123
+
username: 'testuser',
124
+
password: 'testpass'
125
+
},
126
+
serviceName: 'test-service',
127
+
batchSize: 5,
128
+
flushIntervalMs: 1000
129
+
})
130
+
131
+
expect(config.config.enabled).toBe(true)
132
+
expect(config.config.lokiUrl).toBe(mockUrl)
133
+
expect(config.config.prometheusUrl).toBe(mockUrl)
134
+
expect(config.config.lokiAuth?.username).toBe('testuser')
135
+
expect(config.config.prometheusAuth?.username).toBe('testuser')
136
+
})
137
+
138
+
test('should send logs to Loki with basic auth', async () => {
139
+
mockServer.clearRequests()
140
+
141
+
// Initialize with username/password
142
+
initializeGrafanaExporters({
143
+
lokiUrl: mockUrl,
144
+
lokiAuth: {
145
+
username: 'testuser',
146
+
password: 'testpass'
147
+
},
148
+
serviceName: 'test-logs',
149
+
batchSize: 2,
150
+
flushIntervalMs: 500
151
+
})
152
+
153
+
const logger = createLogger('test-logs')
154
+
155
+
// Generate logs that will trigger batch flush
156
+
logger.info('Test message 1')
157
+
logger.warn('Test message 2')
158
+
159
+
// Wait for batch to be sent
160
+
const success = await mockServer.waitForRequests(1, 5000)
161
+
expect(success).toBe(true)
162
+
163
+
const lokiRequests = mockServer.getRequestsByPath('/loki/api/v1/push')
164
+
expect(lokiRequests.length).toBeGreaterThanOrEqual(1)
165
+
166
+
const lastRequest = lokiRequests[lokiRequests.length - 1]!
167
+
168
+
// Verify basic auth header
169
+
expect(lastRequest.headers['authorization']).toMatch(/^Basic /)
170
+
171
+
// Verify Loki batch format
172
+
expect(lastRequest.body).toHaveProperty('streams')
173
+
expect(Array.isArray(lastRequest.body.streams)).toBe(true)
174
+
expect(lastRequest.body.streams.length).toBeGreaterThan(0)
175
+
176
+
const stream = lastRequest.body.streams[0]!
177
+
expect(stream).toHaveProperty('stream')
178
+
expect(stream).toHaveProperty('values')
179
+
expect(stream.stream.job).toBe('test-logs')
180
+
181
+
await shutdownGrafanaExporters()
182
+
})
183
+
184
+
test('should send metrics to Prometheus with bearer token', async () => {
185
+
mockServer.clearRequests()
186
+
187
+
// Initialize with bearer token only for Prometheus (no Loki)
188
+
initializeGrafanaExporters({
189
+
lokiUrl: undefined, // Explicitly disable Loki
190
+
prometheusUrl: mockUrl,
191
+
prometheusAuth: {
192
+
bearerToken: 'test-token-123'
193
+
},
194
+
serviceName: 'test-metrics',
195
+
flushIntervalMs: 1000
196
+
})
197
+
198
+
// Generate metrics
199
+
for (let i = 0; i < 5; i++) {
200
+
metricsCollector.recordRequest('/api/test', 'GET', 200, 100 + i, 'test-metrics')
201
+
}
202
+
203
+
// Wait for metrics to be exported
204
+
await new Promise(resolve => setTimeout(resolve, 2000))
205
+
206
+
const prometheusRequests = mockServer.getRequestsByPath('/v1/metrics')
207
+
expect(prometheusRequests.length).toBeGreaterThan(0)
208
+
209
+
// Note: Due to singleton exporters, we may see auth from previous test
210
+
// The key thing is that metrics are being sent
211
+
const lastRequest = prometheusRequests[prometheusRequests.length - 1]!
212
+
expect(lastRequest.headers['authorization']).toBeTruthy()
213
+
214
+
await shutdownGrafanaExporters()
215
+
})
216
+
217
+
test('should handle errors gracefully', async () => {
218
+
// Initialize with invalid URL
219
+
const config = initializeGrafanaExporters({
220
+
lokiUrl: 'http://localhost:9998', // Non-existent server
221
+
lokiAuth: {
222
+
username: 'test',
223
+
password: 'test'
224
+
},
225
+
serviceName: 'test-error',
226
+
batchSize: 1,
227
+
flushIntervalMs: 500
228
+
})
229
+
230
+
expect(config.config.enabled).toBe(true)
231
+
232
+
const logger = createLogger('test-error')
233
+
234
+
// This should not throw even though server doesn't exist
235
+
logger.info('This should not crash')
236
+
237
+
// Wait for flush attempt
238
+
await new Promise(resolve => setTimeout(resolve, 1000))
239
+
240
+
// If we got here, error handling worked
241
+
expect(true).toBe(true)
242
+
243
+
await shutdownGrafanaExporters()
244
+
})
245
+
})
246
+
247
+
// ============================================================================
248
+
// Live Server Connection Tests (Optional)
249
+
// ============================================================================
250
+
251
+
describe('Live Grafana Connection (Optional)', () => {
252
+
const hasLiveConfig = Boolean(
253
+
process.env.GRAFANA_LOKI_URL &&
254
+
(process.env.GRAFANA_LOKI_TOKEN ||
255
+
(process.env.GRAFANA_LOKI_USERNAME && process.env.GRAFANA_LOKI_PASSWORD))
256
+
)
257
+
258
+
test.skipIf(!hasLiveConfig)('should connect to live Loki server', async () => {
259
+
const config = initializeGrafanaExporters({
260
+
serviceName: 'test-live-loki',
261
+
serviceVersion: '1.0.0-test',
262
+
batchSize: 5,
263
+
flushIntervalMs: 2000
264
+
})
265
+
266
+
expect(config.config.enabled).toBe(true)
267
+
expect(config.config.lokiUrl).toBeTruthy()
268
+
269
+
const logger = createLogger('test-live-loki')
270
+
271
+
// Send test logs
272
+
logger.info('Live connection test log', { test: true, timestamp: Date.now() })
273
+
logger.warn('Test warning from integration test')
274
+
logger.error('Test error (ignore)', new Error('Test error'), { safe: true })
275
+
276
+
// Wait for flush
277
+
await new Promise(resolve => setTimeout(resolve, 3000))
278
+
279
+
// If we got here without errors, connection worked
280
+
expect(true).toBe(true)
281
+
282
+
await shutdownGrafanaExporters()
283
+
})
284
+
285
+
test.skipIf(!hasLiveConfig)('should connect to live Prometheus server', async () => {
286
+
const hasPrometheusConfig = Boolean(
287
+
process.env.GRAFANA_PROMETHEUS_URL &&
288
+
(process.env.GRAFANA_PROMETHEUS_TOKEN ||
289
+
(process.env.GRAFANA_PROMETHEUS_USERNAME && process.env.GRAFANA_PROMETHEUS_PASSWORD))
290
+
)
291
+
292
+
if (!hasPrometheusConfig) {
293
+
console.log('Skipping Prometheus test - no config provided')
294
+
return
295
+
}
296
+
297
+
const config = initializeGrafanaExporters({
298
+
serviceName: 'test-live-prometheus',
299
+
serviceVersion: '1.0.0-test',
300
+
flushIntervalMs: 2000
301
+
})
302
+
303
+
expect(config.config.enabled).toBe(true)
304
+
expect(config.config.prometheusUrl).toBeTruthy()
305
+
306
+
// Generate test metrics
307
+
for (let i = 0; i < 10; i++) {
308
+
metricsCollector.recordRequest(
309
+
'/test/endpoint',
310
+
'GET',
311
+
200,
312
+
50 + Math.random() * 200,
313
+
'test-live-prometheus'
314
+
)
315
+
}
316
+
317
+
// Wait for export
318
+
await new Promise(resolve => setTimeout(resolve, 3000))
319
+
320
+
expect(true).toBe(true)
321
+
322
+
await shutdownGrafanaExporters()
323
+
})
324
+
})
325
+
326
+
// ============================================================================
327
+
// Manual Test Runner
328
+
// ============================================================================
329
+
330
+
if (import.meta.main) {
331
+
console.log('๐งช Running Grafana integration tests...\n')
332
+
console.log('Live server tests will run if these environment variables are set:')
333
+
console.log(' - GRAFANA_LOKI_URL + (GRAFANA_LOKI_TOKEN or GRAFANA_LOKI_USERNAME/PASSWORD)')
334
+
console.log(' - GRAFANA_PROMETHEUS_URL + (GRAFANA_PROMETHEUS_TOKEN or GRAFANA_PROMETHEUS_USERNAME/PASSWORD)')
335
+
console.log('')
336
+
}
+128
-27
packages/@wisp/safe-fetch/src/index.ts
+128
-27
packages/@wisp/safe-fetch/src/index.ts
···
28
28
const MAX_BLOB_SIZE = 500 * 1024 * 1024; // 500MB
29
29
const MAX_REDIRECTS = 10;
30
30
31
+
// Retry configuration
32
+
const MAX_RETRIES = 3;
33
+
const INITIAL_RETRY_DELAY = 1000; // 1 second
34
+
const MAX_RETRY_DELAY = 10000; // 10 seconds
35
+
31
36
function isBlockedHost(hostname: string): boolean {
32
37
const lowerHost = hostname.toLowerCase();
33
38
···
44
49
return false;
45
50
}
46
51
52
+
/**
53
+
* Check if an error is retryable (network/SSL errors, not HTTP errors)
54
+
*/
55
+
function isRetryableError(err: unknown): boolean {
56
+
if (!(err instanceof Error)) return false;
57
+
58
+
// Network errors (ECONNRESET, ENOTFOUND, etc.)
59
+
const errorCode = (err as any).code;
60
+
if (errorCode) {
61
+
const retryableCodes = [
62
+
'ECONNRESET',
63
+
'ECONNREFUSED',
64
+
'ETIMEDOUT',
65
+
'ENOTFOUND',
66
+
'ENETUNREACH',
67
+
'EAI_AGAIN',
68
+
'EPIPE',
69
+
'ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR', // SSL/TLS handshake failures
70
+
'ERR_SSL_WRONG_VERSION_NUMBER',
71
+
'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
72
+
];
73
+
if (retryableCodes.includes(errorCode)) {
74
+
return true;
75
+
}
76
+
}
77
+
78
+
// Timeout errors
79
+
if (err.name === 'AbortError' || err.message.includes('timeout')) {
80
+
return true;
81
+
}
82
+
83
+
// Fetch failures (generic network errors)
84
+
if (err.message.includes('fetch failed')) {
85
+
return true;
86
+
}
87
+
88
+
return false;
89
+
}
90
+
91
+
/**
92
+
* Sleep for a given number of milliseconds
93
+
*/
94
+
function sleep(ms: number): Promise<void> {
95
+
return new Promise(resolve => setTimeout(resolve, ms));
96
+
}
97
+
98
+
/**
99
+
* Retry a function with exponential backoff
100
+
*/
101
+
async function withRetry<T>(
102
+
fn: () => Promise<T>,
103
+
options: { maxRetries?: number; initialDelay?: number; maxDelay?: number; context?: string } = {}
104
+
): Promise<T> {
105
+
const maxRetries = options.maxRetries ?? MAX_RETRIES;
106
+
const initialDelay = options.initialDelay ?? INITIAL_RETRY_DELAY;
107
+
const maxDelay = options.maxDelay ?? MAX_RETRY_DELAY;
108
+
const context = options.context ?? 'Request';
109
+
110
+
let lastError: unknown;
111
+
112
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
113
+
try {
114
+
return await fn();
115
+
} catch (err) {
116
+
lastError = err;
117
+
118
+
// Don't retry if this is the last attempt or error is not retryable
119
+
if (attempt === maxRetries || !isRetryableError(err)) {
120
+
throw err;
121
+
}
122
+
123
+
// Calculate delay with exponential backoff
124
+
const delay = Math.min(initialDelay * Math.pow(2, attempt), maxDelay);
125
+
126
+
const errorCode = (err as any)?.code;
127
+
const errorMsg = err instanceof Error ? err.message : String(err);
128
+
console.warn(
129
+
`${context} failed (attempt ${attempt + 1}/${maxRetries + 1}): ${errorMsg}${errorCode ? ` [${errorCode}]` : ''} - retrying in ${delay}ms`
130
+
);
131
+
132
+
await sleep(delay);
133
+
}
134
+
}
135
+
136
+
throw lastError;
137
+
}
138
+
47
139
export async function safeFetch(
48
140
url: string,
49
-
options?: RequestInit & { maxSize?: number; timeout?: number }
141
+
options?: RequestInit & { maxSize?: number; timeout?: number; retry?: boolean }
50
142
): Promise<Response> {
143
+
const shouldRetry = options?.retry !== false; // Default to true
51
144
const timeoutMs = options?.timeout ?? FETCH_TIMEOUT;
52
145
const maxSize = options?.maxSize ?? MAX_RESPONSE_SIZE;
53
146
54
-
// Parse and validate URL
147
+
// Parse and validate URL (done once, outside retry loop)
55
148
let parsedUrl: URL;
56
149
try {
57
150
parsedUrl = new URL(url);
···
68
161
throw new Error(`Blocked host: ${hostname}`);
69
162
}
70
163
71
-
const controller = new AbortController();
72
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
164
+
const fetchFn = async () => {
165
+
const controller = new AbortController();
166
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
167
+
168
+
try {
169
+
const response = await fetch(url, {
170
+
...options,
171
+
signal: controller.signal,
172
+
redirect: 'follow',
173
+
headers: {
174
+
'User-Agent': 'wisp-place hosting-service',
175
+
...(options?.headers || {}),
176
+
},
177
+
});
73
178
74
-
try {
75
-
const response = await fetch(url, {
76
-
...options,
77
-
signal: controller.signal,
78
-
redirect: 'follow',
79
-
headers: {
80
-
'User-Agent': 'wisp-place hosting-service',
81
-
...(options?.headers || {}),
82
-
},
83
-
});
179
+
const contentLength = response.headers.get('content-length');
180
+
if (contentLength && parseInt(contentLength, 10) > maxSize) {
181
+
throw new Error(`Response too large: ${contentLength} bytes`);
182
+
}
84
183
85
-
const contentLength = response.headers.get('content-length');
86
-
if (contentLength && parseInt(contentLength, 10) > maxSize) {
87
-
throw new Error(`Response too large: ${contentLength} bytes`);
184
+
return response;
185
+
} catch (err) {
186
+
if (err instanceof Error && err.name === 'AbortError') {
187
+
throw new Error(`Request timeout after ${timeoutMs}ms`);
188
+
}
189
+
throw err;
190
+
} finally {
191
+
clearTimeout(timeoutId);
88
192
}
193
+
};
89
194
90
-
return response;
91
-
} catch (err) {
92
-
if (err instanceof Error && err.name === 'AbortError') {
93
-
throw new Error(`Request timeout after ${timeoutMs}ms`);
94
-
}
95
-
throw err;
96
-
} finally {
97
-
clearTimeout(timeoutId);
195
+
if (shouldRetry) {
196
+
return withRetry(fetchFn, { context: `Fetch ${parsedUrl.hostname}` });
197
+
} else {
198
+
return fetchFn();
98
199
}
99
200
}
100
201
101
202
export async function safeFetchJson<T = any>(
102
203
url: string,
103
-
options?: RequestInit & { maxSize?: number; timeout?: number }
204
+
options?: RequestInit & { maxSize?: number; timeout?: number; retry?: boolean }
104
205
): Promise<T> {
105
206
const maxJsonSize = options?.maxSize ?? MAX_JSON_SIZE;
106
207
const response = await safeFetch(url, { ...options, maxSize: maxJsonSize });
···
146
247
147
248
export async function safeFetchBlob(
148
249
url: string,
149
-
options?: RequestInit & { maxSize?: number; timeout?: number }
250
+
options?: RequestInit & { maxSize?: number; timeout?: number; retry?: boolean }
150
251
): Promise<Uint8Array> {
151
252
const maxBlobSize = options?.maxSize ?? MAX_BLOB_SIZE;
152
253
const timeoutMs = options?.timeout ?? FETCH_TIMEOUT_BLOB;
+28
scripts/codegen.sh
+28
scripts/codegen.sh
···
1
+
#!/bin/bash
2
+
set -e
3
+
4
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
6
+
7
+
# Parse arguments
8
+
AUTO_ACCEPT=""
9
+
if [[ "$1" == "-y" || "$1" == "--yes" ]]; then
10
+
AUTO_ACCEPT="yes |"
11
+
fi
12
+
13
+
echo "=== Generating TypeScript lexicons ==="
14
+
cd "$ROOT_DIR/packages/@wisp/lexicons"
15
+
eval "$AUTO_ACCEPT npm run codegen"
16
+
17
+
echo "=== Generating Rust lexicons ==="
18
+
echo "Installing jacquard-lexgen..."
19
+
cargo install jacquard-lexgen --version 0.9.5 2>/dev/null || true
20
+
echo "Running jacquard-codegen..."
21
+
echo " Input: $ROOT_DIR/lexicons"
22
+
echo " Output: $ROOT_DIR/cli/crates/lexicons/src"
23
+
jacquard-codegen -i "$ROOT_DIR/lexicons" -o "$ROOT_DIR/cli/crates/lexicons/src"
24
+
25
+
# Add extern crate alloc for the macro to work
26
+
sed -i '' '1s/^/extern crate alloc;\n\n/' "$ROOT_DIR/cli/crates/lexicons/src/lib.rs"
27
+
28
+
echo "=== Done ==="
+1
-1
tsconfig.json
+1
-1
tsconfig.json
···
33
33
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
34
34
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
35
35
"types": [
36
-
"bun-types"
36
+
"bun"
37
37
] /* Specify type package names to be included without being referenced in a source file. */,
38
38
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
39
39
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */