@convex-dev/static-hosting 0.1.2-beta.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.
Files changed (98) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +333 -0
  3. package/dist/cli/deploy.d.ts +16 -0
  4. package/dist/cli/deploy.d.ts.map +1 -0
  5. package/dist/cli/deploy.js +324 -0
  6. package/dist/cli/deploy.js.map +1 -0
  7. package/dist/cli/index.d.ts +15 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +95 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/init.d.ts +9 -0
  12. package/dist/cli/init.d.ts.map +1 -0
  13. package/dist/cli/init.js +181 -0
  14. package/dist/cli/init.js.map +1 -0
  15. package/dist/cli/next-build.d.ts +24 -0
  16. package/dist/cli/next-build.d.ts.map +1 -0
  17. package/dist/cli/next-build.js +569 -0
  18. package/dist/cli/next-build.js.map +1 -0
  19. package/dist/cli/setup.d.ts +9 -0
  20. package/dist/cli/setup.d.ts.map +1 -0
  21. package/dist/cli/setup.js +157 -0
  22. package/dist/cli/setup.js.map +1 -0
  23. package/dist/cli/upload.d.ts +15 -0
  24. package/dist/cli/upload.d.ts.map +1 -0
  25. package/dist/cli/upload.js +436 -0
  26. package/dist/cli/upload.js.map +1 -0
  27. package/dist/client/_generated/_ignore.d.ts +1 -0
  28. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  29. package/dist/client/_generated/_ignore.js +3 -0
  30. package/dist/client/_generated/_ignore.js.map +1 -0
  31. package/dist/client/index.d.ts +142 -0
  32. package/dist/client/index.d.ts.map +1 -0
  33. package/dist/client/index.js +475 -0
  34. package/dist/client/index.js.map +1 -0
  35. package/dist/client/next.d.ts +38 -0
  36. package/dist/client/next.d.ts.map +1 -0
  37. package/dist/client/next.js +175 -0
  38. package/dist/client/next.js.map +1 -0
  39. package/dist/client/nextAdapter.d.ts +4 -0
  40. package/dist/client/nextAdapter.d.ts.map +1 -0
  41. package/dist/client/nextAdapter.js +9 -0
  42. package/dist/client/nextAdapter.js.map +1 -0
  43. package/dist/component/_generated/api.d.ts +34 -0
  44. package/dist/component/_generated/api.d.ts.map +1 -0
  45. package/dist/component/_generated/api.js +31 -0
  46. package/dist/component/_generated/api.js.map +1 -0
  47. package/dist/component/_generated/component.d.ts +73 -0
  48. package/dist/component/_generated/component.d.ts.map +1 -0
  49. package/dist/component/_generated/component.js +11 -0
  50. package/dist/component/_generated/component.js.map +1 -0
  51. package/dist/component/_generated/dataModel.d.ts +46 -0
  52. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  53. package/dist/component/_generated/dataModel.js +11 -0
  54. package/dist/component/_generated/dataModel.js.map +1 -0
  55. package/dist/component/_generated/server.d.ts +121 -0
  56. package/dist/component/_generated/server.d.ts.map +1 -0
  57. package/dist/component/_generated/server.js +78 -0
  58. package/dist/component/_generated/server.js.map +1 -0
  59. package/dist/component/convex.config.d.ts +3 -0
  60. package/dist/component/convex.config.d.ts.map +1 -0
  61. package/dist/component/convex.config.js +3 -0
  62. package/dist/component/convex.config.js.map +1 -0
  63. package/dist/component/lib.d.ts +88 -0
  64. package/dist/component/lib.d.ts.map +1 -0
  65. package/dist/component/lib.js +210 -0
  66. package/dist/component/lib.js.map +1 -0
  67. package/dist/component/schema.d.ts +27 -0
  68. package/dist/component/schema.d.ts.map +1 -0
  69. package/dist/component/schema.js +20 -0
  70. package/dist/component/schema.js.map +1 -0
  71. package/dist/react/index.d.ts +80 -0
  72. package/dist/react/index.d.ts.map +1 -0
  73. package/dist/react/index.js +138 -0
  74. package/dist/react/index.js.map +1 -0
  75. package/package.json +120 -0
  76. package/src/cli/deploy.ts +375 -0
  77. package/src/cli/index.ts +104 -0
  78. package/src/cli/init.ts +181 -0
  79. package/src/cli/next-build.ts +707 -0
  80. package/src/cli/setup.ts +190 -0
  81. package/src/cli/upload.ts +521 -0
  82. package/src/client/_generated/_ignore.ts +1 -0
  83. package/src/client/index.test.ts +67 -0
  84. package/src/client/index.ts +553 -0
  85. package/src/client/next.ts +223 -0
  86. package/src/client/nextAdapter.ts +17 -0
  87. package/src/client/setup.test.ts +26 -0
  88. package/src/component/_generated/api.ts +50 -0
  89. package/src/component/_generated/component.ts +104 -0
  90. package/src/component/_generated/dataModel.ts +60 -0
  91. package/src/component/_generated/server.ts +161 -0
  92. package/src/component/convex.config.ts +3 -0
  93. package/src/component/lib.test.ts +110 -0
  94. package/src/component/lib.ts +228 -0
  95. package/src/component/schema.ts +21 -0
  96. package/src/component/setup.test.ts +11 -0
  97. package/src/react/index.tsx +184 -0
  98. package/src/test.ts +18 -0
