@amirhosseinnateghi/vibed-cli 0.1.6 → 0.1.7

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/index.js CHANGED
@@ -11229,6 +11229,15 @@ function formatReport(result) {
11229
11229
  out2.push(` \u2022 \u2026and ${result.inlineWarnings.length - 12} more`);
11230
11230
  }
11231
11231
  }
11232
+ const usesBrowserStorage = [...result.warnings.map((w) => w.message), ...result.inlineWarnings].some(
11233
+ (m) => /BROWSER_STORAGE|localStorage|sessionStorage|indexedDB/i.test(m)
11234
+ );
11235
+ if (usesBrowserStorage) {
11236
+ out2.push(
11237
+ "",
11238
+ "\u2139 Uses browser storage (blocked in the sandbox). Port it to `window.vibed.storage` \u2014 run `vibed storage` (or the vibed_storage_guide MCP tool) for the local + shared SDK."
11239
+ );
11240
+ }
11232
11241
  return out2.join("\n");
11233
11242
  }
11234
11243
 
@@ -11406,6 +11415,82 @@ async function deleteExperience(client, idOrUrl) {
11406
11415
  return id;
11407
11416
  }
11408
11417
 
11418
+ // src/storageGuide.ts
11419
+ var STORAGE_GUIDE = `# vibed storage \u2014 add persistence to a vibe (\`window.vibed.storage\`)
11420
+
11421
+ A vibe is ONE static sandboxed HTML file with no backend. \`localStorage\`,
11422
+ \`sessionStorage\`, \`indexedDB\`, and cookies are BLOCKED \u2014 they throw in the
11423
+ sandbox (\`vibed check\` warns \`BROWSER_STORAGE\`). For anything you'd persist,
11424
+ use the injected \`window.vibed.storage\` SDK instead. The platform is the
11425
+ backend; you write zero server code.
11426
+
11427
+ ## Two rules that apply to EVERY call
11428
+ 1. Every call returns a Promise that can reject \u2014 always guard it. When the vibe
11429
+ runs OUTSIDE vibed (e.g. a local file, your \`vibed draft\`/\`preview\`), calls
11430
+ reject with \`{ code: "no_host" }\`. The vibe must stay playable standalone, so
11431
+ treat missing storage as "no saved data yet", never a crash.
11432
+ 2. WRITES require the viewer to be signed in. If not, they reject with
11433
+ \`{ code: "unauthenticated" }\` \u2014 catch it and show a gentle "sign in to save"
11434
+ nudge. READS of shared data work for everyone.
11435
+
11436
+ Publishing auto-detects SDK usage and turns storage on for the post \u2014 no flags.
11437
+
11438
+ ## Tier 1 \u2014 \`vibed.storage.local\` (LOCAL: private, per-viewer, per-post)
11439
+ Each viewer gets their own private bucket for THIS post. Nobody else can read it.
11440
+ Use for: this player's high score, their settings, "resume where I left off".
11441
+ \`\`\`js
11442
+ await vibed.storage.local.set("best", 8200);
11443
+ const best = await vibed.storage.local.get("best"); // null if never set
11444
+ await vibed.storage.local.delete("best");
11445
+ \`\`\`
11446
+
11447
+ ## Tier 2 \u2014 \`vibed.storage.shared\` (GLOBAL: one collective store for the whole post)
11448
+ Data every viewer of the post shares \u2014 leaderboards, votes, guestbooks, shared
11449
+ state. Organized into named "collections" (like tables) you invent.
11450
+ \`\`\`js
11451
+ // key/value doc with optimistic concurrency
11452
+ await vibed.storage.shared.set("state", "doc", { phase: "open" }); // \u2192 { value, version, ... }
11453
+ await vibed.storage.shared.set("state", "doc", next, { ifVersion: 3 }); // rejects { code: "conflict" }
11454
+ const doc = await vibed.storage.shared.get("state", "doc"); // null if missing
11455
+ await vibed.storage.shared.delete("state", "doc");
11456
+
11457
+ // append-only list + query (guestbook, bets, submissions)
11458
+ await vibed.storage.shared.append("bets", { pick: "Argentina", stake: 50 });
11459
+ const mine = await vibed.storage.shared.query("bets", { mine: true });
11460
+ const feed = await vibed.storage.shared.query("bets", { sort: "-created", limit: 30 });
11461
+
11462
+ // counter (poll / reactions)
11463
+ const { num } = await vibed.storage.shared.increment("votes", "argentina", 1);
11464
+
11465
+ // leaderboard: submit a score (keep the best), read the top, get MY rank
11466
+ await vibed.storage.shared.submit("leaderboard", { score, keep: "max", meta: { emoji: "\u{1F427}" } });
11467
+ const top = await vibed.storage.shared.query("leaderboard", { sort: "-num", limit: 10 });
11468
+ const rank = await vibed.storage.shared.rank("leaderboard"); // { rank, of, score } | null
11469
+
11470
+ // live updates (polling now): re-renders when the collection changes; returns an unsubscribe fn
11471
+ const off = vibed.storage.shared.subscribe("leaderboard", (r) => render(r.rows), { intervalMs: 4000 });
11472
+ \`\`\`
11473
+
11474
+ ## Who is watching
11475
+ \`\`\`js
11476
+ const me = await vibed.storage.identity(); // { id, signedIn, name? } \u2014 stable per viewer; identify entries
11477
+ const m = await vibed.storage.meta(); // { postId, ... } \u2014 this post's context
11478
+ \`\`\`
11479
+
11480
+ ## Limits (free tier \u2014 design within these)
11481
+ - Each value must be JSON-serializable and under the per-value byte cap
11482
+ (rejects \`{ code: "too_large" }\`); \`invalid\` if it can't be JSON-stringified.
11483
+ - shared collections are for structured game/app state, NOT open chat/DM/messaging.
11484
+
11485
+ ## Porting a project that used browser storage (the \`BROWSER_STORAGE\` warning)
11486
+ 1. Find every \`localStorage\`/\`sessionStorage\`/\`indexedDB\`/cookie use.
11487
+ 2. Per-viewer state (settings, progress, personal best) \u2192 \`vibed.storage.local\`.
11488
+ 3. Anything others should see (scores to compare, shared counters, submissions)
11489
+ \u2192 the matching \`vibed.storage.shared\` primitive above.
11490
+ 4. Make every call \`await\` + \`try/catch\`, with a standalone fallback (no_host).
11491
+ 5. Re-run \`vibed check\` \u2014 the \`BROWSER_STORAGE\` warning should be gone.
11492
+ `;
11493
+
11409
11494
  // src/index.ts
