@just-be/deploy 0.3.0 → 0.5.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 (3) hide show
  1. package/README.md +40 -6
  2. package/index.ts +75 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,9 +5,42 @@ 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
+
20
+ ## Configuration
21
+
22
+ The deploy script requires access to:
23
+
24
+ - **KV namespace** for routing rules
25
+ - **R2 bucket** for static file storage
26
+
27
+ ### Environment Variables
28
+
29
+ To use different resources, set these environment variables:
30
+
31
+ ```bash
32
+ export KV_NAMESPACE_ID="your-kv-namespace-id"
33
+ export R2_BUCKET_NAME="your-bucket-name"
34
+ bunx @just-be/deploy
35
+ ```
36
+
37
+ You can find your KV namespace ID and R2 buckets by running:
38
+
39
+ ```bash
40
+ wrangler kv namespace list
41
+ wrangler r2 bucket list
42
+ ```
43
+
11
44
  ## Installation
12
45
 
13
46
  No installation needed! Run directly with `bunx`:
@@ -200,13 +233,14 @@ The package includes a JSON Schema (`deploy.schema.json`) for editor validation
200
233
  - Creates a KV entry with the routing configuration
201
234
  5. **Configures** the wildcard service to route requests for each subdomain
202
235
 
203
- ## Configuration
236
+ ## Wildcard Service Requirements
237
+
238
+ The script works with any wildcard service that has:
204
239
 
205
- The script expects your wildcard service to use:
240
+ - **R2 Bucket**: For storing static files (default: `content-bucket`)
241
+ - **KV Namespace**: For routing rules (default: `6118ae3b937c4883b3c582dfef8a0c05`)
206
242
 
207
- - **R2 Bucket**: `content-bucket`
208
- - **KV Binding**: `ROUTING_RULES`
209
- - **Wrangler Config**: `services/wildcard/wrangler.toml`
243
+ No local `wrangler.toml` file is required - the script accesses Cloudflare resources directly via the Wrangler CLI.
210
244
 
211
245
  ## Validation
212
246
 
package/index.ts CHANGED
@@ -7,6 +7,15 @@
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
10
19
  *
11
20
  * Example deploy.json:
