thevoidforge 21.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/vault-read.d.ts +11 -0
- package/dist/scripts/vault-read.js +89 -0
- package/dist/scripts/voidforge.d.ts +20 -0
- package/dist/scripts/voidforge.js +404 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/wizard/api/auth.d.ts +5 -0
- package/dist/wizard/api/auth.js +133 -0
- package/dist/wizard/api/blueprint.d.ts +45 -0
- package/dist/wizard/api/blueprint.js +184 -0
- package/dist/wizard/api/cloud-providers.d.ts +16 -0
- package/dist/wizard/api/cloud-providers.js +363 -0
- package/dist/wizard/api/credentials.d.ts +1 -0
- package/dist/wizard/api/credentials.js +258 -0
- package/dist/wizard/api/danger-room.d.ts +18 -0
- package/dist/wizard/api/danger-room.js +401 -0
- package/dist/wizard/api/deploy.d.ts +4 -0
- package/dist/wizard/api/deploy.js +164 -0
- package/dist/wizard/api/prd.d.ts +1 -0
- package/dist/wizard/api/prd.js +363 -0
- package/dist/wizard/api/project.d.ts +1 -0
- package/dist/wizard/api/project.js +239 -0
- package/dist/wizard/api/projects.d.ts +6 -0
- package/dist/wizard/api/projects.js +648 -0
- package/dist/wizard/api/provision.d.ts +4 -0
- package/dist/wizard/api/provision.js +535 -0
- package/dist/wizard/api/terminal.d.ts +25 -0
- package/dist/wizard/api/terminal.js +241 -0
- package/dist/wizard/api/users.d.ts +6 -0
- package/dist/wizard/api/users.js +244 -0
- package/dist/wizard/api/war-room.d.ts +14 -0
- package/dist/wizard/api/war-room.js +45 -0
- package/dist/wizard/lib/ad-platform-core.d.ts +6 -0
- package/dist/wizard/lib/ad-platform-core.js +1 -0
- package/dist/wizard/lib/adapters/index.d.ts +52 -0
- package/dist/wizard/lib/adapters/index.js +38 -0
- package/dist/wizard/lib/adapters/sandbox-bank.d.ts +17 -0
- package/dist/wizard/lib/adapters/sandbox-bank.js +77 -0
- package/dist/wizard/lib/adapters/sandbox.d.ts +39 -0
- package/dist/wizard/lib/adapters/sandbox.js +174 -0
- package/dist/wizard/lib/adapters/stripe.d.ts +19 -0
- package/dist/wizard/lib/adapters/stripe.js +143 -0
- package/dist/wizard/lib/adapters/types.d.ts +9 -0
- package/dist/wizard/lib/adapters/types.js +10 -0
- package/dist/wizard/lib/agent-memory.d.ts +36 -0
- package/dist/wizard/lib/agent-memory.js +114 -0
- package/dist/wizard/lib/anomaly-detection.d.ts +59 -0
- package/dist/wizard/lib/anomaly-detection.js +122 -0
- package/dist/wizard/lib/anthropic.d.ts +21 -0
- package/dist/wizard/lib/anthropic.js +105 -0
- package/dist/wizard/lib/asset-scanner.d.ts +23 -0
- package/dist/wizard/lib/asset-scanner.js +107 -0
- package/dist/wizard/lib/audit-log.d.ts +23 -0
- package/dist/wizard/lib/audit-log.js +70 -0
- package/dist/wizard/lib/autonomy-controller.d.ts +76 -0
- package/dist/wizard/lib/autonomy-controller.js +183 -0
- package/dist/wizard/lib/body-parser.d.ts +2 -0
- package/dist/wizard/lib/body-parser.js +36 -0
- package/dist/wizard/lib/build-analytics.d.ts +39 -0
- package/dist/wizard/lib/build-analytics.js +91 -0
- package/dist/wizard/lib/build-step.d.ts +21 -0
- package/dist/wizard/lib/build-step.js +104 -0
- package/dist/wizard/lib/campaign-proposer.d.ts +39 -0
- package/dist/wizard/lib/campaign-proposer.js +180 -0
- package/dist/wizard/lib/campaign-state-machine.d.ts +63 -0
- package/dist/wizard/lib/campaign-state-machine.js +114 -0
- package/dist/wizard/lib/ci-generator.d.ts +14 -0
- package/dist/wizard/lib/ci-generator.js +187 -0
- package/dist/wizard/lib/claude-merge.d.ts +38 -0
- package/dist/wizard/lib/claude-merge.js +115 -0
- package/dist/wizard/lib/codegen/erd-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/erd-gen.js +98 -0
- package/dist/wizard/lib/codegen/integrations.d.ts +18 -0
- package/dist/wizard/lib/codegen/integrations.js +189 -0
- package/dist/wizard/lib/codegen/openapi-gen.d.ts +15 -0
- package/dist/wizard/lib/codegen/openapi-gen.js +79 -0
- package/dist/wizard/lib/codegen/prisma-types.d.ts +15 -0
- package/dist/wizard/lib/codegen/prisma-types.js +44 -0
- package/dist/wizard/lib/codegen/seed-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/seed-gen.js +128 -0
- package/dist/wizard/lib/compliance.d.ts +51 -0
- package/dist/wizard/lib/compliance.js +112 -0
- package/dist/wizard/lib/correlation-engine.d.ts +59 -0
- package/dist/wizard/lib/correlation-engine.js +151 -0
- package/dist/wizard/lib/cost-estimator.d.ts +22 -0
- package/dist/wizard/lib/cost-estimator.js +72 -0
- package/dist/wizard/lib/cost-tracker.d.ts +27 -0
- package/dist/wizard/lib/cost-tracker.js +37 -0
- package/dist/wizard/lib/daemon-aggregator.d.ts +71 -0
- package/dist/wizard/lib/daemon-aggregator.js +204 -0
- package/dist/wizard/lib/daemon-core.d.ts +6 -0
- package/dist/wizard/lib/daemon-core.js +5 -0
- package/dist/wizard/lib/dashboard-data.d.ts +132 -0
- package/dist/wizard/lib/dashboard-data.js +336 -0
- package/dist/wizard/lib/dashboard-ws.d.ts +25 -0
- package/dist/wizard/lib/dashboard-ws.js +91 -0
- package/dist/wizard/lib/deep-current.d.ts +77 -0
- package/dist/wizard/lib/deep-current.js +234 -0
- package/dist/wizard/lib/deploy-coordinator.d.ts +40 -0
- package/dist/wizard/lib/deploy-coordinator.js +86 -0
- package/dist/wizard/lib/deploy-log.d.ts +28 -0
- package/dist/wizard/lib/deploy-log.js +52 -0
- package/dist/wizard/lib/desktop-notify.d.ts +27 -0
- package/dist/wizard/lib/desktop-notify.js +98 -0
- package/dist/wizard/lib/dns/cloudflare-dns.d.ts +35 -0
- package/dist/wizard/lib/dns/cloudflare-dns.js +216 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.d.ts +31 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.js +148 -0
- package/dist/wizard/lib/dns/types.d.ts +22 -0
- package/dist/wizard/lib/dns/types.js +4 -0
- package/dist/wizard/lib/document-discovery.d.ts +33 -0
- package/dist/wizard/lib/document-discovery.js +145 -0
- package/dist/wizard/lib/env-validator.d.ts +14 -0
- package/dist/wizard/lib/env-validator.js +205 -0
- package/dist/wizard/lib/env-writer.d.ts +13 -0
- package/dist/wizard/lib/env-writer.js +26 -0
- package/dist/wizard/lib/exec.d.ts +30 -0
- package/dist/wizard/lib/exec.js +52 -0
- package/dist/wizard/lib/experiment.d.ts +70 -0
- package/dist/wizard/lib/experiment.js +169 -0
- package/dist/wizard/lib/extensions.d.ts +20 -0
- package/dist/wizard/lib/extensions.js +183 -0
- package/dist/wizard/lib/financial/adapter-factory.d.ts +47 -0
- package/dist/wizard/lib/financial/adapter-factory.js +225 -0
- package/dist/wizard/lib/financial/billing/base.d.ts +6 -0
- package/dist/wizard/lib/financial/billing/base.js +1 -0
- package/dist/wizard/lib/financial/billing/google-billing.d.ts +56 -0
- package/dist/wizard/lib/financial/billing/google-billing.js +298 -0
- package/dist/wizard/lib/financial/billing/meta-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/meta-billing.js +243 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.js +260 -0
- package/dist/wizard/lib/financial/campaign/base.d.ts +13 -0
- package/dist/wizard/lib/financial/campaign/base.js +1 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.d.ts +42 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.js +388 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +41 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.js +311 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.d.ts +45 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.js +261 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.d.ts +40 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +350 -0
- package/dist/wizard/lib/financial/funding-auto.d.ts +44 -0
- package/dist/wizard/lib/financial/funding-auto.js +52 -0
- package/dist/wizard/lib/financial/funding-policy.d.ts +60 -0
- package/dist/wizard/lib/financial/funding-policy.js +179 -0
- package/dist/wizard/lib/financial/platform-planner.d.ts +47 -0
- package/dist/wizard/lib/financial/platform-planner.js +134 -0
- package/dist/wizard/lib/financial/reconciliation-engine.d.ts +78 -0
- package/dist/wizard/lib/financial/reconciliation-engine.js +193 -0
- package/dist/wizard/lib/financial/registry.d.ts +22 -0
- package/dist/wizard/lib/financial/registry.js +26 -0
- package/dist/wizard/lib/financial/reporting.d.ts +96 -0
- package/dist/wizard/lib/financial/reporting.js +198 -0
- package/dist/wizard/lib/financial/stablecoin/base.d.ts +6 -0
- package/dist/wizard/lib/financial/stablecoin/base.js +1 -0
- package/dist/wizard/lib/financial/stablecoin/circle.d.ts +54 -0
- package/dist/wizard/lib/financial/stablecoin/circle.js +367 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.d.ts +24 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.js +171 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.d.ts +47 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.js +202 -0
- package/dist/wizard/lib/financial/treasury-planner.d.ts +52 -0
- package/dist/wizard/lib/financial/treasury-planner.js +128 -0
- package/dist/wizard/lib/financial-core.d.ts +6 -0
- package/dist/wizard/lib/financial-core.js +5 -0
- package/dist/wizard/lib/financial-vault.d.ts +34 -0
- package/dist/wizard/lib/financial-vault.js +199 -0
- package/dist/wizard/lib/frontmatter.d.ts +30 -0
- package/dist/wizard/lib/frontmatter.js +96 -0
- package/dist/wizard/lib/gap-analysis.d.ts +37 -0
- package/dist/wizard/lib/gap-analysis.js +218 -0
- package/dist/wizard/lib/github.d.ts +22 -0
- package/dist/wizard/lib/github.js +261 -0
- package/dist/wizard/lib/headless-deploy.d.ts +14 -0
- package/dist/wizard/lib/headless-deploy.js +452 -0
- package/dist/wizard/lib/health-monitor.d.ts +15 -0
- package/dist/wizard/lib/health-monitor.js +91 -0
- package/dist/wizard/lib/health-poller.d.ts +9 -0
- package/dist/wizard/lib/health-poller.js +123 -0
- package/dist/wizard/lib/heartbeat.d.ts +15 -0
- package/dist/wizard/lib/heartbeat.js +827 -0
- package/dist/wizard/lib/http-helpers.d.ts +9 -0
- package/dist/wizard/lib/http-helpers.js +24 -0
- package/dist/wizard/lib/image-gen.d.ts +56 -0
- package/dist/wizard/lib/image-gen.js +159 -0
- package/dist/wizard/lib/instance-sizing.d.ts +26 -0
- package/dist/wizard/lib/instance-sizing.js +51 -0
- package/dist/wizard/lib/kongo/analytics.d.ts +29 -0
- package/dist/wizard/lib/kongo/analytics.js +179 -0
- package/dist/wizard/lib/kongo/campaigns.d.ts +52 -0
- package/dist/wizard/lib/kongo/campaigns.js +91 -0
- package/dist/wizard/lib/kongo/client.d.ts +58 -0
- package/dist/wizard/lib/kongo/client.js +221 -0
- package/dist/wizard/lib/kongo/jobs.d.ts +57 -0
- package/dist/wizard/lib/kongo/jobs.js +122 -0
- package/dist/wizard/lib/kongo/pages.d.ts +60 -0
- package/dist/wizard/lib/kongo/pages.js +150 -0
- package/dist/wizard/lib/kongo/provisioner.d.ts +64 -0
- package/dist/wizard/lib/kongo/provisioner.js +116 -0
- package/dist/wizard/lib/kongo/seed.d.ts +49 -0
- package/dist/wizard/lib/kongo/seed.js +237 -0
- package/dist/wizard/lib/kongo/types.d.ts +323 -0
- package/dist/wizard/lib/kongo/types.js +11 -0
- package/dist/wizard/lib/kongo/variants.d.ts +57 -0
- package/dist/wizard/lib/kongo/variants.js +88 -0
- package/dist/wizard/lib/kongo/webhooks.d.ts +41 -0
- package/dist/wizard/lib/kongo/webhooks.js +112 -0
- package/dist/wizard/lib/marker.d.ts +28 -0
- package/dist/wizard/lib/marker.js +79 -0
- package/dist/wizard/lib/migrator.d.ts +35 -0
- package/dist/wizard/lib/migrator.js +190 -0
- package/dist/wizard/lib/natural-language-deploy.d.ts +30 -0
- package/dist/wizard/lib/natural-language-deploy.js +186 -0
- package/dist/wizard/lib/network.d.ts +22 -0
- package/dist/wizard/lib/network.js +72 -0
- package/dist/wizard/lib/oauth-core.d.ts +6 -0
- package/dist/wizard/lib/oauth-core.js +5 -0
- package/dist/wizard/lib/open-browser.d.ts +1 -0
- package/dist/wizard/lib/open-browser.js +26 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.d.ts +209 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.js +269 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.d.ts +200 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.js +212 -0
- package/dist/wizard/lib/patterns/daemon-process.d.ts +88 -0
- package/dist/wizard/lib/patterns/daemon-process.js +271 -0
- package/dist/wizard/lib/patterns/financial-transaction.d.ts +161 -0
- package/dist/wizard/lib/patterns/financial-transaction.js +132 -0
- package/dist/wizard/lib/patterns/funding-plan.d.ts +136 -0
- package/dist/wizard/lib/patterns/funding-plan.js +200 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.d.ts +94 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.js +139 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.d.ts +67 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.js +216 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.d.ts +96 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.js +182 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.d.ts +218 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.js +264 -0
- package/dist/wizard/lib/prd-validator.d.ts +39 -0
- package/dist/wizard/lib/prd-validator.js +137 -0
- package/dist/wizard/lib/project-init.d.ts +24 -0
- package/dist/wizard/lib/project-init.js +193 -0
- package/dist/wizard/lib/project-registry.d.ts +86 -0
- package/dist/wizard/lib/project-registry.js +359 -0
- package/dist/wizard/lib/provision-manifest.d.ts +44 -0
- package/dist/wizard/lib/provision-manifest.js +164 -0
- package/dist/wizard/lib/provisioner-registry.d.ts +15 -0
- package/dist/wizard/lib/provisioner-registry.js +34 -0
- package/dist/wizard/lib/provisioners/aws-vps.d.ts +6 -0
- package/dist/wizard/lib/provisioners/aws-vps.js +643 -0
- package/dist/wizard/lib/provisioners/cloudflare.d.ts +6 -0
- package/dist/wizard/lib/provisioners/cloudflare.js +300 -0
- package/dist/wizard/lib/provisioners/docker.d.ts +6 -0
- package/dist/wizard/lib/provisioners/docker.js +75 -0
- package/dist/wizard/lib/provisioners/http-client.d.ts +20 -0
- package/dist/wizard/lib/provisioners/http-client.js +79 -0
- package/dist/wizard/lib/provisioners/railway.d.ts +6 -0
- package/dist/wizard/lib/provisioners/railway.js +413 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.js +54 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.js +112 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.d.ts +11 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.js +91 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.d.ts +5 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.js +185 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.js +36 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.d.ts +14 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.js +202 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.js +67 -0
- package/dist/wizard/lib/provisioners/self-deploy.d.ts +41 -0
- package/dist/wizard/lib/provisioners/self-deploy.js +185 -0
- package/dist/wizard/lib/provisioners/static-s3.d.ts +6 -0
- package/dist/wizard/lib/provisioners/static-s3.js +235 -0
- package/dist/wizard/lib/provisioners/types.d.ts +40 -0
- package/dist/wizard/lib/provisioners/types.js +4 -0
- package/dist/wizard/lib/provisioners/vercel.d.ts +6 -0
- package/dist/wizard/lib/provisioners/vercel.js +287 -0
- package/dist/wizard/lib/pty-manager.d.ts +42 -0
- package/dist/wizard/lib/pty-manager.js +231 -0
- package/dist/wizard/lib/rate-limiter-core.d.ts +5 -0
- package/dist/wizard/lib/rate-limiter-core.js +5 -0
- package/dist/wizard/lib/reconciliation.d.ts +43 -0
- package/dist/wizard/lib/reconciliation.js +173 -0
- package/dist/wizard/lib/revenue-types.d.ts +5 -0
- package/dist/wizard/lib/revenue-types.js +1 -0
- package/dist/wizard/lib/route-optimizer.d.ts +28 -0
- package/dist/wizard/lib/route-optimizer.js +93 -0
- package/dist/wizard/lib/s3-deploy.d.ts +19 -0
- package/dist/wizard/lib/s3-deploy.js +156 -0
- package/dist/wizard/lib/safety-tiers.d.ts +76 -0
- package/dist/wizard/lib/safety-tiers.js +134 -0
- package/dist/wizard/lib/sentry-generator.d.ts +15 -0
- package/dist/wizard/lib/sentry-generator.js +116 -0
- package/dist/wizard/lib/server-config.d.ts +13 -0
- package/dist/wizard/lib/server-config.js +23 -0
- package/dist/wizard/lib/service-install.d.ts +18 -0
- package/dist/wizard/lib/service-install.js +182 -0
- package/dist/wizard/lib/site-scanner.d.ts +80 -0
- package/dist/wizard/lib/site-scanner.js +262 -0
- package/dist/wizard/lib/ssh-deploy.d.ts +25 -0
- package/dist/wizard/lib/ssh-deploy.js +225 -0
- package/dist/wizard/lib/templates.d.ts +24 -0
- package/dist/wizard/lib/templates.js +219 -0
- package/dist/wizard/lib/totp.d.ts +35 -0
- package/dist/wizard/lib/totp.js +276 -0
- package/dist/wizard/lib/tower-auth.d.ts +43 -0
- package/dist/wizard/lib/tower-auth.js +352 -0
- package/dist/wizard/lib/tower-rate-limit.d.ts +14 -0
- package/dist/wizard/lib/tower-rate-limit.js +61 -0
- package/dist/wizard/lib/tower-session.d.ts +28 -0
- package/dist/wizard/lib/tower-session.js +119 -0
- package/dist/wizard/lib/treasury-backup.d.ts +23 -0
- package/dist/wizard/lib/treasury-backup.js +126 -0
- package/dist/wizard/lib/treasury-heartbeat.d.ts +82 -0
- package/dist/wizard/lib/treasury-heartbeat.js +1104 -0
- package/dist/wizard/lib/updater.d.ts +29 -0
- package/dist/wizard/lib/updater.js +190 -0
- package/dist/wizard/lib/user-manager.d.ts +39 -0
- package/dist/wizard/lib/user-manager.js +182 -0
- package/dist/wizard/lib/vault.d.ts +26 -0
- package/dist/wizard/lib/vault.js +161 -0
- package/dist/wizard/router.d.ts +5 -0
- package/dist/wizard/router.js +15 -0
- package/dist/wizard/server.d.ts +18 -0
- package/dist/wizard/server.js +436 -0
- package/package.json +59 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth API — Login, logout, session check, initial setup.
|
|
3
|
+
* All responses use { success, data?, error? } format.
|
|
4
|
+
*/
|
|
5
|
+
import { addRoute } from '../router.js';
|
|
6
|
+
import { parseJsonBody } from '../lib/body-parser.js';
|
|
7
|
+
import { hasUsers, createUser, login, logout, validateSession, parseSessionCookie, buildSessionCookie, clearSessionCookie, isRemoteMode, checkRateLimit, getClientIp, getUserRole, isValidUsername, } from '../lib/tower-auth.js';
|
|
8
|
+
import { audit } from '../lib/audit-log.js';
|
|
9
|
+
import { sendJson } from '../lib/http-helpers.js';
|
|
10
|
+
// POST /api/auth/setup — Create initial admin user (only when no users exist)
|
|
11
|
+
addRoute('POST', '/api/auth/setup', async (req, res) => {
|
|
12
|
+
if (!isRemoteMode()) {
|
|
13
|
+
sendJson(res, 400, { success: false, error: 'Auth setup is only available in remote mode' });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// Rate-limit the setup endpoint (prevents race-to-setup attacks)
|
|
17
|
+
const ip = getClientIp(req);
|
|
18
|
+
const rateCheck = checkRateLimit(ip);
|
|
19
|
+
if (!rateCheck.allowed) {
|
|
20
|
+
sendJson(res, 429, { success: false, error: 'Too many attempts. Try again later.' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Validate body BEFORE the hasUsers check — body parsing is not security-sensitive
|
|
24
|
+
const body = await parseJsonBody(req);
|
|
25
|
+
if (typeof body !== 'object' || body === null) {
|
|
26
|
+
sendJson(res, 400, { success: false, error: 'Request body must be a JSON object' });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const { username, password } = body;
|
|
30
|
+
if (typeof username !== 'string' || !isValidUsername(username.trim())) {
|
|
31
|
+
sendJson(res, 400, { success: false, error: 'Username must be 3-64 characters (letters, numbers, . _ -)' });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (typeof password !== 'string' || password.length < 12 || password.length > 256) {
|
|
35
|
+
sendJson(res, 400, { success: false, error: 'Password must be 12-256 characters' });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
// v17.0: Removed outer hasUsers() check — it was a TOCTOU race.
|
|
40
|
+
// createUser() has its own serialized hasUsers check that is atomic with creation.
|
|
41
|
+
// Two concurrent requests will serialize: the first creates, the second gets "already taken".
|
|
42
|
+
const { totpSecret, totpUri } = await createUser(username.trim(), password);
|
|
43
|
+
await audit('user_create', ip, username.trim(), { action: 'initial_setup' });
|
|
44
|
+
sendJson(res, 201, {
|
|
45
|
+
success: true,
|
|
46
|
+
data: { totpSecret, totpUri, message: 'Scan the QR code with your authenticator app.' },
|
|
47
|
+
}, true); // no-cache — TOTP secret must not be cached
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const message = err instanceof Error ? err.message : 'Setup failed';
|
|
51
|
+
if (message.includes('already taken')) {
|
|
52
|
+
sendJson(res, 409, { success: false, error: 'Admin user already exists' });
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
sendJson(res, 500, { success: false, error: 'Failed to create user' });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// POST /api/auth/login — Authenticate with username + password + TOTP
|
|
60
|
+
addRoute('POST', '/api/auth/login', async (req, res) => {
|
|
61
|
+
if (!isRemoteMode()) {
|
|
62
|
+
sendJson(res, 400, { success: false, error: 'Auth is only required in remote mode' });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const body = await parseJsonBody(req);
|
|
66
|
+
if (typeof body !== 'object' || body === null) {
|
|
67
|
+
sendJson(res, 400, { success: false, error: 'Request body must be a JSON object' });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const { username, password, totpCode } = body;
|
|
71
|
+
if (typeof username !== 'string' || typeof password !== 'string' || typeof totpCode !== 'string') {
|
|
72
|
+
sendJson(res, 400, { success: false, error: 'username, password, and totpCode are required strings' });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Cap field lengths to prevent DoS via oversized PBKDF2 input
|
|
76
|
+
// QA-R3-018 + CROSS-R4-010: TOTP must be exactly 6 digits per RFC 6238
|
|
77
|
+
if (username.length > 64 || password.length > 256 || totpCode.length !== 6 || !/^\d{6}$/.test(totpCode)) {
|
|
78
|
+
sendJson(res, 400, { success: false, error: 'Field length exceeded' });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const ip = getClientIp(req);
|
|
82
|
+
await audit('login_attempt', ip, username.slice(0, 64), { method: 'password+totp' });
|
|
83
|
+
const result = await login(username, password, totpCode, ip);
|
|
84
|
+
if ('error' in result) {
|
|
85
|
+
await audit('login_failure', ip, username.slice(0, 64), { reason: result.error });
|
|
86
|
+
const status = result.retryAfterMs ? 429 : 401;
|
|
87
|
+
sendJson(res, status, { success: false, error: result.error }, true);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const role = await getUserRole(username.slice(0, 64));
|
|
91
|
+
await audit('login_success', ip, username.slice(0, 64), { role: role ?? 'unknown' });
|
|
92
|
+
// Set Secure flag only when actually serving over HTTPS (proxy or direct TLS).
|
|
93
|
+
// Do NOT force Secure in remote mode — user may access via ZeroTier/Tailscale
|
|
94
|
+
// over plain HTTP without a reverse proxy. Browsers silently drop Secure cookies
|
|
95
|
+
// on HTTP, causing session loss after login. (Field report: April 2026)
|
|
96
|
+
const secure = req.headers['x-forwarded-proto'] === 'https'
|
|
97
|
+
|| req.socket.encrypted === true;
|
|
98
|
+
res.setHeader('Set-Cookie', buildSessionCookie(result.token, secure));
|
|
99
|
+
sendJson(res, 200, { success: true, data: { username: username.slice(0, 64), role } }, true);
|
|
100
|
+
});
|
|
101
|
+
// POST /api/auth/logout — Invalidate session
|
|
102
|
+
addRoute('POST', '/api/auth/logout', async (req, res) => {
|
|
103
|
+
const token = parseSessionCookie(req.headers.cookie);
|
|
104
|
+
const ip = getClientIp(req);
|
|
105
|
+
if (token) {
|
|
106
|
+
const session = validateSession(token, ip);
|
|
107
|
+
logout(token);
|
|
108
|
+
if (session) {
|
|
109
|
+
await audit('logout', ip, session.username, {});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
res.setHeader('Set-Cookie', clearSessionCookie());
|
|
113
|
+
sendJson(res, 200, { success: true });
|
|
114
|
+
});
|
|
115
|
+
// GET /api/auth/session — Check if current session is valid
|
|
116
|
+
addRoute('GET', '/api/auth/session', async (req, res) => {
|
|
117
|
+
if (!isRemoteMode()) {
|
|
118
|
+
sendJson(res, 200, { success: true, data: { authenticated: true, username: 'local', role: 'admin', remoteMode: false } });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const token = parseSessionCookie(req.headers.cookie);
|
|
122
|
+
const ip = getClientIp(req);
|
|
123
|
+
if (!token) {
|
|
124
|
+
sendJson(res, 200, { success: true, data: { authenticated: false, needsSetup: !(await hasUsers()) } });
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const session = validateSession(token, ip);
|
|
128
|
+
if (!session) {
|
|
129
|
+
sendJson(res, 200, { success: true, data: { authenticated: false, needsSetup: false } });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
sendJson(res, 200, { success: true, data: { authenticated: true, username: session.username, role: session.role, remoteMode: true } });
|
|
133
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blueprint API — validates pre-written PRDs for the Blueprint Path.
|
|
3
|
+
*
|
|
4
|
+
* Provides the API endpoint for the wizard UI's blueprint auto-detection
|
|
5
|
+
* and for programmatic PRD validation.
|
|
6
|
+
*
|
|
7
|
+
* PRD Reference: RFC-blueprint-path.md
|
|
8
|
+
*/
|
|
9
|
+
export interface BlueprintValidationResult {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
prdFound: boolean;
|
|
12
|
+
frontmatter: Record<string, string | undefined>;
|
|
13
|
+
frontmatterErrors: string[];
|
|
14
|
+
structuralWarnings: string[];
|
|
15
|
+
conflicts: string[];
|
|
16
|
+
documents: {
|
|
17
|
+
prd: string | null;
|
|
18
|
+
projectDirectives: string | null;
|
|
19
|
+
operations: string | null;
|
|
20
|
+
adrs: string[];
|
|
21
|
+
references: string[];
|
|
22
|
+
total: number;
|
|
23
|
+
};
|
|
24
|
+
summary: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate a project directory for the Blueprint Path.
|
|
28
|
+
* Returns comprehensive validation results without modifying any files.
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateBlueprint(projectRoot: string): Promise<BlueprintValidationResult>;
|
|
31
|
+
export declare function executeBlueprintMerge(projectRoot: string, directivesPath: string | null): Promise<{
|
|
32
|
+
merged: boolean;
|
|
33
|
+
reason: string;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Handle blueprint API requests. Mount at /api/blueprint/*
|
|
37
|
+
*
|
|
38
|
+
* GET /api/blueprint/detect?dir=<path> — Check if PRD exists
|
|
39
|
+
* GET /api/blueprint/validate?dir=<path> — Full validation
|
|
40
|
+
* POST /api/blueprint/merge — Execute CLAUDE.md merge
|
|
41
|
+
*/
|
|
42
|
+
export declare function handleBlueprintRequest(method: string, path: string, body: unknown): Promise<{
|
|
43
|
+
status: number;
|
|
44
|
+
body: unknown;
|
|
45
|
+
} | null>;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blueprint API — validates pre-written PRDs for the Blueprint Path.
|
|
3
|
+
*
|
|
4
|
+
* Provides the API endpoint for the wizard UI's blueprint auto-detection
|
|
5
|
+
* and for programmatic PRD validation.
|
|
6
|
+
*
|
|
7
|
+
* PRD Reference: RFC-blueprint-path.md
|
|
8
|
+
*/
|
|
9
|
+
import { readFile } from 'node:fs/promises';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { addRoute } from '../router.js';
|
|
13
|
+
import { parseFrontmatter, validateFrontmatter } from '../lib/frontmatter.js';
|
|
14
|
+
import { validatePrdStructure, scanConflicts } from '../lib/prd-validator.js';
|
|
15
|
+
import { discoverDocuments } from '../lib/document-discovery.js';
|
|
16
|
+
import { mergeProjectDirectives, isAlreadyMerged } from '../lib/claude-merge.js';
|
|
17
|
+
// ── Validation Function ─────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Validate a project directory for the Blueprint Path.
|
|
20
|
+
* Returns comprehensive validation results without modifying any files.
|
|
21
|
+
*/
|
|
22
|
+
export async function validateBlueprint(projectRoot) {
|
|
23
|
+
const prdPath = join(projectRoot, 'docs/PRD.md');
|
|
24
|
+
// Check if PRD exists
|
|
25
|
+
if (!existsSync(prdPath)) {
|
|
26
|
+
return {
|
|
27
|
+
valid: false,
|
|
28
|
+
prdFound: false,
|
|
29
|
+
frontmatter: {},
|
|
30
|
+
frontmatterErrors: ['No PRD found at docs/PRD.md'],
|
|
31
|
+
structuralWarnings: [],
|
|
32
|
+
conflicts: [],
|
|
33
|
+
documents: { prd: null, projectDirectives: null, operations: null, adrs: [], references: [], total: 0 },
|
|
34
|
+
summary: 'No PRD found. Place your specification at docs/PRD.md.',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Parse PRD
|
|
38
|
+
const content = await readFile(prdPath, 'utf-8');
|
|
39
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
40
|
+
// Validate frontmatter
|
|
41
|
+
const frontmatterErrors = validateFrontmatter(frontmatter);
|
|
42
|
+
// Structural validation
|
|
43
|
+
const structural = validatePrdStructure(content, frontmatter);
|
|
44
|
+
// Conflict scan
|
|
45
|
+
const conflicts = scanConflicts(frontmatter);
|
|
46
|
+
// Document discovery
|
|
47
|
+
const documents = await discoverDocuments(projectRoot);
|
|
48
|
+
// Build summary
|
|
49
|
+
const summaryParts = [];
|
|
50
|
+
if (frontmatter.name)
|
|
51
|
+
summaryParts.push(`Project: ${frontmatter.name}`);
|
|
52
|
+
if (frontmatter.framework)
|
|
53
|
+
summaryParts.push(`Stack: ${frontmatter.framework}`);
|
|
54
|
+
if (frontmatter.deploy)
|
|
55
|
+
summaryParts.push(`Deploy: ${frontmatter.deploy}`);
|
|
56
|
+
summaryParts.push(`Documents: ${documents.total} found`);
|
|
57
|
+
if (frontmatterErrors.length > 0)
|
|
58
|
+
summaryParts.push(`Errors: ${frontmatterErrors.length}`);
|
|
59
|
+
if (structural.warnings.length > 0)
|
|
60
|
+
summaryParts.push(`Warnings: ${structural.warnings.length}`);
|
|
61
|
+
if (conflicts.length > 0)
|
|
62
|
+
summaryParts.push(`Conflicts: ${conflicts.length}`);
|
|
63
|
+
return {
|
|
64
|
+
valid: frontmatterErrors.length === 0,
|
|
65
|
+
prdFound: true,
|
|
66
|
+
frontmatter,
|
|
67
|
+
frontmatterErrors,
|
|
68
|
+
structuralWarnings: structural.warnings,
|
|
69
|
+
conflicts,
|
|
70
|
+
documents,
|
|
71
|
+
summary: summaryParts.join(' | '),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Execute the full blueprint merge (Step 3 of /blueprint).
|
|
76
|
+
* Only called after user confirms — this modifies CLAUDE.md.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Validate that a relative path does not escape the project root.
|
|
80
|
+
* Prevents path traversal attacks via ../ in user-supplied paths.
|
|
81
|
+
*/
|
|
82
|
+
function isPathSafe(projectRoot, relativePath) {
|
|
83
|
+
if (!relativePath || relativePath.includes('..') || relativePath.startsWith('/')) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const resolved = join(projectRoot, relativePath);
|
|
87
|
+
return resolved.startsWith(projectRoot);
|
|
88
|
+
}
|
|
89
|
+
export async function executeBlueprintMerge(projectRoot, directivesPath) {
|
|
90
|
+
if (!directivesPath) {
|
|
91
|
+
return { merged: false, reason: 'No project directives file discovered' };
|
|
92
|
+
}
|
|
93
|
+
// Path traversal prevention
|
|
94
|
+
if (!isPathSafe(projectRoot, directivesPath)) {
|
|
95
|
+
return { merged: false, reason: 'Invalid directives path — must be a relative path within the project' };
|
|
96
|
+
}
|
|
97
|
+
const alreadyMerged = await isAlreadyMerged(projectRoot);
|
|
98
|
+
if (alreadyMerged) {
|
|
99
|
+
return { merged: false, reason: 'Project directives already merged' };
|
|
100
|
+
}
|
|
101
|
+
const result = await mergeProjectDirectives(projectRoot, directivesPath);
|
|
102
|
+
return { merged: result.merged, reason: result.reason };
|
|
103
|
+
}
|
|
104
|
+
// ── Route Handler ───────────────────────────────────
|
|
105
|
+
/**
|
|
106
|
+
* Handle blueprint API requests. Mount at /api/blueprint/*
|
|
107
|
+
*
|
|
108
|
+
* GET /api/blueprint/detect?dir=<path> — Check if PRD exists
|
|
109
|
+
* GET /api/blueprint/validate?dir=<path> — Full validation
|
|
110
|
+
* POST /api/blueprint/merge — Execute CLAUDE.md merge
|
|
111
|
+
*/
|
|
112
|
+
export async function handleBlueprintRequest(method, path, body) {
|
|
113
|
+
if (method === 'GET' && path === '/api/blueprint/detect') {
|
|
114
|
+
// Quick check: does docs/PRD.md exist in the current project?
|
|
115
|
+
const projectRoot = process.cwd();
|
|
116
|
+
const prdPath = join(projectRoot, 'docs/PRD.md');
|
|
117
|
+
const exists = existsSync(prdPath);
|
|
118
|
+
if (exists) {
|
|
119
|
+
const content = await readFile(prdPath, 'utf-8');
|
|
120
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
121
|
+
return {
|
|
122
|
+
status: 200,
|
|
123
|
+
body: {
|
|
124
|
+
detected: true,
|
|
125
|
+
name: frontmatter.name ?? 'Unnamed',
|
|
126
|
+
description: frontmatter.type ?? 'Unknown type',
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return { status: 200, body: { detected: false } };
|
|
131
|
+
}
|
|
132
|
+
if (method === 'GET' && path === '/api/blueprint/validate') {
|
|
133
|
+
const projectRoot = process.cwd();
|
|
134
|
+
const result = await validateBlueprint(projectRoot);
|
|
135
|
+
return { status: 200, body: result };
|
|
136
|
+
}
|
|
137
|
+
if (method === 'POST' && path === '/api/blueprint/merge') {
|
|
138
|
+
const projectRoot = process.cwd();
|
|
139
|
+
const params = body;
|
|
140
|
+
const result = await executeBlueprintMerge(projectRoot, params?.directivesPath ?? null);
|
|
141
|
+
return { status: 200, body: result };
|
|
142
|
+
}
|
|
143
|
+
return null; // Not a blueprint route
|
|
144
|
+
}
|
|
145
|
+
// ── JSON Response Helper ────────────────────────────
|
|
146
|
+
function sendJson(res, status, data) {
|
|
147
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
148
|
+
res.end(JSON.stringify(data));
|
|
149
|
+
}
|
|
150
|
+
// ── Route Registration ──────────────────────────────
|
|
151
|
+
addRoute('GET', '/api/blueprint/detect', async (_req, res) => {
|
|
152
|
+
const projectRoot = process.cwd();
|
|
153
|
+
const prdPath = join(projectRoot, 'docs/PRD.md');
|
|
154
|
+
if (existsSync(prdPath)) {
|
|
155
|
+
const content = await readFile(prdPath, 'utf-8');
|
|
156
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
157
|
+
sendJson(res, 200, {
|
|
158
|
+
detected: true,
|
|
159
|
+
name: frontmatter.name ?? 'Unnamed',
|
|
160
|
+
description: frontmatter.type ?? 'Unknown type',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
sendJson(res, 200, { detected: false });
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
addRoute('GET', '/api/blueprint/validate', async (_req, res) => {
|
|
168
|
+
const projectRoot = process.cwd();
|
|
169
|
+
const result = await validateBlueprint(projectRoot);
|
|
170
|
+
sendJson(res, 200, result);
|
|
171
|
+
});
|
|
172
|
+
addRoute('POST', '/api/blueprint/merge', async (req, res) => {
|
|
173
|
+
let body = '';
|
|
174
|
+
for await (const chunk of req)
|
|
175
|
+
body += chunk;
|
|
176
|
+
let params = {};
|
|
177
|
+
try {
|
|
178
|
+
params = JSON.parse(body);
|
|
179
|
+
}
|
|
180
|
+
catch { /* empty body is fine — directivesPath defaults to null */ }
|
|
181
|
+
const projectRoot = process.cwd();
|
|
182
|
+
const result = await executeBlueprintMerge(projectRoot, params.directivesPath ?? null);
|
|
183
|
+
sendJson(res, 200, result);
|
|
184
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ProviderInfo {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
fields: {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
placeholder: string;
|
|
8
|
+
secret: boolean;
|
|
9
|
+
optional?: boolean;
|
|
10
|
+
}[];
|
|
11
|
+
deployTargets: string[];
|
|
12
|
+
description: string;
|
|
13
|
+
credentialUrl: string;
|
|
14
|
+
help: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const PROVIDERS: ProviderInfo[];
|