@just-be/deploy 0.4.0 → 0.6.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/README.md +12 -3
- package/index.ts +104 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,15 +5,24 @@ Deploy static sites and setup routing for the wildcard subdomain service.
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- [Bun](https://bun.sh/) runtime
|
|
8
|
-
- [Wrangler](https://developers.cloudflare.com/workers/wrangler/) CLI configured with Cloudflare credentials
|
|
9
8
|
- A Cloudflare Workers wildcard subdomain service with R2 and KV configured
|
|
10
9
|
|
|
10
|
+
## Authentication
|
|
11
|
+
|
|
12
|
+
The script will automatically run `wrangler login` if you're not authenticated with Cloudflare. This will open a browser window for OAuth authentication.
|
|
13
|
+
|
|
14
|
+
Alternatively, you can set the `CLOUDFLARE_API_TOKEN` environment variable:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
export CLOUDFLARE_API_TOKEN="your-api-token"
|
|
18
|
+
```
|
|
19
|
+
|
|
11
20
|
## Configuration
|
|
12
21
|
|
|
13
22
|
The deploy script requires access to:
|
|
14
23
|
|
|
15
|
-
- **KV namespace** for routing rules
|
|
16
|
-
- **R2 bucket** for static file storage
|
|
24
|
+
- **KV namespace** for routing rules
|
|
25
|
+
- **R2 bucket** for static file storage
|
|
17
26
|
|
|
18
27
|
### Environment Variables
|
|
19
28
|
|
package/index.ts
CHANGED
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
* bunx @just-be/deploy # Looks for deploy.json in current directory
|
|
8
8
|
* bunx @just-be/deploy path/to/config.json # Deploy with specific config file
|
|
9
9
|
* bunx @just-be/deploy preview <subdomain> # Preview deploy with branch name suffix
|
|
10
|
+
* bunx @just-be/deploy --version # Show version
|
|
11
|
+
*
|
|
12
|
+
* Authentication:
|
|
13
|
+
* The script will automatically run 'wrangler login' if you're not authenticated.
|
|
14
|
+
* Alternatively, set CLOUDFLARE_API_TOKEN environment variable.
|
|
15
|
+
*
|
|
16
|
+
* Environment Variables:
|
|
17
|
+
* R2_BUCKET_NAME # R2 bucket name
|
|
18
|
+
* KV_NAMESPACE_ID # KV namespace ID
|
|
19
|
+
* DEBUG # Set to "1" or "true" to enable verbose error output
|
|
10
20
|
*
|
|
11
21
|
* Example deploy.json:
|
|
12
22
|
* {
|
|
@@ -37,6 +47,7 @@ import { readdir, stat, access } from "fs/promises";
|
|
|
37
47
|
import { join, relative, resolve } from "path";
|
|
38
48
|
import { intro, outro, spinner } from "@clack/prompts";
|
|
39
49
|
import { z } from "zod";
|
|
50
|
+
import packageJson from "./package.json" with { type: "json" };
|
|
40
51
|
import {
|
|
41
52
|
StaticConfigSchema,
|
|
42
53
|
RedirectConfigSchema,
|
|
@@ -47,6 +58,7 @@ import {
|
|
|
47
58
|
|
|
48
59
|
const BUCKET_NAME = process.env.R2_BUCKET_NAME || "content-bucket";
|
|
49
60
|
const KV_NAMESPACE_ID = process.env.KV_NAMESPACE_ID || "6118ae3b937c4883b3c582dfef8a0c05";
|
|
61
|
+
const DEBUG = process.env.DEBUG === "1" || process.env.DEBUG === "true";
|
|
50
62
|
|
|
51
63
|
/**
|
|
52
64
|
* Run wrangler command using bunx to ensure it resolves from package dependencies
|
|
@@ -167,7 +179,34 @@ async function uploadToR2(localPath: string, r2Key: string): Promise<boolean> {
|
|
|
167
179
|
await wrangler`r2 object put ${BUCKET_NAME}/${r2Key} --file ${localPath}`;
|
|
168
180
|
return true;
|
|
169
181
|
} catch (error) {
|
|
170
|
-
|
|
182
|
+
if (DEBUG) {
|
|
183
|
+
console.error(`\nFailed to upload ${localPath}:`);
|
|
184
|
+
console.error("Error details:", error);
|
|
185
|
+
if (error instanceof Error) {
|
|
186
|
+
console.error("Stack trace:", error.stack);
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
console.error(`\nFailed to upload ${localPath}:`, error);
|
|
190
|
+
}
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Check if user is authenticated with wrangler
|
|
197
|
+
*/
|
|
198
|
+
async function validateWranglerAuth(): Promise<boolean> {
|
|
199
|
+
try {
|
|
200
|
+
await wrangler`whoami`.quiet();
|
|
201
|
+
return true;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
if (DEBUG) {
|
|
204
|
+
console.error("\nWrangler auth validation failed:");
|
|
205
|
+
console.error("Error details:", error);
|
|
206
|
+
if (error instanceof Error) {
|
|
207
|
+
console.error("Stack trace:", error.stack);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
171
210
|
return false;
|
|
172
211
|
}
|
|
173
212
|
}
|
|
@@ -179,7 +218,15 @@ async function validateKVAccess(): Promise<boolean> {
|
|
|
179
218
|
try {
|
|
180
219
|
await wrangler`kv key list --namespace-id ${KV_NAMESPACE_ID}`.quiet();
|
|
181
220
|
return true;
|
|
182
|
-
} catch {
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (DEBUG) {
|
|
223
|
+
console.error("\nKV access validation failed:");
|
|
224
|
+
console.error("Error details:", error);
|
|
225
|
+
if (error instanceof Error) {
|
|
226
|
+
console.error("Stack trace:", error.stack);
|
|
227
|
+
}
|
|
228
|
+
console.error(`Namespace ID: ${KV_NAMESPACE_ID}`);
|
|
229
|
+
}
|
|
183
230
|
return false;
|
|
184
231
|
}
|
|
185
232
|
}
|
|
@@ -192,6 +239,13 @@ async function getCurrentBranch(): Promise<string> {
|
|
|
192
239
|
const result = await $`git rev-parse --abbrev-ref HEAD`.text();
|
|
193
240
|
return result.trim();
|
|
194
241
|
} catch (error) {
|
|
242
|
+
if (DEBUG) {
|
|
243
|
+
console.error("\nFailed to get current git branch:");
|
|
244
|
+
console.error("Error details:", error);
|
|
245
|
+
if (error instanceof Error) {
|
|
246
|
+
console.error("Stack trace:", error.stack);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
195
249
|
throw new Error("Failed to get current git branch. Are you in a git repository?");
|
|
196
250
|
}
|
|
197
251
|
}
|
|
@@ -394,13 +448,50 @@ async function deploy() {
|
|
|
394
448
|
console.log(`\nFound ${config.rules.length} rule(s) to deploy`);
|
|
395
449
|
}
|
|
396
450
|
|
|
397
|
-
//
|
|
451
|
+
// Check wrangler authentication first
|
|
398
452
|
const s = spinner();
|
|
453
|
+
s.start("Checking wrangler authentication");
|
|
454
|
+
const isAuthenticated = await validateWranglerAuth();
|
|
455
|
+
if (!isAuthenticated) {
|
|
456
|
+
s.stop("Not authenticated with wrangler");
|
|
457
|
+
console.log("\nAuthenticating with Cloudflare...");
|
|
458
|
+
console.log("This will open a browser window for you to authorize access.\n");
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
await wrangler`login`;
|
|
462
|
+
console.log("\n✓ Successfully authenticated!");
|
|
463
|
+
|
|
464
|
+
// Verify authentication worked
|
|
465
|
+
s.start("Verifying authentication");
|
|
466
|
+
const isNowAuthenticated = await validateWranglerAuth();
|
|
467
|
+
if (!isNowAuthenticated) {
|
|
468
|
+
s.stop("Error: Authentication verification failed");
|
|
469
|
+
console.error("\nIf you prefer to use an API token instead:");
|
|
470
|
+
console.error(" export CLOUDFLARE_API_TOKEN=your-token");
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
s.stop("✓ Authentication verified");
|
|
474
|
+
} catch {
|
|
475
|
+
console.error("\n❌ Authentication failed");
|
|
476
|
+
console.error("\nAlternatively, you can set up an API token:");
|
|
477
|
+
console.error(" export CLOUDFLARE_API_TOKEN=your-token");
|
|
478
|
+
process.exit(1);
|
|
479
|
+
}
|
|
480
|
+
} else {
|
|
481
|
+
s.stop("✓ Wrangler authenticated");
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Validate KV access
|
|
399
485
|
s.start("Validating KV access");
|
|
400
486
|
const hasKVAccess = await validateKVAccess();
|
|
401
487
|
if (!hasKVAccess) {
|
|
402
488
|
s.stop("Error: Cannot access KV namespace");
|
|
403
|
-
console.error("
|
|
489
|
+
console.error("\nCheck that you have permission to access the KV namespace.");
|
|
490
|
+
console.error(`KV Namespace ID: ${KV_NAMESPACE_ID}`);
|
|
491
|
+
console.error("\nYou may need to:");
|
|
492
|
+
console.error(" 1. Verify the namespace ID is correct");
|
|
493
|
+
console.error(" 2. Ensure your account has access to this KV namespace");
|
|
494
|
+
console.error(" 3. Check wrangler.toml configuration if using one");
|
|
404
495
|
process.exit(1);
|
|
405
496
|
}
|
|
406
497
|
s.stop("✓ KV access validated");
|
|
@@ -432,8 +523,16 @@ async function deploy() {
|
|
|
432
523
|
outro("\n✅ Deployment complete!\n\nDeployed sites:\n" + deployedSubdomains.join("\n"));
|
|
433
524
|
}
|
|
434
525
|
|
|
435
|
-
// Only run
|
|
526
|
+
// Only run when this file is executed directly, not when imported
|
|
436
527
|
if (import.meta.main) {
|
|
528
|
+
const args = Bun.argv.slice(2);
|
|
529
|
+
|
|
530
|
+
// Handle version command
|
|
531
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
532
|
+
console.log(packageJson.version);
|
|
533
|
+
process.exit(0);
|
|
534
|
+
}
|
|
535
|
+
|
|
437
536
|
deploy().catch((error) => {
|
|
438
537
|
console.error("\n❌ Fatal error:", error);
|
|
439
538
|
process.exit(1);
|