package/package.json ADDED
@@ -0,0 +1,120 @@
1
+ {
2
+ "name": "@convex-dev/static-hosting",
3
+ "description": "A static hosting component for Convex.",
4
+ "repository": "github:get-convex/static-hosting",
5
+ "homepage": "https://github.com/get-convex/static-hosting#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/get-convex/static-hosting/issues"
8
+ },
9
+ "version": "0.1.2-beta.0",
10
+ "license": "Apache-2.0",
11
+ "keywords": [
12
+ "convex",
13
+ "component"
14
+ ],
15
+ "type": "module",
16
+ "bin": {
17
+ "static-hosting": "./dist/cli/index.js"
18
+ },
19
+ "scripts": {
20
+ "postinstall": "echo '\\n📦 @convex-dev/static-hosting installed!\\n\\n 🚀 Quick Setup (Interactive):\\n npx @convex-dev/static-hosting setup\\n\\n 🤖 For LLMs: See INTEGRATION.md for complete integration instructions\\n 📖 Manual Setup: npx @convex-dev/static-hosting init\\n'",
21
+ "dev": "run-p -r 'dev:*'",
22
+ "dev:backend": "convex dev --typecheck-components",
23
+ "dev:frontend": "cd example && vite --clearScreen false",
24
+ "build:example": "cd example && vite build",
25
+ "upload:static": "node dist/cli/index.js upload --dist ./example/dist --component staticHosting",
26
+ "deploy:static": "npm run build:example && npm run upload:static",
27
+ "dev:build": "chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial",
28
+ "predev": "path-exists .env.local dist || (npm run build && convex dev --once)",
29
+ "build": "tsc --project ./tsconfig.build.json",
30
+ "build:codegen": "npx convex codegen --component-dir ./src/component && npm run build",
31
+ "build:clean": "rm -rf dist *.tsbuildinfo && npm run build:codegen",
32
+ "typecheck": "tsc --noEmit && tsc -p example && tsc -p example/convex",
33
+ "lint": "eslint .",
34
+ "all": "run-p -r 'dev:*' 'test:watch'",
35
+ "test": "vitest run --typecheck",
36
+ "test:watch": "vitest --typecheck --clearScreen false",
37
+ "test:debug": "vitest --inspect-brk --no-file-parallelism",
38
+ "test:coverage": "vitest run --coverage --coverage.reporter=text",
39
+ "preversion": "npm ci && npm run build:clean && run-p test lint typecheck",
40
+ "alpha": "npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags",
41
+ "release": "npm version patch && npm publish && git push --follow-tags",
42
+ "version": "vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "src"
47
+ ],
48
+ "exports": {
49
+ "./package.json": "./package.json",
50
+ ".": {
51
+ "types": "./dist/client/index.d.ts",
52
+ "default": "./dist/client/index.js"
53
+ },
54
+ "./react": {
55
+ "types": "./dist/react/index.d.ts",
56
+ "default": "./dist/react/index.js"
57
+ },
58
+ "./next": {
59
+ "types": "./dist/client/next.d.ts",
60
+ "default": "./dist/client/next.js"
61
+ },
62
+ "./nextAdapter": {
63
+ "types": "./dist/client/nextAdapter.d.ts",
64
+ "default": "./dist/client/nextAdapter.js"
65
+ },
66
+ "./test": "./src/test.ts",
67
+ "./_generated/component.js": {
68
+ "types": "./dist/component/_generated/component.d.ts"
69
+ },
70
+ "./_generated/component": {
71
+ "types": "./dist/component/_generated/component.d.ts"
72
+ },
73
+ "./convex.config.js": {
74
+ "types": "./dist/component/convex.config.d.ts",
75
+ "default": "./dist/component/convex.config.js"
76
+ },
77
+ "./convex.config": {
78
+ "types": "./dist/component/convex.config.d.ts",
79
+ "default": "./dist/component/convex.config.js"
80
+ }
81
+ },
82
+ "dependencies": {
83
+ "fetch-to-node": "^2.1.0"
84
+ },
85
+ "peerDependencies": {
86
+ "convex": "^1.29.3",
87
+ "react": "^18.3.1 || ^19.0.0"
88
+ },
89
+ "devDependencies": {
90
+ "@convex-dev/eslint-plugin": "^1.1.1",
91
+ "@edge-runtime/vm": "^5.0.0",
92
+ "@eslint/eslintrc": "^3.3.1",
93
+ "@eslint/js": "9.39.1",
94
+ "@types/node": "^24.10.4",
95
+ "@types/react": "^19.2.7",
96
+ "@types/react-dom": "^19.2.3",
97
+ "@vitejs/plugin-react": "^5.1.1",
98
+ "chokidar-cli": "3.0.0",
99
+ "convex": "1.31.0",
100
+ "convex-test": "0.0.40",
101
+ "cpy-cli": "^6.0.0",
102
+ "eslint": "9.39.1",
103
+ "eslint-plugin-react": "^7.37.5",
104
+ "eslint-plugin-react-hooks": "^7.0.1",
105
+ "eslint-plugin-react-refresh": "^0.4.24",
106
+ "globals": "^17.0.0",
107
+ "npm-run-all2": "8.0.4",
108
+ "path-exists-cli": "2.0.0",
109
+ "pkg-pr-new": "^0.0.60",
110
+ "prettier": "3.6.2",
111
+ "react": "^19.2.1",
112
+ "react-dom": "^19.2.1",
113
+ "typescript": "5.9.3",
114
+ "typescript-eslint": "8.47.0",
115
+ "vite": "7.2.6",
116
+ "vitest": "4.0.17"
117
+ },
118
+ "types": "./dist/client/index.d.ts",
119
+ "module": "./dist/client/index.js"
120
+ }
@@ -0,0 +1,375 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * One-shot deployment command that deploys both Convex backend and static files.
4
+ *
5
+ * Usage:
6
+ * npx @convex-dev/static-hosting deploy [options]
7
+ *
8
+ * This command:
9
+ * 1. Builds the frontend with the correct VITE_CONVEX_URL
10
+ * 2. Deploys the Convex backend (npx convex deploy)
11
+ * 3. Deploys static files to Convex storage
12
+ *
13
+ * The goal is to minimize the inconsistency window between backend and frontend.
14
+ */
15
+
16
+ import { existsSync, readFileSync } from "fs";
17
+ import { resolve } from "path";
18
+ import { execSync, spawnSync } from "child_process";
19
+
20
+ interface ParsedArgs {
21
+ dist: string;
22
+ component: string;
23
+ help: boolean;
24
+ skipBuild: boolean;
25
+ skipConvex: boolean;
26
+ cdn: boolean;
27
+ dev: boolean;
28
+ }
29
+
30
+ function parseArgs(args: string[]): ParsedArgs {
31
+ const result: ParsedArgs = {
32
+ dist: "./dist",
33
+ component: "staticHosting",
34
+ help: false,
35
+ skipBuild: false,
36
+ skipConvex: false,
37
+ cdn: false,
38
+ dev: false,
39
+ };
40
+
41
+ for (let i = 0; i < args.length; i++) {
42
+ const arg = args[i];
43
+ if (arg === "--help" || arg === "-h") {
44
+ result.help = true;
45
+ } else if (arg === "--dist" || arg === "-d") {
46
+ result.dist = args[++i] || result.dist;
47
+ } else if (arg === "--component" || arg === "-c") {
48
+ result.component = args[++i] || result.component;
49
+ } else if (arg === "--skip-build") {
50
+ result.skipBuild = true;
51
+ } else if (arg === "--skip-convex") {
52
+ result.skipConvex = true;
53
+ } else if (arg === "--cdn") {
54
+ result.cdn = true;
55
+ } else if (arg === "--dev") {
56
+ result.dev = true;
57
+ }
58
+ }
59
+
60
+ return result;
61
+ }
62
+
63
+ function showHelp(): void {
64
+ console.log(`
65
+ Usage: npx @convex-dev/static-hosting deploy [options]
66
+
67
+ One-shot deployment: builds frontend, deploys Convex backend, then deploys static files.
68
+ Minimizes the inconsistency window between backend and frontend updates.
69
+
70
+ Options:
71
+ -d, --dist <path> Path to dist directory (default: ./dist)
72
+ -c, --component <name> Convex component name (default: staticHosting)
73
+ --skip-build Skip the build step (use existing dist)
74
+ --skip-convex Skip Convex backend deployment
75
+ --cdn Upload non-HTML assets to convex-fs CDN
76
+ --dev Deploy to dev environment (skip backend deploy, upload without --prod)
77
+ -h, --help Show this help message
78
+
79
+ Deployment Flow (production, default):
80
+ 1. Build frontend with production VITE_CONVEX_URL
81
+ 2. Deploy Convex backend (npx convex deploy)
82
+ 3. Deploy static files to Convex storage
83
+
84
+ Deployment Flow (--dev):
85
+ 1. Build frontend with dev VITE_CONVEX_URL (from .env.local)
86
+ 2. Skip Convex backend deployment (use running 'npx convex dev')
87
+ 3. Deploy static files to dev Convex storage
88
+
89
+ Examples:
90
+ # Full production deployment
91
+ npx @convex-dev/static-hosting deploy
92
+
93
+ # Deploy to dev environment
94
+ npx @convex-dev/static-hosting deploy --dev
95
+
96
+ # Skip build (if already built)
97
+ npx @convex-dev/static-hosting deploy --skip-build
98
+
99
+ # Only deploy static files (skip Convex backend)
100
+ npx @convex-dev/static-hosting deploy --skip-convex
101
+ `);
102
+ }
103
+
104
+ /**
105
+ * Get the production Convex URL
106
+ */
107
+ function getConvexProdUrl(): string | null {
108
+ try {
109
+ const result = execSync("npx convex env get CONVEX_CLOUD_URL --prod", {
110
+ stdio: "pipe",
111
+ encoding: "utf-8",
112
+ });
113
+ return result.trim() || null;
114
+ } catch {
115
+ // Fall back to env files
116
+ }
117
+
118
+ // Try env files as fallback
119
+ const envFiles = [".env.production", ".env.production.local", ".env.local"];
120
+ for (const envFile of envFiles) {
121
+ if (existsSync(envFile)) {
122
+ const content = readFileSync(envFile, "utf-8");
123
+ const match = content.match(/(?:VITE_)?CONVEX_URL=(.+)/);
124
+ if (match) {
125
+ return match[1].trim();
126
+ }
127
+ }
128
+ }
129
+
130
+ return null;
131
+ }
132
+
133
+ /**
134
+ * Get the dev Convex URL (from running `npx convex dev`)
135
+ */
136
+ function getConvexDevUrl(): string | null {
137
+ try {
138
+ const result = execSync("npx convex env get CONVEX_CLOUD_URL", {
139
+ stdio: "pipe",
140
+ encoding: "utf-8",
141
+ });
142
+ return result.trim() || null;
143
+ } catch {
144
+ // Fall back to env files
145
+ }
146
+
147
+ // Try .env.local (standard location for dev URL)
148
+ const envFiles = [".env.local", ".env.development.local", ".env.development"];
149
+ for (const envFile of envFiles) {
150
+ if (existsSync(envFile)) {
151
+ const content = readFileSync(envFile, "utf-8");
152
+ const match = content.match(/(?:VITE_)?CONVEX_URL=(.+)/);
153
+ if (match) {
154
+ return match[1].trim();
155
+ }
156
+ }
157
+ }
158
+
159
+ return null;
160
+ }
161
+
162
+ /**
163
+ * Run the Convex storage upload flow
164
+ */
165
+ async function uploadToConvexStorage(
166
+ distDir: string,
167
+ componentName: string,
168
+ useCdn: boolean,
169
+ prod: boolean,
170
+ ): Promise<boolean> {
171
+ console.log("");
172
+ console.log(useCdn
173
+ ? "📦 Uploading static files (HTML to Convex, assets to CDN)..."
174
+ : "📦 Uploading static files to Convex storage...");
175
+ console.log("");
176
+
177
+ const uploadArgs = [
178
+ "@convex-dev/static-hosting",
179
+ "upload",
180
+ "--dist",
181
+ distDir,
182
+ "--component",
183
+ componentName,
184
+ ];
185
+
186
+ if (prod) {
187
+ uploadArgs.push("--prod");
188
+ }
189
+
190
+ if (useCdn) {
191
+ uploadArgs.push("--cdn");
192
+ }
193
+
194
+ const result = spawnSync("npx", uploadArgs, { stdio: "inherit" });
195
+
196
+ return result.status === 0;
197
+ }
198
+
199
+ async function main(): Promise<void> {
200
+ const args = parseArgs(process.argv.slice(2));
201
+
202
+ if (args.help) {
203
+ showHelp();
204
+ process.exit(0);
205
+ }
206
+
207
+ const isDev = args.dev;
208
+
209
+ // --dev implies --skip-convex (backend is managed by `npx convex dev`)
210
+ if (isDev) {
211
+ args.skipConvex = true;
212
+ }
213
+
214
+ console.log("");
215
+ console.log(isDev
216
+ ? "🚀 Convex + Static Files Deployment (dev)"
217
+ : "🚀 Convex + Static Files Deployment");
218
+ console.log("═══════════════════════════════════════════════════════════");
219
+
220
+ const startTime = Date.now();
221
+
222
+ // Step 1: Get Convex URL (needed for build)
223
+ console.log("");
224
+ console.log(isDev
225
+ ? "Step 1: Getting dev Convex URL..."
226
+ : "Step 1: Getting production Convex URL...");
227
+
228
+ let convexUrl = isDev ? getConvexDevUrl() : getConvexProdUrl();
229
+
230
+ if (!convexUrl && !args.skipConvex) {
231
+ console.log(" No production deployment found. Will get URL after deploying backend.");
232
+ } else if (!convexUrl && isDev) {
233
+ console.error("");
234
+ console.error("❌ Could not determine dev Convex URL");
235
+ console.error(" Make sure 'npx convex dev' is running and .env.local contains CONVEX_URL");
236
+ process.exit(1);
237
+ } else if (convexUrl) {
238
+ console.log(` ✓ ${convexUrl}`);
239
+ }
240
+
241
+ // Step 2: Build frontend
242
+ if (!args.skipBuild) {
243
+ console.log("");
244
+ console.log("Step 2: Building frontend...");
245
+
246
+ // If we don't have a URL yet, we need to deploy Convex first to get it
247
+ if (!convexUrl && !args.skipConvex) {
248
+ console.log(" Deploying Convex backend first to get production URL...");
249
+ console.log("");
250
+
251
+ const convexResult = spawnSync("npx", ["convex", "deploy"], {
252
+ stdio: "inherit",
253
+ });
254
+
255
+ if (convexResult.status !== 0) {
256
+ console.error("");
257
+ console.error("❌ Convex deployment failed");
258
+ process.exit(1);
259
+ }
260
+
261
+ // Now get the URL
262
+ convexUrl = getConvexProdUrl();
263
+ if (!convexUrl) {
264
+ console.error("");
265
+ console.error("❌ Could not get production Convex URL after deployment");
266
+ process.exit(1);
267
+ }
268
+ console.log("");
269
+ console.log(` ✓ Production URL: ${convexUrl}`);
270
+ args.skipConvex = true; // Already deployed
271
+ }
272
+
273
+ if (!convexUrl) {
274
+ console.error("");
275
+ console.error("❌ Could not determine Convex URL for build");
276
+ console.error(" Run 'npx convex deploy' first or remove --skip-convex");
277
+ process.exit(1);
278
+ }
279
+
280
+ console.log(` Building with VITE_CONVEX_URL=${convexUrl}`);
281
+ console.log("");
282
+
283
+ const buildResult = spawnSync("npm", ["run", "build"], {
284
+ stdio: "inherit",
285
+ env: { ...process.env, VITE_CONVEX_URL: convexUrl },
286
+ });
287
+
288
+ if (buildResult.status !== 0) {
289
+ console.error("");
290
+ console.error("❌ Build failed");
291
+ process.exit(1);
292
+ }
293
+
294
+ console.log("");
295
+ console.log(" ✓ Build complete");
296
+ } else {
297
+ console.log("");
298
+ console.log("Step 2: Skipping build (--skip-build)");
299
+ }
300
+
301
+ // Step 3: Deploy Convex backend
302
+ if (!args.skipConvex) {
303
+ console.log("");
304
+ console.log("Step 3: Deploying Convex backend...");
305
+ console.log("");
306
+
307
+ const convexResult = spawnSync("npx", ["convex", "deploy"], {
308
+ stdio: "inherit",
309
+ });
310
+
311
+ if (convexResult.status !== 0) {
312
+ console.error("");
313
+ console.error("❌ Convex deployment failed");
314
+ process.exit(1);
315
+ }
316
+
317
+ console.log("");
318
+ console.log(" ✓ Convex backend deployed");
319
+ } else {
320
+ console.log("");
321
+ console.log("Step 3: Skipping Convex deployment (--skip-convex or already deployed)");
322
+ }
323
+
324
+ // Step 4: Deploy static files
325
+ console.log("");
326
+ console.log("Step 4: Deploying static files to Convex storage...");
327
+
328
+ const distDir = resolve(args.dist);
329
+
330
+ if (!existsSync(distDir)) {
331
+ console.error("");
332
+ console.error(`❌ Dist directory not found: ${distDir}`);
333
+ console.error(" Run build first or check --dist path");
334
+ process.exit(1);
335
+ }
336
+
337
+ const staticDeploySuccess = await uploadToConvexStorage(distDir, args.component, args.cdn, !isDev);
338
+
339
+ if (!staticDeploySuccess) {
340
+ console.error("");
341
+ console.error("❌ Static file upload failed");
342
+ process.exit(1);
343
+ }
344
+
345
+ // Done!
346
+ const duration = ((Date.now() - startTime) / 1000).toFixed(1);
347
+
348
+ console.log("");
349
+ console.log("═══════════════════════════════════════════════════════════");
350
+ console.log(`✨ Deployment complete! (${duration}s)`);
351
+ console.log("");
352
+
353
+ // Show Convex site URL
354
+ try {
355
+ const envFlag = isDev ? "" : "--prod";
356
+ const result = execSync(`npx convex env get CONVEX_CLOUD_URL ${envFlag}`, {
357
+ stdio: "pipe",
358
+ encoding: "utf-8",
359
+ });
360
+ const cloudUrl = result.trim();
361
+ if (cloudUrl && cloudUrl.includes(".convex.cloud")) {
362
+ const siteUrl = cloudUrl.replace(".convex.cloud", ".convex.site");
363
+ console.log(`Frontend: ${siteUrl}`);
364
+ }
365
+ } catch {
366
+ // Ignore
367
+ }
368
+
369
+ console.log("");
370
+ }
371
+
372
+ main().catch((error) => {
373
+ console.error("Deployment failed:", error);
374
+ process.exit(1);
375
+ });
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for Convex Static Hosting
4
+ *
5
+ * Commands:
6
+ * deploy One-shot deployment (Convex backend + static files)
7
+ * upload Upload static files to Convex storage
8
+ * next-build Build Next.js app and prepare for Convex deployment
9
+ * init Print setup instructions
10
+ */
11
+
12
+ const command = process.argv[2];
13
+
14
+ async function main() {
15
+ switch (command) {
16
+ case "setup":
17
+ await import("./setup.js");
18
+ break;
19
+
20
+ case "deploy":
21
+ // Pass remaining args to deploy command
22
+ process.argv.splice(2, 1);
23
+ await import("./deploy.js");
24
+ break;
25
+
26
+ case "upload":
27
+ // Pass remaining args to upload command
28
+ process.argv.splice(2, 1);
29
+ await import("./upload.js");
30
+ break;
31
+
32
+ case "next-build":
33
+ // Pass remaining args to next-build command
34
+ process.argv.splice(2, 1);
35
+ await import("./next-build.js");
36
+ break;
37
+
38
+ case "init":
39
+ printInitInstructions();
40
+ break;
41
+
42
+ case "--help":
43
+ case "-h":
44
+ case undefined:
45
+ printHelp();
46
+ break;
47
+
48
+ default:
49
+ console.error(`Unknown command: ${command}`);
50
+ console.log("");
51
+ printHelp();
52
+ process.exit(1);
53
+ }
54
+ }
55
+
56
+ function printHelp() {
57
+ console.log(`
58
+ Convex Static Hosting CLI
59
+
60
+ Usage:
61
+ npx @convex-dev/static-hosting <command> [options]
62
+
63
+ Commands:
64
+ setup Interactive setup wizard (creates files, configures deployment)
65
+ deploy One-shot deployment (Convex backend + static files)
66
+ upload Upload static files to Convex storage
67
+ next-build Build Next.js app and prepare for Convex deployment
68
+ init Print setup instructions for integration
69
+
70
+ Examples:
71
+ # Interactive setup (recommended for first-time users)
72
+ npx @convex-dev/static-hosting setup
73
+
74
+ # One-shot deployment
75
+ npx @convex-dev/static-hosting deploy
76
+
77
+ # Upload only (no Convex backend deploy)
78
+ npx @convex-dev/static-hosting upload --build --prod
79
+
80
+ Run '<command> --help' for more information on a specific command.
81
+ `);
82
+ }
83
+
84
+ function printInitInstructions() {
85
+ console.log(`
86
+ 📦 Convex Static Hosting
87
+
88
+ Quick Start:
89
+ npx @convex-dev/static-hosting setup # Interactive setup wizard
90
+
91
+ For LLMs:
92
+ Read INTEGRATION.md in this package for complete integration instructions
93
+
94
+ Manual Setup:
95
+ See README.md at https://github.com/get-convex/static-hosting#readme
96
+
97
+ This component hosts your static files in Convex storage and serves them via HTTP actions.
98
+ `);
99
+ }
100
+
101
+ main().catch((err) => {
102
+ console.error("Error:", err);
103
+ process.exit(1);
104
+ });