star-sdk-cli 0.1.11 → 0.1.12

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 (2) hide show
  1. package/dist/cli.mjs +133 -10
  2. package/package.json +15 -1
package/dist/cli.mjs CHANGED
@@ -89,6 +89,20 @@ function gameOver(finalScore) {
89
89
  }
90
90
  \`\`\`
91
91
 
92
+ ### Lower-is-Better Games (Time, Moves, Golf)
93
+
94
+ For games where lower scores win, set \`sort: 'asc'\` in \`Star.init()\`:
95
+
96
+ \`\`\`javascript
97
+ Star.init({ gameId: '<gameId from .starrc>', leaderboard: { sort: 'asc' } });
98
+
99
+ // Submit the raw value \u2014 do NOT invert the score
100
+ Star.leaderboard.submit(reactionTimeMs);
101
+ Star.leaderboard.show();
102
+ \`\`\`
103
+
104
+ **Do NOT** invert scores to fake ascending order (e.g., \`10000 - score\`). Use \`sort: 'asc'\` instead.
105
+
92
106
  ### Audio (It Just Works)
93
107
 
94
108
  Star.audio handles mobile audio unlocking automatically. Just call \`play()\` - no special handling needed.
@@ -207,6 +221,16 @@ Star.game(ctx => {
207
221
  \`\`\`
208
222
 
209
223
  For detailed API documentation, see the linked files above.
224
+
225
+ ## Examples
226
+
227
+ Complete working games are in the \`examples/\` directory (also published with the npm package):
228
+
229
+ - **click-frenzy** \u2014 5-second click speed game with leaderboard
230
+ - **dodge** \u2014 Avoid falling obstacles, keyboard and touch controls
231
+ - **reaction-time** \u2014 Test your reflexes over 5 rounds, DOM-based (no canvas)
232
+
233
+ Each example is a single HTML file, no build step \u2014 imports from esm.sh.
210
234
  `;
211
235
  var AUDIO_DOCS = `**Installation**
212
236
 
@@ -1309,6 +1333,7 @@ ${colors.bright}Star SDK CLI${colors.reset} v${VERSION}
1309
1333
 
1310
1334
  ${colors.dim}Commands:${colors.reset}
1311
1335
  ${colors.cyan}init <name>${colors.reset} Register a new game
1336
+ ${colors.cyan}deploy [path]${colors.reset} Deploy game to Star hosting
1312
1337
  ${colors.cyan}install [agent]${colors.reset} Install Star SDK docs for AI coding agents
1313
1338
  ${colors.cyan}docs [topic]${colors.reset} Print API documentation (default: all docs)
1314
1339
  ${colors.cyan}whoami${colors.reset} Show current configuration
@@ -1331,6 +1356,10 @@ ${colors.dim}Examples:${colors.reset}
1331
1356
  ${colors.dim}# Register a new game${colors.reset}
1332
1357
  npx star-sdk init "My Awesome Game"
1333
1358
 
1359
+ ${colors.dim}# Deploy to Star hosting${colors.reset}
1360
+ npx star-sdk deploy ${colors.dim}# Deploy current directory${colors.reset}
1361
+ npx star-sdk deploy ./dist ${colors.dim}# Deploy specific directory${colors.reset}
1362
+
1334
1363
  ${colors.dim}# Install for different AI agents${colors.reset}
1335
1364
  npx star-sdk install ${colors.dim}# Claude Code (default)${colors.reset}
1336
1365
  npx star-sdk install codex ${colors.dim}# OpenAI Codex${colors.reset}
@@ -1343,7 +1372,7 @@ ${colors.dim}Examples:${colors.reset}
1343
1372
  npx star-sdk docs audio ${colors.dim}# Just audio API${colors.reset}
1344
1373
  npx star-sdk docs skill ${colors.dim}# Just main skill file${colors.reset}
1345
1374
 
1346
- ${colors.dim}Learn more:${colors.reset} https://buildwithstar.com/docs
1375
+ ${colors.dim}Learn more:${colors.reset} https://buildwithstar.com/docs/sdk
1347
1376
  `);
1348
1377
  }
