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

dockerfile work

nekomimi.pet 75f9efeb ec6efeba

verified
Changed files
+104 -67
apps
hosting-service
main-app
public
editor
tabs
src
routes
binaries
docs
src
content
docs
packages
@wisp
fs-utils
+9 -11
Dockerfile
···
# Set working directory
WORKDIR /app
-
# Copy package files
-
COPY package.json ./
+
# Copy workspace configuration
+
COPY package.json bunfig.toml tsconfig.json ./
-
# Copy Bun configuration
-
COPY bunfig.toml ./
+
# Copy workspace packages
+
COPY packages ./packages
-
COPY tsconfig.json ./
+
# Copy both apps (needed for workspace resolution)
+
COPY apps/main-app ./apps/main-app
+
COPY apps/hosting-service/package.json ./apps/hosting-service/package.json
-
# Install dependencies
+
# Install all dependencies (including workspaces)
RUN bun install
-
# Copy source code
-
COPY src ./src
-
COPY public ./public
-
ENV PORT=8000
ENV NODE_ENV=production
EXPOSE 8000
-
CMD ["bun", "start"]
+
CMD ["bun", "run", "start"]
+20 -9
apps/hosting-service/Dockerfile
···
-
# Use official Node.js Alpine image
+
# Use official Node.js Alpine image with pnpm
+
# Build from monorepo root: docker build -f apps/hosting-service/Dockerfile .
FROM node:alpine AS base
+
# Install pnpm globally (supports workspace: protocol)
+
RUN npm install -g pnpm
+
# Set working directory
WORKDIR /app
-
# Copy package files
-
COPY package.json ./
+
# Copy workspace configuration
+
COPY package.json tsconfig.json ./
+
+
# Copy all workspace packages
+
COPY packages ./packages
+
+
# Copy hosting-service and main-app package.json (for workspace resolution)
+
COPY apps/hosting-service ./apps/hosting-service
+
COPY apps/main-app/package.json ./apps/main-app/package.json
-
# Install dependencies
-
RUN npm install
+
# Install all dependencies (including workspaces)
+
RUN pnpm install --frozen-lockfile || pnpm install
-
# Copy source code
-
COPY src ./src
+
# Set working directory to hosting-service
+
WORKDIR /app/apps/hosting-service
# Create cache directory
RUN mkdir -p ./cache/sites
···
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "fetch('http://localhost:3001/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
-
# Start the application (can override with 'npm run backfill' in compose)
-
CMD ["npm", "run", "start"]
+
# Start the application (can override with 'pnpm run backfill' in compose)
+
CMD ["pnpm", "run", "start"]
+4 -3
apps/hosting-service/src/lib/firehose.ts
···
} from './utils'
import { upsertSite, tryAcquireLock, releaseLock } from './db'
import { safeFetch } from '@wisp/safe-fetch'
-
import { isRecord, validateRecord } from '@wisp/lexicons/types/place/wisp/fs'
+
// import { isRecord, validateRecord } from '@wisp/lexicons/types/place/wisp/fs'
+
import { isRecord } from '@wisp/lexicons/types/place/wisp/fs'
import { Firehose } from '@atproto/sync'
import { IdResolver } from '@atproto/identity'
import { invalidateSiteCache, markSiteAsBeingCached, unmarkSiteAsBeingCached } from './cache'
···
// If the write is a valid place.wisp.fs record
if (
evt.collection === 'place.wisp.fs' &&
-
isRecord(record) &&
-
validateRecord(record).success
+
isRecord(record)
+
// && validateRecord(record).success
) {
this.log('Received place.wisp.fs event', {
did: evt.did,
+4 -2
apps/main-app/package.json
···
"@wisp/database": "workspace:*",
"@wisp/fs-utils": "workspace:*",
"@atproto/api": "^0.17.3",
+
"@atproto/common-web": "^0.4.5",
+
"@atproto/jwk-jose": "^0.1.11",
"@atproto/lex-cli": "^0.9.5",
"@atproto/oauth-client-node": "^0.3.9",
"@atproto/xrpc-server": "^0.9.5",
···
"tailwindcss": "4",
"tw-animate-css": "^1.4.0",
"typescript": "^5.9.3",
-
"zlib": "^1.0.5"
+
"zlib": "^1.0.5",
+
"bun-plugin-tailwind": "^0.1.2"
},
"devDependencies": {
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.1",
-
"bun-plugin-tailwind": "^0.1.2",
"bun-types": "latest",
"esbuild": "0.26.0",
"playwright": "^1.49.0"
+12 -2
apps/main-app/public/editor/tabs/CLITab.tsx
···
<div className="flex items-center gap-2 mb-2">
<CardTitle>Wisp CLI Tool</CardTitle>
<Badge variant="secondary" className="text-xs">
-
v0.2.0
+
v0.4.0
</Badge>
<Badge variant="outline" className="text-xs">
Alpha
···
</div>
<div className="space-y-3">
-
<h3 className="text-sm font-semibold">Download v0.2.0</h3>
+
<h3 className="text-sm font-semibold">Download v0.4.0</h3>
<div className="grid gap-2">
<div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border">
<a
···
wisp-cli serve your-handle.bsky.social \\
--site my-site \\
--port 3000
+
+
# Enable SPA mode (serve index.html for all routes)
+
wisp-cli serve your-handle.bsky.social \\
+
--site my-site \\
+
--spa
+
+
# Enable directory listing for paths without index files
+
wisp-cli serve your-handle.bsky.social \\
+
--site my-site \\
+
--directory
# Downloads site, serves it, and watches firehose for live updates!`}
language="bash"
+19 -18
apps/main-app/src/routes/wisp.ts
···
import { createManifest } from '@wisp/fs-utils'
import { upsertSite } from '../lib/db'
import { createLogger } from '@wisp/observability'
-
import { validateRecord, type Directory } from '@wisp/lexicons/types/place/wisp/fs'
-
import { validateRecord as validateSubfsRecord } from '@wisp/lexicons/types/place/wisp/subfs'
+
// import { validateRecord, type Directory } from '@wisp/lexicons/types/place/wisp/fs'
+
import { type Directory } from '@wisp/lexicons/types/place/wisp/fs'
+
// import { validateRecord as validateSubfsRecord } from '@wisp/lexicons/types/place/wisp/subfs'
import { MAX_SITE_SIZE, MAX_FILE_SIZE, MAX_FILE_COUNT } from '@wisp/constants'
import {
createUploadJob,
···
createdAt: new Date().toISOString()
};
-
const validationResult = validateRecord(emptyManifest);
-
if (!validationResult.success) {
-
throw new Error(`Invalid manifest: ${validationResult.error?.message || 'Validation failed'}`);
-
}
+
// const validationResult = validateRecord(emptyManifest);
+
// if (!validationResult.success) {
+
// throw new Error(`Invalid manifest: ${validationResult.error?.message || 'Validation failed'}`);
+
// }
const rkey = siteName;
updateJobProgress(jobId, { phase: 'finalizing' });
···
};
// Validate subfs record
-
const subfsValidation = validateSubfsRecord(subfsManifest);
-
if (!subfsValidation.success) {
-
throw new Error(`Invalid subfs manifest: ${subfsValidation.error?.message || 'Validation failed'}`);
-
}
+
// const subfsValidation = validateSubfsRecord(subfsManifest);
+
// if (!subfsValidation.success) {
+
// throw new Error(`Invalid subfs manifest: ${subfsValidation.error?.message || 'Validation failed'}`);
+
// }
// Upload subfs record to PDS
const subfsRecord = await agent.com.atproto.repo.putRecord({
···
};
// Validate subfs record
-
const subfsValidation = validateSubfsRecord(subfsManifest);
-
if (!subfsValidation.success) {
-
throw new Error(`Invalid subfs manifest: ${subfsValidation.error?.message || 'Validation failed'}`);
-
}
+
// const subfsValidation = validateSubfsRecord(subfsManifest);
+
// if (!subfsValidation.success) {
+
// throw new Error(`Invalid subfs manifest: ${subfsValidation.error?.message || 'Validation failed'}`);
+
// }
// Upload subfs record to PDS
const subfsRecord = await agent.com.atproto.repo.putRecord({
···
createdAt: new Date().toISOString()
};
-
const validationResult = validateRecord(emptyManifest);
-
if (!validationResult.success) {
-
throw new Error(`Invalid manifest: ${validationResult.error?.message || 'Validation failed'}`);
-
}
+
// const validationResult = validateRecord(emptyManifest);
+
// if (!validationResult.success) {
+
// throw new Error(`Invalid manifest: ${validationResult.error?.message || 'Validation failed'}`);
+
// }
const rkey = siteName;
+1 -1
binaries/index.html
···
</head>
<body>
<div class="container">
-
<h1>Wisp CLI <span style="font-size: 1.5rem; color: var(--demo-text-secondary);">v0.2.0</span></h1>
+
<h1>Wisp CLI <span style="font-size: 1.5rem; color: var(--demo-text-secondary);">v0.4.0</span></h1>
<p class="subtitle">Deploy static sites to the AT Protocol</p>
<div class="description">
+24 -14
bun.lock
···
"workspaces": {
"": {
"name": "elysia-static",
+
"dependencies": {
+
"bun-plugin-tailwind": "^0.1.2",
+
"tailwindcss": "4",
+
},
},
"apps/hosting-service": {
"name": "wisp-hosting-service",
···
"version": "1.0.50",
"dependencies": {
"@atproto/api": "^0.17.3",
+
"@atproto/common-web": "^0.4.5",
+
"@atproto/jwk-jose": "^0.1.11",
"@atproto/lex-cli": "^0.9.5",
"@atproto/oauth-client-node": "^0.3.9",
"@atproto/xrpc-server": "^0.9.5",
···
"@wisp/observability": "workspace:*",
"actor-typeahead": "^0.1.1",
"atproto-ui": "^0.11.3",
+
"bun-plugin-tailwind": "^0.1.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"elysia": "latest",
···
"devDependencies": {
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.1",
-
"bun-plugin-tailwind": "^0.1.2",
"bun-types": "latest",
"esbuild": "0.26.0",
"playwright": "^1.49.0",
···
"@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=="],
-
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
+
"@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
"@atproto/crypto": ["@atproto/crypto@0.4.4", "", { "dependencies": { "@noble/curves": "^1.7.0", "@noble/hashes": "^1.6.1", "uint8arrays": "3.0.0" } }, "sha512-Yq9+crJ7WQl7sxStVpHgie5Z51R05etaK9DLWYG/7bR5T4bhdcIgF6IfklLShtZwLYdVVj+K15s0BqW9a8PSDA=="],
···
"@atproto-labs/fetch-node/ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="],
+
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
+
"@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=="],
"@atproto/api/@atproto/xrpc": ["@atproto/xrpc@0.6.12", "", { "dependencies": { "@atproto/lexicon": "^0.4.10", "zod": "^3.23.8" } }, "sha512-Ut3iISNLujlmY9Gu8sNU+SPDJDvqlVzWddU8qUr0Yae5oD4SguaUFjjhireMGhQ3M5E0KljQgDbTmnBo1kIZ3w=="],
"@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
-
"@atproto/common/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
-
-
"@atproto/common-web/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
-
"@atproto/identity/@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
+
"@atproto/common/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
"@atproto/jwk/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
···
"@atproto/lex-data/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
-
"@atproto/lexicon/@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
-
"@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
"@atproto/oauth-client/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
"@atproto/repo/@atproto/common": ["@atproto/common@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.5", "@atproto/lex-cbor": "0.0.1", "@atproto/lex-data": "0.0.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-0S57sjzw4r9OLc5srJFi6uAz/aTKYl6btz3x36tSnGriL716m6h0x2IVtgd+FhUfIQfisevrqcqw8SfaGk8VTw=="],
-
-
"@atproto/repo/@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
"@atproto/repo/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
···
"wisp-hosting-service/@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" } }, "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A=="],
-
"@atproto/lex-cli/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
-
"@atproto/sync/@atproto/common/@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
+
"@atproto/lex-cli/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
"@atproto/sync/@atproto/xrpc-server/@atproto/xrpc": ["@atproto/xrpc@0.7.6", "", { "dependencies": { "@atproto/lexicon": "^0.5.2", "zod": "^3.23.8" } }, "sha512-RvCf4j0JnKYWuz3QzsYCntJi3VuiAAybQsMIUw2wLWcHhchO9F7UaBZINLL2z0qc/cYWPv5NSwcVydMseoCZLA=="],
-
"@atproto/ws-client/@atproto/common/@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
-
"@atproto/ws-client/@atproto/common/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
+
"@atproto/xrpc-server/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+
+
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
"@atproto/xrpc/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
"@tokenizer/inflate/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
"@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" } }, "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A=="],
···
"tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
+
"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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
+
"wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+
+
"wisp-hosting-service/@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" } }, "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg=="],
"wisp-hosting-service/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+2 -2
docs/src/content/docs/cli.md
···
---
-
title: Wisp CLI 0.2.0 (alpha)
+
title: Wisp CLI 0.4.0 (alpha)
description: Command-line tool for deploying static sites to the AT Protocol
---
···
<div class="downloads">
-
<h2>Download v0.3.0</h2>
+
<h2>Download v0.4.0</h2>
<a href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwin" class="download-link" download="">
+4
package.json
···
"apps/main-app",
"apps/hosting-service"
],
+
"dependencies": {
+
"bun-plugin-tailwind": "^0.1.2",
+
"tailwindcss": "4"
+
},
"scripts": {
"test": "bun test",
"dev": "bun run --watch apps/main-app/src/index.ts",
+5 -5
packages/@wisp/fs-utils/src/manifest.ts
···
import type { Record, Directory } from "@wisp/lexicons/types/place/wisp/fs";
-
import { validateRecord } from "@wisp/lexicons/types/place/wisp/fs";
+
// import { validateRecord } from "@wisp/lexicons/types/place/wisp/fs";
/**
* Create the manifest record for a site
···
};
// Validate the manifest before returning
-
const validationResult = validateRecord(manifest);
-
if (!validationResult.success) {
-
throw new Error(`Invalid manifest: ${validationResult.error?.message || 'Validation failed'}`);
-
}
+
// const validationResult = validateRecord(manifest);
+
// if (!validationResult.success) {
+
// throw new Error(`Invalid manifest: ${validationResult.error?.message || 'Validation failed'}`);
+
// }
return manifest;
}