12
21
  * {
@@ -37,6 +46,7 @@ import { readdir, stat, access } from "fs/promises";
37
46
  import { join, relative, resolve } from "path";
38
47
  import { intro, outro, spinner } from "@clack/prompts";
39
48
  import { z } from "zod";
49
+ import packageJson from "./package.json" with { type: "json" };
40
50
  import {
41
51
  StaticConfigSchema,
42
52
  RedirectConfigSchema,
@@ -45,8 +55,8 @@ import {
45
55
  subdomain,
46
56
  } from "@just-be/wildcard";
47
57
 
48
- const BUCKET_NAME = "content-bucket";
49
- const WRANGLER_CONFIG = "services/wildcard/wrangler.toml";
58
+ const BUCKET_NAME = process.env.R2_BUCKET_NAME || "content-bucket";
59
+ const KV_NAMESPACE_ID = process.env.KV_NAMESPACE_ID || "6118ae3b937c4883b3c582dfef8a0c05";
50
60
 
51
61
  /**
52
62
  * Run wrangler command using bunx to ensure it resolves from package dependencies
@@ -172,12 +182,24 @@ async function uploadToR2(localPath: string, r2Key: string): Promise<boolean> {
172
182
  }
173
183
  }
174
184
 
185
+ /**
186
+ * Check if user is authenticated with wrangler
187
+ */
188
+ async function validateWranglerAuth(): Promise<boolean> {
189
+ try {
190
+ await wrangler`whoami`.quiet();
191
+ return true;
192
+ } catch {
193
+ return false;
194
+ }
195
+ }
196
+
175
197
  /**
176
198
  * Validate KV access by attempting to list keys
177
199
  */
178
200
  async function validateKVAccess(): Promise<boolean> {
179
201
  try {
180
- await wrangler`kv key list --binding ROUTING_RULES --config ${WRANGLER_CONFIG}`.quiet();
202
+ await wrangler`kv key list --namespace-id ${KV_NAMESPACE_ID}`.quiet();
181
203
  return true;
182
204
  } catch {
183
205
  return false;
@@ -191,7 +213,7 @@ async function getCurrentBranch(): Promise<string> {
191
213
  try {
192
214
  const result = await $`git rev-parse --abbrev-ref HEAD`.text();
193
215
  return result.trim();
194
- } catch (error) {
216
+ } catch {
195
217
  throw new Error("Failed to get current git branch. Are you in a git repository?");
196
218
  }
197
219
  }
@@ -213,7 +235,7 @@ function sanitizeBranchName(branch: string): string {
213
235
  */
214
236
  async function createKVEntry(subdomain: string, routeConfig: RouteConfig): Promise<void> {
215
237
  const configJson = JSON.stringify(routeConfig);
216
- await wrangler`kv key put --binding ROUTING_RULES ${subdomain} ${configJson} --config ${WRANGLER_CONFIG}`;
238
+ await wrangler`kv key put --namespace-id ${KV_NAMESPACE_ID} ${subdomain} ${configJson}`;
217
239
  }
218
240
 
219
241
  /**
@@ -394,13 +416,50 @@ async function deploy() {
394
416
  console.log(`\nFound ${config.rules.length} rule(s) to deploy`);
395
417
  }
396
418
 
397
- // Validate KV access before starting
419
+ // Check wrangler authentication first
398
420
  const s = spinner();
421
+ s.start("Checking wrangler authentication");
422
+ const isAuthenticated = await validateWranglerAuth();
423
+ if (!isAuthenticated) {
424
+ s.stop("Not authenticated with wrangler");
425
+ console.log("\nAuthenticating with Cloudflare...");
426
+ console.log("This will open a browser window for you to authorize access.\n");
427
+
428
+ try {
429
+ await wrangler`login`;
430
+ console.log("\n✓ Successfully authenticated!");
431
+
432
+ // Verify authentication worked
433
+ s.start("Verifying authentication");
434
+ const isNowAuthenticated = await validateWranglerAuth();
435
+ if (!isNowAuthenticated) {
436
+ s.stop("Error: Authentication verification failed");
437
+ console.error("\nIf you prefer to use an API token instead:");
438
+ console.error(" export CLOUDFLARE_API_TOKEN=your-token");
439
+ process.exit(1);
440
+ }
441
+ s.stop("✓ Authentication verified");
442
+ } catch (error) {
443
+ console.error("\n❌ Authentication failed");
444
+ console.error("\nAlternatively, you can set up an API token:");
445
+ console.error(" export CLOUDFLARE_API_TOKEN=your-token");
446
+ process.exit(1);
447
+ }
448
+ } else {
449
+ s.stop("✓ Wrangler authenticated");
450
+ }
451
+
452
+ // Validate KV access
399
453
  s.start("Validating KV access");
400
454
  const hasKVAccess = await validateKVAccess();
401
455
  if (!hasKVAccess) {
402
456
  s.stop("Error: Cannot access KV namespace");
403
- console.error("Check wrangler configuration and permissions.");
457
+ console.error("\nCheck that you have permission to access the KV namespace.");
458
+ console.error(`KV Namespace ID: ${KV_NAMESPACE_ID}`);
459
+ console.error("\nYou may need to:");
460
+ console.error(" 1. Verify the namespace ID is correct");
461
+ console.error(" 2. Ensure your account has access to this KV namespace");
462
+ console.error(" 3. Check wrangler.toml configuration if using one");
404
463
  process.exit(1);
405
464
  }
406
465
  s.stop("✓ KV access validated");
@@ -432,8 +491,16 @@ async function deploy() {
432
491
  outro("\n✅ Deployment complete!\n\nDeployed sites:\n" + deployedSubdomains.join("\n"));
433
492
  }
434
493
 
435
- // Only run deploy() when this file is executed directly, not when imported
494
+ // Only run when this file is executed directly, not when imported
436
495
  if (import.meta.main) {
496
+ const args = Bun.argv.slice(2);
497
+
498
+ // Handle version command
499
+ if (args[0] === "--version" || args[0] === "-v") {
500
+ console.log(packageJson.version);
501
+ process.exit(0);
502
+ }
503
+
437
504
  deploy().catch((error) => {
438
505
  console.error("\n❌ Fatal error:", error);
439
506
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@just-be/deploy",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Deploy static sites to Cloudflare R2 with subdomain routing",
5
5
  "type": "module",
6
6
  "bin": {