1349
1378
  function showVersion() {
@@ -1403,7 +1432,8 @@ async function initCommand(name, email) {
1403
1432
  gameId: data.gameId,
1404
1433
  name: data.name,
1405
1434
  email: email?.trim(),
1406
- dashboardUrl: data.dashboardUrl
1435
+ dashboardUrl: data.dashboardUrl,
1436
+ deployKey: data.deployKey
1407
1437
  };
1408
1438
  saveConfig(config);
1409
1439
  log("");
@@ -1415,20 +1445,20 @@ async function initCommand(name, email) {
1415
1445
  log(`${colors.dim}Config saved to${colors.reset} ${colors.bright}.starrc${colors.reset}`);
1416
1446
  log("");
1417
1447
  log(`${colors.dim}Next steps:${colors.reset}`);
1418
- log(` 1. Install the leaderboard package: ${colors.cyan}yarn add star-leaderboard${colors.reset}`);
1419
- log(` 2. Submit scores and show the leaderboard`);
1448
+ log(` 1. Add the SDK: ${colors.cyan}npm install star-sdk${colors.reset}`);
1449
+ log(` 2. Build your game, then deploy: ${colors.cyan}npx star-sdk deploy${colors.reset}`);
1420
1450
  log("");
1421
1451
  log(`${colors.dim}Example:${colors.reset}`);
1422
- log(` ${colors.cyan}import { createLeaderboard } from 'star-leaderboard';${colors.reset}`);
1423
- log(` ${colors.cyan}const leaderboard = createLeaderboard({ gameId: '${data.gameId}' });${colors.reset}`);
1424
- log(` ${colors.cyan}leaderboard.submit(1500);${colors.reset}`);
1425
- log(` ${colors.cyan}leaderboard.show();${colors.reset}`);
1452
+ log(` ${colors.cyan}import Star from 'star-sdk';${colors.reset}`);
1453
+ log(` ${colors.cyan}Star.init({ gameId: '${data.gameId}' });${colors.reset}`);
1454
+ log(` ${colors.cyan}Star.leaderboard.submit(1500);${colors.reset}`);
1455
+ log(` ${colors.cyan}Star.leaderboard.show();${colors.reset}`);
1426
1456
  log("");
1427
1457
  log(`${colors.dim}Using an AI coding agent?${colors.reset}`);
1428
- log(` ${colors.cyan}npx star-sdk install${colors.reset} ${colors.dim}Claude Code, Codex, Cursor, Windsurf, Aider${colors.reset}`);
1458
+ log(` ${colors.cyan}npx star-sdk install${colors.reset} ${colors.dim}Claude Code, Codex, Cursor, Aider${colors.reset}`);
1429
1459
  log("");
1430
1460
  log(`${colors.dim}Documentation:${colors.reset}`);
1431
- log(` ${colors.cyan}https://buildwithstar.com/docs${colors.reset}`);
1461
+ log(` ${colors.cyan}https://buildwithstar.com/docs/sdk/sdk${colors.reset}`);
1432
1462
  log("");
1433
1463
  } catch (err) {
1434
1464
  if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
@@ -1458,8 +1488,98 @@ function whoamiCommand() {
1458
1488
  if (config.dashboardUrl) {
1459
1489
  log(` ${colors.dim}Dashboard:${colors.reset} ${colors.cyan}${config.dashboardUrl}${colors.reset}`);
1460
1490
  }
1491
+ if (config.deployUrl) {
1492
+ log(` ${colors.dim}Live URL:${colors.reset} ${colors.cyan}${config.deployUrl}${colors.reset}`);
1493
+ }
1494
+ if (config.deployKey) {
1495
+ log(` ${colors.dim}Deploy key:${colors.reset} ${colors.dim}${config.deployKey.slice(0, 8)}...${colors.reset}`);
1496
+ }
1461
1497
  log("");
1462
1498
  }
1499
+ async function deployCommand(dirPath) {
1500
+ const config = loadConfig();
1501
+ if (!config) {
1502
+ error('No .starrc found. Run "npx star-sdk init <name>" first.');
1503
+ process.exit(1);
1504
+ }
1505
+ if (!config.deployKey) {
1506
+ error('No deploy key found. Re-run "npx star-sdk init <name>" to get one.');
1507
+ process.exit(1);
1508
+ }
1509
+ const deployDir = dirPath ? path.resolve(dirPath) : process.cwd();
1510
+ if (!fs.existsSync(deployDir)) {
1511
+ error(`Directory not found: ${deployDir}`);
1512
+ process.exit(1);
1513
+ }
1514
+ if (!fs.statSync(deployDir).isDirectory()) {
1515
+ error(`Not a directory: ${deployDir}`);
1516
+ process.exit(1);
1517
+ }
1518
+ const indexPath = path.join(deployDir, "index.html");
1519
+ if (!fs.existsSync(indexPath)) {
1520
+ error(`No index.html found in ${deployDir}`);
1521
+ log("");
1522
+ log("Your game needs an index.html file to deploy.");
1523
+ process.exit(1);
1524
+ }
1525
+ log(`Deploying ${colors.bright}${config.name}${colors.reset} from ${colors.dim}${deployDir}${colors.reset}`);
1526
+ try {
1527
+ const archiver = (await import("archiver")).default;
1528
+ const zipBuffer = await new Promise((resolve2, reject) => {
1529
+ const chunks = [];
1530
+ const archive = archiver("zip", { zlib: { level: 9 } });
1531
+ archive.on("data", (chunk) => chunks.push(chunk));
1532
+ archive.on("end", () => resolve2(Buffer.concat(chunks)));
1533
+ archive.on("error", reject);
1534
+ archive.glob("**/*", {
1535
+ cwd: deployDir,
1536
+ ignore: ["node_modules/**", ".starrc", ".git/**", ".DS_Store"],
1537
+ dot: false
1538
+ });
1539
+ archive.finalize();
1540
+ });
1541
+ log(` ${colors.dim}Uploading ${(zipBuffer.length / 1024).toFixed(1)} KB...${colors.reset}`);
1542
+ const response = await fetch(`${API_BASE}/api/sdk/games/${config.gameId}/deploy`, {
1543
+ method: "POST",
1544
+ headers: {
1545
+ "Content-Type": "application/zip",
1546
+ "x-deploy-key": config.deployKey
1547
+ },
1548
+ body: zipBuffer
1549
+ });
1550
+ if (!response.ok) {
1551
+ const data2 = await response.json().catch(() => ({}));
1552
+ if (response.status === 403) {
1553
+ error(data2.error || 'Invalid deploy key. Re-run "npx star-sdk init" to get a new one.');
1554
+ } else if (response.status === 404) {
1555
+ error("Game not found. It may have been deleted.");
1556
+ } else if (response.status === 413) {
1557
+ error(data2.error || "Upload too large (50MB limit).");
1558
+ } else if (response.status === 429) {
1559
+ error(data2.error || "Rate limit exceeded. Try again later.");
1560
+ } else {
1561
+ error(data2.error || `Deploy failed (HTTP ${response.status})`);
1562
+ }
1563
+ process.exit(1);
1564
+ }
1565
+ const data = await response.json();
1566
+ config.deployUrl = data.url;
1567
+ saveConfig(config);
1568
+ log("");
1569
+ success("Deployed successfully!");
1570
+ log("");
1571
+ log(` ${colors.dim}URL:${colors.reset} ${colors.cyan}${data.url}${colors.reset}`);
1572
+ log(` ${colors.dim}Files:${colors.reset} ${data.files} files, ${data.assets} assets`);
1573
+ log("");
1574
+ } catch (err) {
1575
+ if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
1576
+ error("Could not connect to Star API. Check your internet connection.");
1577
+ } else {
1578
+ error(err.message || "Deploy failed");
1579
+ }
1580
+ process.exit(1);
1581
+ }
1582
+ }
1463
1583
  function transformForStdout(content) {
1464
1584
  return content.replace(/\[(\w+)\.md\]\(\.\/\1\.md\)/g, "$1 (`npx star-sdk docs $1`)").replace(/see (\w+)\.md/g, "run `npx star-sdk docs $1`").replace(
1465
1585
  /For detailed API documentation, see the linked files above\./,
@@ -1670,6 +1790,9 @@ async function main() {
1670
1790
  case "init":
1671
1791
  await initCommand(positional[0], email);
1672
1792
  break;
1793
+ case "deploy":
1794
+ await deployCommand(positional[0]);
1795
+ break;
1673
1796
  case "install": {
1674
1797
  const agent = positional[0] || "claude";
1675
1798
  const scope = flags.project ? "project" : "global";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "star-sdk-cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "CLI tool for Star SDK - register games and manage leaderboards",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,16 @@
18
18
  "build": "tsup",
19
19
  "dev": "tsx src/cli.ts"
20
20
  },
21
+ "license": "MIT",
22
+ "homepage": "https://buildwithstar.com/docs/sdk",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/buildwithstar/star-sdk",
26
+ "directory": "packages/star-sdk-cli"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/buildwithstar/star-sdk/issues"
30
+ },
21
31
  "keywords": [
22
32
  "star",
23
33
  "sdk",
@@ -25,7 +35,11 @@
25
35
  "games",
26
36
  "leaderboard"
27
37
  ],
38
+ "dependencies": {
39
+ "archiver": "^7.0.0"
40
+ },
28
41
  "devDependencies": {
42
+ "@types/archiver": "^6.0.0",
29
43
  "tsup": "^8.0.0",
30
44
  "tsx": "^4.7.0",
31
45
  "typescript": "^5.4.5"