11410
11495
  function parseArgs(argv) {
11411
11496
  const _ = [];
@@ -11438,6 +11523,7 @@ var USAGE = `vibed \u2014 make it vibed
11438
11523
  Usage:
11439
11524
  vibed login Authenticate this machine (opens the browser)
11440
11525
  vibed check [path] Check if a project can be published (no network)
11526
+ vibed storage Print the persistence guide (leaderboards, saves, shared state)
11441
11527
  vibed preview [path] Bundle + open the artifact locally (no publish)
11442
11528
  vibed draft [path] Upload a private, hosted preview link (no publish)
11443
11529
  vibed publish [path] Bundle the project and publish it to vibed
@@ -11685,6 +11771,9 @@ async function main() {
11685
11771
  return cmdWhoami(args);
11686
11772
  case "check":
11687
11773
  return cmdCheck(args);
11774
+ case "storage":
11775
+ console.log(STORAGE_GUIDE);
11776
+ return 0;
11688
11777
  case "preview":
11689
11778
  return cmdPreview(args);
11690
11779
  case "draft":
package/dist/vibed.cjs CHANGED
@@ -11230,6 +11230,15 @@ function formatReport(result) {
11230
11230
  out2.push(` \u2022 \u2026and ${result.inlineWarnings.length - 12} more`);
11231
11231
  }
11232
11232
  }
11233
+ const usesBrowserStorage = [...result.warnings.map((w) => w.message), ...result.inlineWarnings].some(
11234
+ (m) => /BROWSER_STORAGE|localStorage|sessionStorage|indexedDB/i.test(m)
11235
+ );
11236
+ if (usesBrowserStorage) {
11237
+ out2.push(
11238
+ "",
11239
+ "\u2139 Uses browser storage (blocked in the sandbox). Port it to `window.vibed.storage` \u2014 run `vibed storage` (or the vibed_storage_guide MCP tool) for the local + shared SDK."
11240
+ );
11241
+ }
11233
11242
  return out2.join("\n");
11234
11243
  }
11235
11244
 
@@ -11407,6 +11416,82 @@ async function deleteExperience(client, idOrUrl) {
11407
11416
  return id;
11408
11417
  }
11409
11418
 
11419
+ // src/storageGuide.ts
11420
+ var STORAGE_GUIDE = `# vibed storage \u2014 add persistence to a vibe (\`window.vibed.storage\`)
11421
+
11422
+ A vibe is ONE static sandboxed HTML file with no backend. \`localStorage\`,
11423
+ \`sessionStorage\`, \`indexedDB\`, and cookies are BLOCKED \u2014 they throw in the
11424
+ sandbox (\`vibed check\` warns \`BROWSER_STORAGE\`). For anything you'd persist,
11425
+ use the injected \`window.vibed.storage\` SDK instead. The platform is the
11426
+ backend; you write zero server code.
11427
+
11428
+ ## Two rules that apply to EVERY call
11429
+ 1. Every call returns a Promise that can reject \u2014 always guard it. When the vibe
11430
+ runs OUTSIDE vibed (e.g. a local file, your \`vibed draft\`/\`preview\`), calls
11431
+ reject with \`{ code: "no_host" }\`. The vibe must stay playable standalone, so
11432
+ treat missing storage as "no saved data yet", never a crash.
11433
+ 2. WRITES require the viewer to be signed in. If not, they reject with
11434
+ \`{ code: "unauthenticated" }\` \u2014 catch it and show a gentle "sign in to save"
11435
+ nudge. READS of shared data work for everyone.
11436
+
11437
+ Publishing auto-detects SDK usage and turns storage on for the post \u2014 no flags.
11438
+
11439
+ ## Tier 1 \u2014 \`vibed.storage.local\` (LOCAL: private, per-viewer, per-post)
11440
+ Each viewer gets their own private bucket for THIS post. Nobody else can read it.
11441
+ Use for: this player's high score, their settings, "resume where I left off".
11442
+ \`\`\`js
11443
+ await vibed.storage.local.set("best", 8200);
11444
+ const best = await vibed.storage.local.get("best"); // null if never set
11445
+ await vibed.storage.local.delete("best");
11446
+ \`\`\`
11447
+
11448
+ ## Tier 2 \u2014 \`vibed.storage.shared\` (GLOBAL: one collective store for the whole post)
11449
+ Data every viewer of the post shares \u2014 leaderboards, votes, guestbooks, shared
11450
+ state. Organized into named "collections" (like tables) you invent.
11451
+ \`\`\`js
11452
+ // key/value doc with optimistic concurrency
11453
+ await vibed.storage.shared.set("state", "doc", { phase: "open" }); // \u2192 { value, version, ... }
11454
+ await vibed.storage.shared.set("state", "doc", next, { ifVersion: 3 }); // rejects { code: "conflict" }
11455
+ const doc = await vibed.storage.shared.get("state", "doc"); // null if missing
11456
+ await vibed.storage.shared.delete("state", "doc");
11457
+
11458
+ // append-only list + query (guestbook, bets, submissions)
11459
+ await vibed.storage.shared.append("bets", { pick: "Argentina", stake: 50 });
11460
+ const mine = await vibed.storage.shared.query("bets", { mine: true });
11461
+ const feed = await vibed.storage.shared.query("bets", { sort: "-created", limit: 30 });
11462
+
11463
+ // counter (poll / reactions)
11464
+ const { num } = await vibed.storage.shared.increment("votes", "argentina", 1);
11465
+
11466
+ // leaderboard: submit a score (keep the best), read the top, get MY rank
11467
+ await vibed.storage.shared.submit("leaderboard", { score, keep: "max", meta: { emoji: "\u{1F427}" } });
11468
+ const top = await vibed.storage.shared.query("leaderboard", { sort: "-num", limit: 10 });
11469
+ const rank = await vibed.storage.shared.rank("leaderboard"); // { rank, of, score } | null
11470
+
11471
+ // live updates (polling now): re-renders when the collection changes; returns an unsubscribe fn
11472
+ const off = vibed.storage.shared.subscribe("leaderboard", (r) => render(r.rows), { intervalMs: 4000 });
11473
+ \`\`\`
11474
+
11475
+ ## Who is watching
11476
+ \`\`\`js
11477
+ const me = await vibed.storage.identity(); // { id, signedIn, name? } \u2014 stable per viewer; identify entries
11478
+ const m = await vibed.storage.meta(); // { postId, ... } \u2014 this post's context
11479
+ \`\`\`
11480
+
11481
+ ## Limits (free tier \u2014 design within these)
11482
+ - Each value must be JSON-serializable and under the per-value byte cap
11483
+ (rejects \`{ code: "too_large" }\`); \`invalid\` if it can't be JSON-stringified.
11484
+ - shared collections are for structured game/app state, NOT open chat/DM/messaging.
11485
+
11486
+ ## Porting a project that used browser storage (the \`BROWSER_STORAGE\` warning)
11487
+ 1. Find every \`localStorage\`/\`sessionStorage\`/\`indexedDB\`/cookie use.
11488
+ 2. Per-viewer state (settings, progress, personal best) \u2192 \`vibed.storage.local\`.
11489
+ 3. Anything others should see (scores to compare, shared counters, submissions)
11490
+ \u2192 the matching \`vibed.storage.shared\` primitive above.
11491
+ 4. Make every call \`await\` + \`try/catch\`, with a standalone fallback (no_host).
11492
+ 5. Re-run \`vibed check\` \u2014 the \`BROWSER_STORAGE\` warning should be gone.
11493
+ `;
11494
+
11410
11495
  // src/index.ts
11411
11496
  function parseArgs(argv) {
11412
11497
  const _ = [];
@@ -11439,6 +11524,7 @@ var USAGE = `vibed \u2014 make it vibed
11439
11524
  Usage:
11440
11525
  vibed login Authenticate this machine (opens the browser)
11441
11526
  vibed check [path] Check if a project can be published (no network)
11527
+ vibed storage Print the persistence guide (leaderboards, saves, shared state)
11442
11528
  vibed preview [path] Bundle + open the artifact locally (no publish)
11443
11529
  vibed draft [path] Upload a private, hosted preview link (no publish)
11444
11530
  vibed publish [path] Bundle the project and publish it to vibed
@@ -11686,6 +11772,9 @@ async function main() {
11686
11772
  return cmdWhoami(args);
11687
11773
  case "check":
11688
11774
  return cmdCheck(args);
11775
+ case "storage":
11776
+ console.log(STORAGE_GUIDE);
11777
+ return 0;
11689
11778
  case "preview":
11690
11779
  return cmdPreview(args);
11691
11780
  case "draft":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amirhosseinnateghi/vibed-cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "make it vibed — check, bundle, and publish a project to vibed from the terminal",
5
5
  "license": "MIT",
6
6
  "type": "module",