playcademy 0.15.6 → 0.16.1

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
@@ -3976,7 +3976,7 @@ import { join as join12 } from "path";
3976
3976
  // package.json with { type: 'json' }
3977
3977
  var package_default2 = {
3978
3978
  name: "playcademy",
3979
- version: "0.15.5",
3979
+ version: "0.16.0",
3980
3980
  type: "module",
3981
3981
  exports: {
3982
3982
  ".": {
@@ -10625,7 +10625,7 @@ var getStatusCommand = new Command13("status").description("Check your developer
10625
10625
  });
10626
10626
 
10627
10627
  // package.json
10628
- var version2 = "0.15.5";
10628
+ var version2 = "0.16.0";
10629
10629
 
10630
10630
  // src/commands/dev/server.ts
10631
10631
  function setupCleanupHandlers(workspace, getServer) {
@@ -11577,96 +11577,155 @@ import { Command as Command20 } from "commander";
11577
11577
  import { join as join38 } from "path";
11578
11578
  import { confirm as confirm11 } from "@inquirer/prompts";
11579
11579
  import { Miniflare as Miniflare4 } from "miniflare";
11580
- async function runKVClear(options = {}) {
11581
- try {
11580
+ async function runKVClearRemote(options) {
11581
+ const environment = ensureEnvironment(options.env);
11582
+ const client = await requireAuthenticatedClient();
11583
+ const workspace = getWorkspace();
11584
+ const deployedGame = await getDeployedGame(workspace);
11585
+ if (!deployedGame) {
11582
11586
  if (!options.raw && !options.json) {
11587
+ logger.admonition("warning", "Deploy First", [
11588
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
11589
+ ]);
11583
11590
  logger.newLine();
11584
11591
  }
11585
- if (options.remote) {
11586
- if (!options.raw && !options.json) {
11587
- logger.newLine();
11588
- logger.warn("Remote KV operations are not yet implemented");
11589
- logger.newLine();
11590
- logger.admonition("info", "Coming Soon", [
11591
- "Remote KV support is on the roadmap and will be available soon.",
11592
- "For now, KV commands only work with local development storage."
11593
- ]);
11594
- logger.newLine();
11595
- }
11596
- process.exit(1);
11592
+ process.exit(1);
11593
+ }
11594
+ const game = await getGameById(client, deployedGame.gameId, {
11595
+ silent: options.raw || options.json
11596
+ });
11597
+ const keys = await client.dev.games.kv.list(game.slug);
11598
+ const keyCount = keys.length;
11599
+ if (keyCount === 0) {
11600
+ if (options.json) {
11601
+ logger.json({
11602
+ success: true,
11603
+ deleted: 0,
11604
+ message: "No keys to clear",
11605
+ environment
11606
+ });
11607
+ } else if (options.raw) {
11608
+ logger.raw("0");
11609
+ } else {
11610
+ logger.remark(`No keys found in ${environment} KV namespace`);
11611
+ logger.newLine();
11597
11612
  }
11598
- const config = await loadConfig();
11599
- if (!hasKVSetup(config)) {
11600
- if (!options.raw && !options.json) {
11601
- logger.error("KV storage is not configured");
11602
- logger.newLine();
11603
- logger.admonition("tip", "Getting Started", [
11604
- "Run `playcademy kv init` to enable KV storage",
11605
- "",
11606
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11607
- ]);
11608
- logger.newLine();
11609
- }
11610
- process.exit(1);
11613
+ return;
11614
+ }
11615
+ if (!options.force && !options.raw && !options.json) {
11616
+ logger.warn(
11617
+ `This will delete ${keyCount} ${pluralize(keyCount, "key")} from ${environment}`
11618
+ );
11619
+ logger.newLine();
11620
+ const confirmed = await confirm11({
11621
+ message: "Are you sure you want to clear all keys?",
11622
+ default: false
11623
+ });
11624
+ if (!confirmed) {
11625
+ logger.remark("Cancelled");
11626
+ logger.newLine();
11627
+ return;
11611
11628
  }
11612
- const kvDir = join38(getWorkspace(), CLI_DIRECTORIES.KV);
11613
- const mf = new Miniflare4({
11614
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11615
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11616
- kvPersist: kvDir,
11617
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11629
+ logger.newLine();
11630
+ }
11631
+ const deleted = await client.dev.games.kv.clear(game.slug);
11632
+ if (options.json) {
11633
+ logger.json({
11634
+ success: true,
11635
+ deleted,
11636
+ environment
11618
11637
  });
11619
- try {
11620
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11621
- const listResult = await kv.list();
11622
- const keyCount = listResult.keys?.length || 0;
11623
- if (keyCount === 0) {
11624
- if (options.json) {
11625
- logger.json({
11626
- success: true,
11627
- deleted: 0,
11628
- message: "No keys to clear"
11629
- });
11630
- } else if (options.raw) {
11631
- logger.raw("0");
11632
- } else {
11633
- logger.newLine();
11634
- logger.remark("No keys found in KV namespace");
11635
- logger.newLine();
11636
- }
11637
- return;
11638
- }
11639
- if (!options.force && !options.raw && !options.json) {
11640
- logger.warn(`This will delete ${keyCount} ${pluralize(keyCount, "key")}`);
11641
- logger.newLine();
11642
- const confirmed = await confirm11({
11643
- message: "Are you sure you want to clear all keys?",
11644
- default: false
11645
- });
11646
- if (!confirmed) {
11647
- logger.remark("Cancelled");
11648
- logger.newLine();
11649
- return;
11650
- }
11651
- logger.newLine();
11652
- }
11653
- const keys = listResult.keys || [];
11654
- for (const key of keys) {
11655
- await kv.delete(key.name);
11656
- }
11638
+ } else if (options.raw) {
11639
+ logger.raw(deleted.toString());
11640
+ } else {
11641
+ logger.success(`Deleted ${deleted} ${pluralize(deleted, "key")} from ${environment}`);
11642
+ logger.newLine();
11643
+ }
11644
+ }
11645
+ async function runKVClearLocal(options) {
11646
+ const config = await loadConfig();
11647
+ if (!hasKVSetup(config)) {
11648
+ if (!options.raw && !options.json) {
11649
+ logger.error("KV storage is not configured");
11650
+ logger.newLine();
11651
+ logger.admonition("tip", "Getting Started", [
11652
+ "Run `playcademy kv init` to enable KV storage",
11653
+ "",
11654
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11655
+ ]);
11656
+ logger.newLine();
11657
+ }
11658
+ process.exit(1);
11659
+ }
11660
+ const kvDir = join38(getWorkspace(), CLI_DIRECTORIES.KV);
11661
+ const mf = new Miniflare4({
11662
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11663
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11664
+ kvPersist: kvDir,
11665
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11666
+ });
11667
+ try {
11668
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11669
+ const listResult = await kv.list();
11670
+ const keyCount = listResult.keys?.length || 0;
11671
+ if (keyCount === 0) {
11657
11672
  if (options.json) {
11658
11673
  logger.json({
11659
11674
  success: true,
11660
- deleted: keyCount
11675
+ deleted: 0,
11676
+ message: "No keys to clear"
11661
11677
  });
11662
11678
  } else if (options.raw) {
11663
- logger.raw(keyCount.toString());
11679
+ logger.raw("0");
11664
11680
  } else {
11665
- logger.success(`Deleted ${keyCount} ${pluralize(keyCount, "key")}`);
11666
11681
  logger.newLine();
11682
+ logger.remark("No keys found in KV namespace");
11683
+ logger.newLine();
11684
+ }
11685
+ return;
11686
+ }
11687
+ if (!options.force && !options.raw && !options.json) {
11688
+ logger.warn(`This will delete ${keyCount} ${pluralize(keyCount, "key")}`);
11689
+ logger.newLine();
11690
+ const confirmed = await confirm11({
11691
+ message: "Are you sure you want to clear all keys?",
11692
+ default: false
11693
+ });
11694
+ if (!confirmed) {
11695
+ logger.remark("Cancelled");
11696
+ logger.newLine();
11697
+ return;
11667
11698
  }
11668
- } finally {
11669
- await mf.dispose();
11699
+ logger.newLine();
11700
+ }
11701
+ const keys = listResult.keys || [];
11702
+ for (const key of keys) {
11703
+ await kv.delete(key.name);
11704
+ }
11705
+ if (options.json) {
11706
+ logger.json({
11707
+ success: true,
11708
+ deleted: keyCount
11709
+ });
11710
+ } else if (options.raw) {
11711
+ logger.raw(keyCount.toString());
11712
+ } else {
11713
+ logger.success(`Deleted ${keyCount} ${pluralize(keyCount, "key")}`);
11714
+ logger.newLine();
11715
+ }
11716
+ } finally {
11717
+ await mf.dispose();
11718
+ }
11719
+ }
11720
+ async function runKVClear(options = {}) {
11721
+ try {
11722
+ if (!options.raw && !options.json) {
11723
+ logger.newLine();
11724
+ }
11725
+ if (options.remote) {
11726
+ await runKVClearRemote(options);
11727
+ } else {
11728
+ await runKVClearLocal(options);
11670
11729
  }
11671
11730
  } catch (error) {
11672
11731
  if (!options.raw && !options.json) {
@@ -11681,24 +11740,107 @@ async function runKVClear(options = {}) {
11681
11740
 
11682
11741
  // src/commands/kv/delete.ts
11683
11742
  import { join as join39 } from "path";
11743
+ import { confirm as confirm12 } from "@inquirer/prompts";
11684
11744
  import { Miniflare as Miniflare5 } from "miniflare";
11685
- async function runKVDelete(key, options = {}) {
11686
- try {
11745
+ async function runKVDeleteRemote(key, options) {
11746
+ const environment = ensureEnvironment(options.env);
11747
+ const client = await requireAuthenticatedClient();
11748
+ const workspace = getWorkspace();
11749
+ const deployedGame = await getDeployedGame(workspace);
11750
+ if (!deployedGame) {
11687
11751
  if (!options.raw && !options.json) {
11752
+ logger.admonition("warning", "Deploy First", [
11753
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
11754
+ ]);
11688
11755
  logger.newLine();
11689
11756
  }
11690
- if (options.remote) {
11691
- if (!options.raw && !options.json) {
11692
- logger.newLine();
11693
- logger.warn("Remote KV operations are not yet implemented");
11694
- logger.newLine();
11695
- logger.admonition("info", "Coming Soon", [
11696
- "Remote KV support is on the roadmap and will be available soon.",
11697
- "For now, KV commands only work with local development storage."
11698
- ]);
11757
+ process.exit(1);
11758
+ }
11759
+ const game = await getGameById(client, deployedGame.gameId, {
11760
+ silent: options.raw || options.json
11761
+ });
11762
+ if (!options.force && !options.raw && !options.json) {
11763
+ const confirmed = await confirm12({
11764
+ message: `Delete key "${key}" from ${environment}?`,
11765
+ default: false
11766
+ });
11767
+ if (!confirmed) {
11768
+ logger.remark("Cancelled");
11769
+ logger.newLine();
11770
+ return;
11771
+ }
11772
+ logger.newLine();
11773
+ }
11774
+ await client.dev.games.kv.delete(game.slug, key);
11775
+ if (options.json) {
11776
+ logger.json({
11777
+ key,
11778
+ success: true,
11779
+ environment
11780
+ });
11781
+ } else if (options.raw) {
11782
+ logger.raw("ok");
11783
+ } else {
11784
+ logger.success(`Deleted key: ${key} from ${environment}`);
11785
+ logger.newLine();
11786
+ }
11787
+ }
11788
+ async function runKVDeleteLocal(key, options) {
11789
+ const config = await loadConfig();
11790
+ if (!hasKVSetup(config)) {
11791
+ if (!options.raw && !options.json) {
11792
+ logger.error("KV storage is not configured");
11793
+ logger.newLine();
11794
+ logger.admonition("tip", "Getting Started", [
11795
+ "Run `playcademy kv init` to enable KV storage",
11796
+ "",
11797
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11798
+ ]);
11799
+ logger.newLine();
11800
+ }
11801
+ process.exit(1);
11802
+ }
11803
+ const kvDir = join39(getWorkspace(), CLI_DIRECTORIES.KV);
11804
+ const mf = new Miniflare5({
11805
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11806
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11807
+ kvPersist: kvDir,
11808
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11809
+ });
11810
+ try {
11811
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11812
+ if (!options.force && !options.raw && !options.json) {
11813
+ const confirmed = await confirm12({
11814
+ message: `Delete key "${key}"?`,
11815
+ default: false
11816
+ });
11817
+ if (!confirmed) {
11818
+ logger.remark("Cancelled");
11699
11819
  logger.newLine();
11820
+ return;
11700
11821
  }
11701
- process.exit(1);
11822
+ logger.newLine();
11823
+ }
11824
+ await kv.delete(key);
11825
+ if (options.json) {
11826
+ logger.json({
11827
+ key,
11828
+ success: true
11829
+ });
11830
+ } else if (options.raw) {
11831
+ logger.raw("ok");
11832
+ } else {
11833
+ logger.success(`Deleted key: ${key}`);
11834
+ logger.newLine();
11835
+ }
11836
+ } finally {
11837
+ await mf.dispose();
11838
+ }
11839
+ }
11840
+ async function runKVDelete(key, options = {}) {
11841
+ try {
11842
+ if (!options.raw && !options.json) {
11843
+ logger.newLine();
11702
11844
  }
11703
11845
  if (!key) {
11704
11846
  if (!options.raw && !options.json) {
@@ -11709,43 +11851,10 @@ async function runKVDelete(key, options = {}) {
11709
11851
  }
11710
11852
  process.exit(1);
11711
11853
  }
11712
- const config = await loadConfig();
11713
- if (!hasKVSetup(config)) {
11714
- if (!options.raw && !options.json) {
11715
- logger.error("KV storage is not configured");
11716
- logger.newLine();
11717
- logger.admonition("tip", "Getting Started", [
11718
- "Run `playcademy kv init` to enable KV storage",
11719
- "",
11720
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11721
- ]);
11722
- logger.newLine();
11723
- }
11724
- process.exit(1);
11725
- }
11726
- const kvDir = join39(getWorkspace(), CLI_DIRECTORIES.KV);
11727
- const mf = new Miniflare5({
11728
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11729
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11730
- kvPersist: kvDir,
11731
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11732
- });
11733
- try {
11734
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11735
- await kv.delete(key);
11736
- if (options.json) {
11737
- logger.json({
11738
- key,
11739
- success: true
11740
- });
11741
- } else if (options.raw) {
11742
- logger.raw("ok");
11743
- } else {
11744
- logger.success(`Deleted key: ${key}`);
11745
- logger.newLine();
11746
- }
11747
- } finally {
11748
- await mf.dispose();
11854
+ if (options.remote) {
11855
+ await runKVDeleteRemote(key, options);
11856
+ } else {
11857
+ await runKVDeleteLocal(key, options);
11749
11858
  }
11750
11859
  } catch (error) {
11751
11860
  if (!options.raw && !options.json) {
@@ -11761,98 +11870,154 @@ async function runKVDelete(key, options = {}) {
11761
11870
  // src/commands/kv/get.ts
11762
11871
  import { join as join40 } from "path";
11763
11872
  import { Miniflare as Miniflare6 } from "miniflare";
11764
- async function runKVGet(key, options = {}) {
11765
- try {
11873
+ async function runKVGetRemote(key, options) {
11874
+ const environment = ensureEnvironment(options.env);
11875
+ const client = await requireAuthenticatedClient();
11876
+ const workspace = getWorkspace();
11877
+ const deployedGame = await getDeployedGame(workspace);
11878
+ if (!deployedGame) {
11766
11879
  if (!options.raw && !options.json) {
11880
+ logger.admonition("warning", "Deploy First", [
11881
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
11882
+ ]);
11767
11883
  logger.newLine();
11768
11884
  }
11769
- if (options.remote) {
11770
- if (!options.raw && !options.json) {
11771
- logger.newLine();
11772
- logger.warn("Remote KV operations are not yet implemented");
11773
- logger.newLine();
11774
- logger.admonition("info", "Coming Soon", [
11775
- "Remote KV support is on the roadmap and will be available soon.",
11776
- "For now, KV commands only work with local development storage."
11777
- ]);
11778
- logger.newLine();
11779
- }
11780
- process.exit(1);
11781
- }
11782
- if (!key) {
11783
- if (!options.raw && !options.json) {
11784
- logger.error("Key is required");
11785
- logger.newLine();
11786
- logger.admonition("tip", "Usage", ["`playcademy kv get <key>`"]);
11787
- logger.newLine();
11788
- }
11789
- process.exit(1);
11885
+ process.exit(1);
11886
+ }
11887
+ const game = await getGameById(client, deployedGame.gameId, {
11888
+ silent: options.raw || options.json
11889
+ });
11890
+ const value = await client.dev.games.kv.get(game.slug, key);
11891
+ if (value === null) {
11892
+ if (!options.raw && !options.json) {
11893
+ logger.warn(`Key '${key}' not found in ${environment}`);
11894
+ logger.newLine();
11895
+ logger.admonition("tip", "Hint", [
11896
+ "Use `playcademy kv list --remote` to see all available keys"
11897
+ ]);
11898
+ logger.newLine();
11790
11899
  }
11791
- const config = await loadConfig();
11792
- if (!hasKVSetup(config)) {
11900
+ process.exit(1);
11901
+ }
11902
+ let parsedValue;
11903
+ let isJson = false;
11904
+ try {
11905
+ parsedValue = JSON.parse(value);
11906
+ isJson = true;
11907
+ } catch {
11908
+ parsedValue = value;
11909
+ }
11910
+ if (options.json) {
11911
+ if (isJson) {
11912
+ logger.json(parsedValue);
11913
+ } else {
11914
+ logger.json(value);
11915
+ }
11916
+ return;
11917
+ }
11918
+ if (options.raw) {
11919
+ logger.raw(value);
11920
+ return;
11921
+ }
11922
+ logger.data("Key", key, 1);
11923
+ if (isJson) {
11924
+ logger.newLine();
11925
+ logger.data("Value", "", 1);
11926
+ logger.newLine();
11927
+ logger.json(parsedValue, 2);
11928
+ } else {
11929
+ logger.data("Value", value, 1);
11930
+ }
11931
+ logger.newLine();
11932
+ }
11933
+ async function runKVGetLocal(key, options) {
11934
+ const config = await loadConfig();
11935
+ if (!hasKVSetup(config)) {
11936
+ if (!options.raw && !options.json) {
11937
+ logger.error("KV storage is not configured");
11938
+ logger.newLine();
11939
+ logger.admonition("tip", "Getting Started", [
11940
+ "Run `playcademy kv init` to enable KV storage",
11941
+ "",
11942
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11943
+ ]);
11944
+ logger.newLine();
11945
+ }
11946
+ process.exit(1);
11947
+ }
11948
+ const kvDir = join40(getWorkspace(), CLI_DIRECTORIES.KV);
11949
+ const mf = new Miniflare6({
11950
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11951
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11952
+ kvPersist: kvDir,
11953
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11954
+ });
11955
+ try {
11956
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11957
+ const value = await kv.get(key, "text");
11958
+ if (value === null) {
11793
11959
  if (!options.raw && !options.json) {
11794
- logger.error("KV storage is not configured");
11960
+ logger.warn(`Key '${key}' not found`);
11795
11961
  logger.newLine();
11796
- logger.admonition("tip", "Getting Started", [
11797
- "Run `playcademy kv init` to enable KV storage",
11798
- "",
11799
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11962
+ logger.admonition("tip", "Hint", [
11963
+ "Use `playcademy kv list` to see all available keys"
11800
11964
  ]);
11801
11965
  logger.newLine();
11802
11966
  }
11803
11967
  process.exit(1);
11804
11968
  }
11805
- const kvDir = join40(getWorkspace(), CLI_DIRECTORIES.KV);
11806
- const mf = new Miniflare6({
11807
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11808
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11809
- kvPersist: kvDir,
11810
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11811
- });
11969
+ let parsedValue;
11970
+ let isJson = false;
11812
11971
  try {
11813
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11814
- const value = await kv.get(key, "text");
11815
- if (value === null) {
11816
- if (!options.raw && !options.json) {
11817
- logger.warn(`Key '${key}' not found`);
11818
- logger.newLine();
11819
- logger.admonition("tip", "Hint", [
11820
- "Use `playcademy kv list` to see all available keys"
11821
- ]);
11822
- logger.newLine();
11823
- }
11824
- process.exit(1);
11825
- }
11826
- let parsedValue;
11827
- let isJson = false;
11828
- try {
11829
- parsedValue = JSON.parse(value);
11830
- isJson = true;
11831
- } catch {
11832
- parsedValue = value;
11833
- }
11834
- if (options.json) {
11835
- if (isJson) {
11836
- logger.json(parsedValue);
11837
- } else {
11838
- logger.json(value);
11839
- }
11840
- return;
11841
- }
11842
- if (options.raw) {
11843
- logger.raw(value);
11844
- return;
11845
- }
11846
- logger.success(`Key: ${key}`);
11847
- logger.newLine();
11972
+ parsedValue = JSON.parse(value);
11973
+ isJson = true;
11974
+ } catch {
11975
+ parsedValue = value;
11976
+ }
11977
+ if (options.json) {
11848
11978
  if (isJson) {
11849
- logger.json(parsedValue, 1);
11979
+ logger.json(parsedValue);
11850
11980
  } else {
11851
- logger.data("Value", value, 1);
11981
+ logger.json(value);
11852
11982
  }
11983
+ return;
11984
+ }
11985
+ if (options.raw) {
11986
+ logger.raw(value);
11987
+ return;
11988
+ }
11989
+ logger.data("Key", key, 1);
11990
+ if (isJson) {
11853
11991
  logger.newLine();
11854
- } finally {
11855
- await mf.dispose();
11992
+ logger.data("Value", "", 1);
11993
+ logger.newLine();
11994
+ logger.json(parsedValue, 2);
11995
+ } else {
11996
+ logger.data("Value", value, 1);
11997
+ }
11998
+ logger.newLine();
11999
+ } finally {
12000
+ await mf.dispose();
12001
+ }
12002
+ }
12003
+ async function runKVGet(key, options = {}) {
12004
+ try {
12005
+ if (!options.raw && !options.json) {
12006
+ logger.newLine();
12007
+ }
12008
+ if (!key) {
12009
+ if (!options.raw && !options.json) {
12010
+ logger.error("Key is required");
12011
+ logger.newLine();
12012
+ logger.admonition("tip", "Usage", ["`playcademy kv get <key>`"]);
12013
+ logger.newLine();
12014
+ }
12015
+ process.exit(1);
12016
+ }
12017
+ if (options.remote) {
12018
+ await runKVGetRemote(key, options);
12019
+ } else {
12020
+ await runKVGetLocal(key, options);
11856
12021
  }
11857
12022
  } catch (error) {
11858
12023
  if (!options.raw && !options.json) {
@@ -11935,24 +12100,192 @@ async function runKVInit() {
11935
12100
  // src/commands/kv/inspect.ts
11936
12101
  import { join as join41 } from "path";
11937
12102
  import { Miniflare as Miniflare7 } from "miniflare";
11938
- async function runKVInspect(key, options = {}) {
12103
+ async function runKVInspectRemote(key, options) {
12104
+ const environment = ensureEnvironment(options.env);
12105
+ const client = await requireAuthenticatedClient();
12106
+ const workspace = getWorkspace();
12107
+ const deployedGame = await getDeployedGame(workspace);
12108
+ if (!deployedGame) {
12109
+ if (!options.raw && !options.json) {
12110
+ logger.admonition("warning", "Deploy First", [
12111
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
12112
+ ]);
12113
+ logger.newLine();
12114
+ }
12115
+ process.exit(1);
12116
+ }
12117
+ const game = await getGameById(client, deployedGame.gameId, {
12118
+ silent: options.raw || options.json
12119
+ });
12120
+ const [value, metadata] = await Promise.all([
12121
+ client.dev.games.kv.get(game.slug, key),
12122
+ client.dev.games.kv.inspect(game.slug, key)
12123
+ ]);
12124
+ if (value === null) {
12125
+ const result2 = {
12126
+ key,
12127
+ exists: false
12128
+ };
12129
+ if (options.json) {
12130
+ logger.json(result2);
12131
+ } else if (!options.raw) {
12132
+ logger.warn(`Key '${key}' not found in ${environment}`);
12133
+ logger.newLine();
12134
+ logger.admonition("tip", "Hint", [
12135
+ "Use `playcademy kv list --remote` to see all available keys"
12136
+ ]);
12137
+ logger.newLine();
12138
+ }
12139
+ process.exit(1);
12140
+ }
12141
+ const size = new Blob([value]).size;
12142
+ let parsedValue;
12143
+ let valueType = "string";
11939
12144
  try {
12145
+ parsedValue = JSON.parse(value);
12146
+ valueType = "json";
12147
+ } catch {
12148
+ parsedValue = value;
12149
+ }
12150
+ const result = {
12151
+ key,
12152
+ exists: true,
12153
+ size,
12154
+ value: parsedValue,
12155
+ valueType,
12156
+ customMetadata: metadata?.metadata
12157
+ };
12158
+ if (options.json) {
12159
+ logger.json(result);
12160
+ } else if (options.raw) {
12161
+ logger.raw(size.toString());
12162
+ } else {
12163
+ logger.data("Key", key, 1);
12164
+ const sizeKB = (size / 1024).toFixed(2);
12165
+ const sizeDisplay = size >= 1024 ? `${sizeKB} KB` : `${size} bytes`;
12166
+ logger.data("Size", sizeDisplay, 1);
12167
+ logger.data("Type", valueType === "json" ? "JSON" : "String", 1);
12168
+ logger.newLine();
12169
+ logger.data("Environment", environment, 1);
12170
+ if (result.customMetadata && Object.keys(result.customMetadata).length > 0) {
12171
+ logger.newLine();
12172
+ logger.data("Custom Metadata:", "", 1);
12173
+ logger.json(result.customMetadata, 2);
12174
+ }
12175
+ logger.newLine();
12176
+ logger.data("Value", "", 1);
12177
+ logger.newLine();
12178
+ if (valueType === "json") {
12179
+ logger.json(parsedValue, 2);
12180
+ } else {
12181
+ const lines = value.split("\n");
12182
+ const maxLines = 5;
12183
+ const preview = lines.slice(0, maxLines);
12184
+ for (const line of preview) {
12185
+ logger.raw(line, 2);
12186
+ }
12187
+ if (lines.length > maxLines) {
12188
+ logger.raw(`... (${lines.length - maxLines} more lines)`, 2);
12189
+ }
12190
+ }
12191
+ logger.newLine();
12192
+ }
12193
+ }
12194
+ async function runKVInspectLocal(key, options) {
12195
+ const config = await loadConfig();
12196
+ if (!hasKVSetup(config)) {
11940
12197
  if (!options.raw && !options.json) {
12198
+ logger.error("KV storage is not configured");
12199
+ logger.newLine();
12200
+ logger.admonition("tip", "Getting Started", [
12201
+ "Run `playcademy kv init` to enable KV storage",
12202
+ "",
12203
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12204
+ ]);
11941
12205
  logger.newLine();
11942
12206
  }
11943
- if (options.remote) {
11944
- if (!options.raw && !options.json) {
11945
- logger.newLine();
11946
- logger.warn("Remote KV operations are not yet implemented");
12207
+ process.exit(1);
12208
+ }
12209
+ const kvDir = join41(getWorkspace(), CLI_DIRECTORIES.KV);
12210
+ const mf = new Miniflare7({
12211
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12212
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12213
+ kvPersist: kvDir,
12214
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12215
+ });
12216
+ try {
12217
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12218
+ const value = await kv.get(key, "text");
12219
+ if (value === null) {
12220
+ const metadata2 = {
12221
+ key,
12222
+ exists: false
12223
+ };
12224
+ if (options.json) {
12225
+ logger.json(metadata2);
12226
+ } else if (!options.raw) {
12227
+ logger.warn(`Key '${key}' not found`);
11947
12228
  logger.newLine();
11948
- logger.admonition("info", "Coming Soon", [
11949
- "Remote KV support is on the roadmap and will be available soon.",
11950
- "For now, KV commands only work with local development storage."
12229
+ logger.admonition("tip", "Hint", [
12230
+ "Use `playcademy kv list` to see all available keys"
11951
12231
  ]);
11952
12232
  logger.newLine();
11953
12233
  }
11954
12234
  process.exit(1);
11955
12235
  }
12236
+ const size = new Blob([value]).size;
12237
+ let parsedValue;
12238
+ let valueType = "string";
12239
+ try {
12240
+ parsedValue = JSON.parse(value);
12241
+ valueType = "json";
12242
+ } catch {
12243
+ parsedValue = value;
12244
+ }
12245
+ const metadata = {
12246
+ key,
12247
+ exists: true,
12248
+ size,
12249
+ value: parsedValue,
12250
+ valueType
12251
+ };
12252
+ if (options.json) {
12253
+ logger.json(metadata);
12254
+ } else if (options.raw) {
12255
+ logger.raw(size.toString());
12256
+ } else {
12257
+ logger.data("Key", key, 1);
12258
+ const sizeKB = (size / 1024).toFixed(2);
12259
+ const sizeDisplay = size >= 1024 ? `${sizeKB} KB` : `${size} bytes`;
12260
+ logger.data("Size", sizeDisplay, 1);
12261
+ logger.data("Type", valueType === "json" ? "JSON" : "String", 1);
12262
+ logger.newLine();
12263
+ logger.data("Value", "", 1);
12264
+ logger.newLine();
12265
+ if (valueType === "json") {
12266
+ logger.json(parsedValue, 2);
12267
+ } else {
12268
+ const lines = value.split("\n");
12269
+ const maxLines = 5;
12270
+ const preview = lines.slice(0, maxLines);
12271
+ for (const line of preview) {
12272
+ logger.raw(line, 2);
12273
+ }
12274
+ if (lines.length > maxLines) {
12275
+ logger.raw(`... (${lines.length - maxLines} more lines)`, 2);
12276
+ }
12277
+ }
12278
+ logger.newLine();
12279
+ }
12280
+ } finally {
12281
+ await mf.dispose();
12282
+ }
12283
+ }
12284
+ async function runKVInspect(key, options = {}) {
12285
+ try {
12286
+ if (!options.raw && !options.json) {
12287
+ logger.newLine();
12288
+ }
11956
12289
  if (!key) {
11957
12290
  if (!options.raw && !options.json) {
11958
12291
  logger.error("Key is required");
@@ -11962,93 +12295,10 @@ async function runKVInspect(key, options = {}) {
11962
12295
  }
11963
12296
  process.exit(1);
11964
12297
  }
11965
- const config = await loadConfig();
11966
- if (!hasKVSetup(config)) {
11967
- if (!options.raw && !options.json) {
11968
- logger.error("KV storage is not configured");
11969
- logger.newLine();
11970
- logger.admonition("tip", "Getting Started", [
11971
- "Run `playcademy kv init` to enable KV storage",
11972
- "",
11973
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
11974
- ]);
11975
- logger.newLine();
11976
- }
11977
- process.exit(1);
11978
- }
11979
- const kvDir = join41(getWorkspace(), CLI_DIRECTORIES.KV);
11980
- const mf = new Miniflare7({
11981
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11982
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
11983
- kvPersist: kvDir,
11984
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11985
- });
11986
- try {
11987
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
11988
- const value = await kv.get(key, "text");
11989
- if (value === null) {
11990
- const metadata2 = {
11991
- key,
11992
- exists: false
11993
- };
11994
- if (options.json) {
11995
- logger.json(metadata2);
11996
- } else if (!options.raw) {
11997
- logger.warn(`Key '${key}' not found`);
11998
- logger.newLine();
11999
- logger.admonition("tip", "Hint", [
12000
- "Use `playcademy kv list` to see all available keys"
12001
- ]);
12002
- logger.newLine();
12003
- }
12004
- process.exit(1);
12005
- }
12006
- const size = new Blob([value]).size;
12007
- let parsedValue;
12008
- let valueType = "string";
12009
- try {
12010
- parsedValue = JSON.parse(value);
12011
- valueType = "json";
12012
- } catch {
12013
- parsedValue = value;
12014
- }
12015
- const metadata = {
12016
- key,
12017
- exists: true,
12018
- size,
12019
- value: parsedValue,
12020
- valueType
12021
- };
12022
- if (options.json) {
12023
- logger.json(metadata);
12024
- } else if (options.raw) {
12025
- logger.raw(size.toString());
12026
- } else {
12027
- logger.success(`Key: ${key}`);
12028
- logger.newLine();
12029
- const sizeKB = (size / 1024).toFixed(2);
12030
- const sizeDisplay = size >= 1024 ? `${sizeKB} KB` : `${size} bytes`;
12031
- logger.data("Size", sizeDisplay, 1);
12032
- logger.data("Type", valueType === "json" ? "JSON" : "String", 1);
12033
- logger.newLine();
12034
- logger.data("Value", "", 1);
12035
- if (valueType === "json") {
12036
- logger.json(parsedValue, 2);
12037
- } else {
12038
- const lines = value.split("\n");
12039
- const maxLines = 5;
12040
- const preview = lines.slice(0, maxLines);
12041
- for (const line of preview) {
12042
- logger.dim(line, 2);
12043
- }
12044
- if (lines.length > maxLines) {
12045
- logger.dim(`... (${lines.length - maxLines} more lines)`, 2);
12046
- }
12047
- }
12048
- logger.newLine();
12049
- }
12050
- } finally {
12051
- await mf.dispose();
12298
+ if (options.remote) {
12299
+ await runKVInspectRemote(key, options);
12300
+ } else {
12301
+ await runKVInspectLocal(key, options);
12052
12302
  }
12053
12303
  } catch (error) {
12054
12304
  if (!options.raw && !options.json) {
@@ -12064,71 +12314,112 @@ async function runKVInspect(key, options = {}) {
12064
12314
  // src/commands/kv/list.ts
12065
12315
  import { join as join42 } from "path";
12066
12316
  import { Miniflare as Miniflare8 } from "miniflare";
12067
- async function runKVList(options = {}) {
12068
- try {
12317
+ async function runKVListRemote(options) {
12318
+ const environment = ensureEnvironment(options.env);
12319
+ const client = await requireAuthenticatedClient();
12320
+ const workspace = getWorkspace();
12321
+ const deployedGame = await getDeployedGame(workspace);
12322
+ if (!deployedGame) {
12069
12323
  if (!options.raw && !options.json) {
12324
+ logger.admonition("warning", "Deploy First", [
12325
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
12326
+ ]);
12070
12327
  logger.newLine();
12071
12328
  }
12072
- if (options.remote) {
12073
- if (!options.raw && !options.json) {
12074
- logger.newLine();
12075
- logger.warn("Remote KV operations are not yet implemented");
12076
- logger.newLine();
12077
- logger.admonition("info", "Coming Soon", [
12078
- "Remote KV support is on the roadmap and will be available soon.",
12079
- "For now, KV commands only work with local development storage."
12080
- ]);
12081
- logger.newLine();
12082
- }
12083
- process.exit(1);
12329
+ process.exit(1);
12330
+ }
12331
+ const game = await getGameById(client, deployedGame.gameId, {
12332
+ silent: options.raw || options.json
12333
+ });
12334
+ const keys = await client.dev.games.kv.list(game.slug, options.prefix);
12335
+ if (options.json) {
12336
+ logger.json(keys);
12337
+ return;
12338
+ }
12339
+ if (options.raw) {
12340
+ for (const key of keys) {
12341
+ logger.raw(key.name);
12084
12342
  }
12085
- const config = await loadConfig();
12086
- if (!hasKVSetup(config)) {
12087
- if (!options.raw && !options.json) {
12088
- logger.error("KV storage is not configured");
12089
- logger.newLine();
12090
- logger.admonition("tip", "Getting Started", [
12091
- "Run `playcademy kv init` to enable KV storage",
12092
- "",
12093
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12094
- ]);
12095
- logger.newLine();
12096
- }
12097
- process.exit(1);
12343
+ return;
12344
+ }
12345
+ if (keys.length === 0) {
12346
+ logger.remark("No keys found");
12347
+ if (options.prefix) {
12348
+ logger.newLine();
12349
+ logger.data("Prefix", options.prefix, 1);
12098
12350
  }
12099
- const kvDir = join42(getWorkspace(), CLI_DIRECTORIES.KV);
12100
- const mf = new Miniflare8({
12101
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12102
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12103
- kvPersist: kvDir,
12104
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12105
- });
12106
- try {
12107
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12108
- const listResult = await kv.list();
12109
- const keyNames = listResult.keys?.map((k) => k.name) || [];
12110
- if (options.json) {
12111
- logger.json(keyNames);
12112
- return;
12113
- }
12114
- if (options.raw) {
12115
- for (const keyName of keyNames) {
12116
- logger.raw(keyName);
12117
- }
12118
- return;
12351
+ logger.newLine();
12352
+ return;
12353
+ }
12354
+ logger.success(`Found ${keys.length} ${pluralize(keys.length, "key")} in ${environment}`);
12355
+ if (options.prefix) {
12356
+ logger.data("Prefix", options.prefix, 1);
12357
+ }
12358
+ logger.newLine();
12359
+ for (const key of keys) {
12360
+ logger.bold(key.name, 1);
12361
+ }
12362
+ logger.newLine();
12363
+ }
12364
+ async function runKVListLocal(options) {
12365
+ const config = await loadConfig();
12366
+ if (!hasKVSetup(config)) {
12367
+ if (!options.raw && !options.json) {
12368
+ logger.error("KV storage is not configured");
12369
+ logger.newLine();
12370
+ logger.admonition("tip", "Getting Started", [
12371
+ "Run `playcademy kv init` to enable KV storage",
12372
+ "",
12373
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12374
+ ]);
12375
+ logger.newLine();
12376
+ }
12377
+ process.exit(1);
12378
+ }
12379
+ const kvDir = join42(getWorkspace(), CLI_DIRECTORIES.KV);
12380
+ const mf = new Miniflare8({
12381
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12382
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12383
+ kvPersist: kvDir,
12384
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12385
+ });
12386
+ try {
12387
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12388
+ const listResult = await kv.list({ prefix: options.prefix });
12389
+ const keyNames = listResult.keys?.map((k) => k.name) || [];
12390
+ if (options.json) {
12391
+ logger.json(keyNames);
12392
+ return;
12393
+ }
12394
+ if (options.raw) {
12395
+ for (const keyName of keyNames) {
12396
+ logger.raw(keyName);
12119
12397
  }
12120
- if (keyNames.length === 0) {
12121
- logger.remark("No keys found in KV namespace");
12122
- } else {
12123
- logger.success(`Found ${keyNames.length} ${pluralize(keyNames.length, "key")}`);
12124
- logger.newLine();
12125
- for (const keyName of keyNames) {
12126
- logger.bold(keyName, 1);
12127
- }
12398
+ return;
12399
+ }
12400
+ if (keyNames.length === 0) {
12401
+ logger.remark("No keys found in KV namespace");
12402
+ } else {
12403
+ logger.success(`Found ${keyNames.length} ${pluralize(keyNames.length, "key")}`);
12404
+ logger.newLine();
12405
+ for (const keyName of keyNames) {
12406
+ logger.bold(keyName, 1);
12128
12407
  }
12408
+ }
12409
+ logger.newLine();
12410
+ } finally {
12411
+ await mf.dispose();
12412
+ }
12413
+ }
12414
+ async function runKVList(options = {}) {
12415
+ try {
12416
+ if (!options.raw && !options.json) {
12129
12417
  logger.newLine();
12130
- } finally {
12131
- await mf.dispose();
12418
+ }
12419
+ if (options.remote) {
12420
+ await runKVListRemote(options);
12421
+ } else {
12422
+ await runKVListLocal(options);
12132
12423
  }
12133
12424
  } catch (error) {
12134
12425
  if (!options.raw && !options.json) {
@@ -12144,25 +12435,196 @@ async function runKVList(options = {}) {
12144
12435
  // src/commands/kv/seed.ts
12145
12436
  init_file_loader();
12146
12437
  import { join as join43 } from "path";
12147
- import { confirm as confirm12 } from "@inquirer/prompts";
12438
+ import { confirm as confirm13 } from "@inquirer/prompts";
12439
+ import { underline as underline5 } from "colorette";
12148
12440
  import { Miniflare as Miniflare9 } from "miniflare";
12149
- async function runKVSeed(seedFile, options = {}) {
12150
- try {
12441
+ async function runKVSeedRemote(seedFile, options) {
12442
+ const environment = ensureEnvironment(options.env);
12443
+ const client = await requireAuthenticatedClient();
12444
+ const workspace = getWorkspace();
12445
+ const deployedGame = await getDeployedGame(workspace);
12446
+ if (!deployedGame) {
12151
12447
  if (!options.raw && !options.json) {
12448
+ logger.admonition("warning", "Deploy First", [
12449
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
12450
+ ]);
12152
12451
  logger.newLine();
12153
12452
  }
12154
- if (options.remote) {
12155
- if (!options.raw && !options.json) {
12156
- logger.newLine();
12157
- logger.warn("Remote KV operations are not yet implemented");
12453
+ process.exit(1);
12454
+ }
12455
+ const seedData = await loadFile(seedFile, {
12456
+ cwd: workspace,
12457
+ parseJson: true
12458
+ });
12459
+ if (!seedData) {
12460
+ if (!options.raw && !options.json) {
12461
+ logger.error(`Seed file not found: ${seedFile}`);
12462
+ logger.newLine();
12463
+ }
12464
+ process.exit(1);
12465
+ }
12466
+ if (typeof seedData !== "object" || seedData === null || Array.isArray(seedData)) {
12467
+ if (!options.raw && !options.json) {
12468
+ logger.error("Seed file must contain a JSON object");
12469
+ logger.newLine();
12470
+ }
12471
+ process.exit(1);
12472
+ }
12473
+ const game = await getGameById(client, deployedGame.gameId, {
12474
+ silent: options.raw || options.json
12475
+ });
12476
+ const keysToSeed = Object.keys(seedData);
12477
+ if (!options.force && !options.raw && !options.json) {
12478
+ logger.bold(
12479
+ `Found ${underline5(keysToSeed.length.toString())} ${underline5(pluralize(keysToSeed.length, "key"))} to seed to ${environment}`
12480
+ );
12481
+ if (options.replace) {
12482
+ logger.warn("All existing keys will be cleared first");
12483
+ }
12484
+ logger.newLine();
12485
+ const confirmed = await confirm13({
12486
+ message: "Continue seeding?",
12487
+ default: false
12488
+ });
12489
+ if (!confirmed) {
12490
+ logger.remark("Cancelled");
12491
+ logger.newLine();
12492
+ return;
12493
+ }
12494
+ logger.newLine();
12495
+ }
12496
+ if (options.replace) {
12497
+ await client.dev.games.kv.clear(game.slug);
12498
+ }
12499
+ const entries = keysToSeed.map((key) => {
12500
+ const value = seedData[key];
12501
+ const valueString = typeof value === "string" ? value : JSON.stringify(value);
12502
+ return { key, value: valueString };
12503
+ });
12504
+ const seededCount = await client.dev.games.kv.seed(game.slug, entries);
12505
+ if (options.json) {
12506
+ logger.json({
12507
+ success: true,
12508
+ seeded: seededCount,
12509
+ environment,
12510
+ ...options.replace && { cleared: true }
12511
+ });
12512
+ } else if (options.raw) {
12513
+ logger.raw(seededCount.toString());
12514
+ } else {
12515
+ if (options.replace) {
12516
+ logger.success("Cleared existing keys");
12517
+ }
12518
+ logger.success(`Seeded ${seededCount} ${pluralize(seededCount, "key")} to ${environment}`);
12519
+ logger.newLine();
12520
+ }
12521
+ }
12522
+ async function runKVSeedLocal(seedFile, options) {
12523
+ const config = await loadConfig();
12524
+ if (!hasKVSetup(config)) {
12525
+ if (!options.raw && !options.json) {
12526
+ logger.error("KV storage is not configured");
12527
+ logger.newLine();
12528
+ logger.admonition("tip", "Getting Started", [
12529
+ "Run `playcademy kv init` to enable KV storage",
12530
+ "",
12531
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12532
+ ]);
12533
+ logger.newLine();
12534
+ }
12535
+ process.exit(1);
12536
+ }
12537
+ const workspace = getWorkspace();
12538
+ const seedData = await loadFile(seedFile, {
12539
+ cwd: workspace,
12540
+ parseJson: true
12541
+ });
12542
+ if (!seedData) {
12543
+ if (!options.raw && !options.json) {
12544
+ logger.error(`Seed file not found: ${seedFile}`);
12545
+ logger.newLine();
12546
+ }
12547
+ process.exit(1);
12548
+ }
12549
+ if (typeof seedData !== "object" || seedData === null || Array.isArray(seedData)) {
12550
+ if (!options.raw && !options.json) {
12551
+ logger.error("Seed file must contain a JSON object");
12552
+ logger.newLine();
12553
+ }
12554
+ process.exit(1);
12555
+ }
12556
+ const kvDir = join43(workspace, CLI_DIRECTORIES.KV);
12557
+ const mf = new Miniflare9({
12558
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12559
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12560
+ kvPersist: kvDir,
12561
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12562
+ });
12563
+ try {
12564
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12565
+ const keysToSeed = Object.keys(seedData);
12566
+ if (!options.force && !options.replace && !options.raw && !options.json) {
12567
+ const existingKeys = [];
12568
+ for (const key of keysToSeed) {
12569
+ const existingValue = await kv.get(key);
12570
+ if (existingValue !== null) {
12571
+ existingKeys.push(key);
12572
+ }
12573
+ }
12574
+ if (existingKeys.length > 0) {
12575
+ logger.warn(
12576
+ `${existingKeys.length} ${pluralize(existingKeys.length, "key")} will be overwritten`
12577
+ );
12158
12578
  logger.newLine();
12159
- logger.admonition("info", "Coming Soon", [
12160
- "Remote KV support is on the roadmap and will be available soon.",
12161
- "For now, KV commands only work with local development storage."
12162
- ]);
12579
+ const confirmed = await confirm13({
12580
+ message: "Continue seeding?",
12581
+ default: false
12582
+ });
12583
+ if (!confirmed) {
12584
+ logger.remark("Cancelled");
12585
+ logger.newLine();
12586
+ return;
12587
+ }
12163
12588
  logger.newLine();
12164
12589
  }
12165
- process.exit(1);
12590
+ }
12591
+ if (options.replace) {
12592
+ const listResult = await kv.list();
12593
+ const existingKeys = listResult.keys || [];
12594
+ for (const key of existingKeys) {
12595
+ await kv.delete(key.name);
12596
+ }
12597
+ }
12598
+ let seededCount = 0;
12599
+ for (const key of keysToSeed) {
12600
+ const value = seedData[key];
12601
+ const valueString = typeof value === "string" ? value : JSON.stringify(value);
12602
+ await kv.put(key, valueString);
12603
+ seededCount++;
12604
+ }
12605
+ if (options.json) {
12606
+ logger.json({
12607
+ success: true,
12608
+ seeded: seededCount,
12609
+ ...options.replace && { cleared: true }
12610
+ });
12611
+ } else if (options.raw) {
12612
+ logger.raw(seededCount.toString());
12613
+ } else {
12614
+ if (options.replace) {
12615
+ logger.success("Cleared existing keys");
12616
+ }
12617
+ logger.success(`Seeded ${seededCount} ${pluralize(seededCount, "key")}`);
12618
+ logger.newLine();
12619
+ }
12620
+ } finally {
12621
+ await mf.dispose();
12622
+ }
12623
+ }
12624
+ async function runKVSeed(seedFile, options = {}) {
12625
+ try {
12626
+ if (!options.raw && !options.json) {
12627
+ logger.newLine();
12166
12628
  }
12167
12629
  if (!seedFile) {
12168
12630
  if (!options.raw && !options.json) {
@@ -12178,105 +12640,10 @@ async function runKVSeed(seedFile, options = {}) {
12178
12640
  }
12179
12641
  process.exit(1);
12180
12642
  }
12181
- const config = await loadConfig();
12182
- if (!hasKVSetup(config)) {
12183
- if (!options.raw && !options.json) {
12184
- logger.error("KV storage is not configured");
12185
- logger.newLine();
12186
- logger.admonition("tip", "Getting Started", [
12187
- "Run `playcademy kv init` to enable KV storage",
12188
- "",
12189
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12190
- ]);
12191
- logger.newLine();
12192
- }
12193
- process.exit(1);
12194
- }
12195
- const workspace = getWorkspace();
12196
- const seedData = await loadFile(seedFile, {
12197
- cwd: workspace,
12198
- parseJson: true
12199
- });
12200
- if (!seedData) {
12201
- if (!options.raw && !options.json) {
12202
- logger.error(`Seed file not found: ${seedFile}`);
12203
- logger.newLine();
12204
- }
12205
- process.exit(1);
12206
- }
12207
- if (typeof seedData !== "object" || seedData === null || Array.isArray(seedData)) {
12208
- if (!options.raw && !options.json) {
12209
- logger.error("Seed file must contain a JSON object");
12210
- logger.newLine();
12211
- }
12212
- process.exit(1);
12213
- }
12214
- const kvDir = join43(workspace, CLI_DIRECTORIES.KV);
12215
- const mf = new Miniflare9({
12216
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12217
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12218
- kvPersist: kvDir,
12219
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12220
- });
12221
- try {
12222
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12223
- const keysToSeed = Object.keys(seedData);
12224
- if (!options.force && !options.replace && !options.raw && !options.json) {
12225
- const existingKeys = [];
12226
- for (const key of keysToSeed) {
12227
- const existingValue = await kv.get(key);
12228
- if (existingValue !== null) {
12229
- existingKeys.push(key);
12230
- }
12231
- }
12232
- if (existingKeys.length > 0) {
12233
- logger.warn(
12234
- `${existingKeys.length} ${pluralize(existingKeys.length, "key")} will be overwritten`
12235
- );
12236
- logger.newLine();
12237
- const confirmed = await confirm12({
12238
- message: "Continue seeding?",
12239
- default: false
12240
- });
12241
- if (!confirmed) {
12242
- logger.remark("Cancelled");
12243
- logger.newLine();
12244
- return;
12245
- }
12246
- logger.newLine();
12247
- }
12248
- }
12249
- if (options.replace) {
12250
- const listResult = await kv.list();
12251
- const existingKeys = listResult.keys || [];
12252
- for (const key of existingKeys) {
12253
- await kv.delete(key.name);
12254
- }
12255
- }
12256
- let seededCount = 0;
12257
- for (const key of keysToSeed) {
12258
- const value = seedData[key];
12259
- const valueString = typeof value === "string" ? value : JSON.stringify(value);
12260
- await kv.put(key, valueString);
12261
- seededCount++;
12262
- }
12263
- if (options.json) {
12264
- logger.json({
12265
- success: true,
12266
- seeded: seededCount,
12267
- ...options.replace && { cleared: true }
12268
- });
12269
- } else if (options.raw) {
12270
- logger.raw(seededCount.toString());
12271
- } else {
12272
- if (options.replace) {
12273
- logger.success("Cleared existing keys");
12274
- }
12275
- logger.success(`Seeded ${seededCount} ${pluralize(seededCount, "key")}`);
12276
- logger.newLine();
12277
- }
12278
- } finally {
12279
- await mf.dispose();
12643
+ if (options.remote) {
12644
+ await runKVSeedRemote(seedFile, options);
12645
+ } else {
12646
+ await runKVSeedLocal(seedFile, options);
12280
12647
  }
12281
12648
  } catch (error) {
12282
12649
  if (!options.raw && !options.json) {
@@ -12293,67 +12660,133 @@ async function runKVSeed(seedFile, options = {}) {
12293
12660
  init_file_loader();
12294
12661
  import { join as join44 } from "path";
12295
12662
  import { Miniflare as Miniflare10 } from "miniflare";
12296
- async function runKVSet(key, value, options = {}) {
12297
- try {
12663
+ async function runKVSetRemote(key, value, options) {
12664
+ const environment = ensureEnvironment(options.env);
12665
+ const client = await requireAuthenticatedClient();
12666
+ const workspace = getWorkspace();
12667
+ const deployedGame = await getDeployedGame(workspace);
12668
+ if (!deployedGame) {
12298
12669
  if (!options.raw && !options.json) {
12670
+ logger.admonition("warning", "Deploy First", [
12671
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
12672
+ ]);
12299
12673
  logger.newLine();
12300
12674
  }
12301
- if (options.remote) {
12675
+ process.exit(1);
12676
+ }
12677
+ let valueToSet;
12678
+ if (options.file) {
12679
+ const fileContent = await loadFile(options.file, { cwd: workspace });
12680
+ if (!fileContent) {
12302
12681
  if (!options.raw && !options.json) {
12303
- logger.newLine();
12304
- logger.warn("Remote KV operations are not yet implemented");
12305
- logger.newLine();
12306
- logger.admonition("info", "Coming Soon", [
12307
- "Remote KV support is on the roadmap and will be available soon.",
12308
- "For now, KV commands only work with local development storage."
12309
- ]);
12682
+ logger.error(`File not found: ${options.file}`);
12310
12683
  logger.newLine();
12311
12684
  }
12312
12685
  process.exit(1);
12313
12686
  }
12314
- if (!key) {
12315
- if (!options.raw && !options.json) {
12316
- logger.error("Key is required");
12317
- logger.newLine();
12318
- logger.admonition("tip", "Usage", [
12319
- "`playcademy kv set <key> <value>`",
12320
- "`playcademy kv set <key> --file <path>`"
12321
- ]);
12322
- logger.newLine();
12323
- }
12324
- process.exit(1);
12687
+ valueToSet = fileContent;
12688
+ } else if (value !== void 0) {
12689
+ valueToSet = value;
12690
+ } else {
12691
+ if (!options.raw && !options.json) {
12692
+ logger.error("Value is required (either as argument or via --file)");
12693
+ logger.newLine();
12694
+ logger.admonition("tip", "Usage", [
12695
+ "`playcademy kv set <key> <value> --remote`",
12696
+ "`playcademy kv set <key> --file <path> --remote`"
12697
+ ]);
12698
+ logger.newLine();
12325
12699
  }
12326
- const config = await loadConfig();
12327
- if (!hasKVSetup(config)) {
12700
+ process.exit(1);
12701
+ }
12702
+ const game = await getGameById(client, deployedGame.gameId, {
12703
+ silent: options.raw || options.json
12704
+ });
12705
+ await client.dev.games.kv.set(game.slug, key, valueToSet);
12706
+ if (options.json) {
12707
+ logger.json({
12708
+ key,
12709
+ success: true,
12710
+ environment
12711
+ });
12712
+ } else if (options.raw) {
12713
+ logger.raw("ok");
12714
+ } else {
12715
+ logger.success(`Set key: ${key} in ${environment}`);
12716
+ logger.newLine();
12717
+ }
12718
+ }
12719
+ async function runKVSetLocal(key, value, options) {
12720
+ const config = await loadConfig();
12721
+ if (!hasKVSetup(config)) {
12722
+ if (!options.raw && !options.json) {
12723
+ logger.error("KV storage is not configured");
12724
+ logger.newLine();
12725
+ logger.admonition("tip", "Getting Started", [
12726
+ "Run `playcademy kv init` to enable KV storage",
12727
+ "",
12728
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12729
+ ]);
12730
+ logger.newLine();
12731
+ }
12732
+ process.exit(1);
12733
+ }
12734
+ let valueToSet;
12735
+ if (options.file) {
12736
+ const workspace = getWorkspace();
12737
+ const fileContent = await loadFile(options.file, { cwd: workspace });
12738
+ if (!fileContent) {
12328
12739
  if (!options.raw && !options.json) {
12329
- logger.error("KV storage is not configured");
12330
- logger.newLine();
12331
- logger.admonition("tip", "Getting Started", [
12332
- "Run `playcademy kv init` to enable KV storage",
12333
- "",
12334
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12335
- ]);
12740
+ logger.error(`File not found: ${options.file}`);
12336
12741
  logger.newLine();
12337
12742
  }
12338
12743
  process.exit(1);
12339
12744
  }
12340
- let valueToSet;
12341
- if (options.file) {
12342
- const workspace = getWorkspace();
12343
- const fileContent = await loadFile(options.file, { cwd: workspace });
12344
- if (!fileContent) {
12345
- if (!options.raw && !options.json) {
12346
- logger.error(`File not found: ${options.file}`);
12347
- logger.newLine();
12348
- }
12349
- process.exit(1);
12350
- }
12351
- valueToSet = fileContent;
12352
- } else if (value !== void 0) {
12353
- valueToSet = value;
12745
+ valueToSet = fileContent;
12746
+ } else if (value !== void 0) {
12747
+ valueToSet = value;
12748
+ } else {
12749
+ if (!options.raw && !options.json) {
12750
+ logger.error("Value is required (either as argument or via --file)");
12751
+ logger.newLine();
12752
+ logger.admonition("tip", "Usage", [
12753
+ "`playcademy kv set <key> <value>`",
12754
+ "`playcademy kv set <key> --file <path>`"
12755
+ ]);
12756
+ logger.newLine();
12757
+ }
12758
+ process.exit(1);
12759
+ }
12760
+ const kvDir = join44(getWorkspace(), CLI_DIRECTORIES.KV);
12761
+ const mf = new Miniflare10({
12762
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12763
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12764
+ kvPersist: kvDir,
12765
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12766
+ });
12767
+ try {
12768
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12769
+ await kv.put(key, valueToSet);
12770
+ if (options.json) {
12771
+ logger.json({
12772
+ key,
12773
+ success: true
12774
+ });
12775
+ } else if (options.raw) {
12776
+ logger.raw("ok");
12354
12777
  } else {
12778
+ logger.success(`Set key: ${key}`);
12779
+ logger.newLine();
12780
+ }
12781
+ } finally {
12782
+ await mf.dispose();
12783
+ }
12784
+ }
12785
+ async function runKVSet(key, value, options = {}) {
12786
+ try {
12787
+ if (!key) {
12355
12788
  if (!options.raw && !options.json) {
12356
- logger.error("Value is required (either as argument or via --file)");
12789
+ logger.error("Key is required");
12357
12790
  logger.newLine();
12358
12791
  logger.admonition("tip", "Usage", [
12359
12792
  "`playcademy kv set <key> <value>`",
@@ -12363,29 +12796,10 @@ async function runKVSet(key, value, options = {}) {
12363
12796
  }
12364
12797
  process.exit(1);
12365
12798
  }
12366
- const kvDir = join44(getWorkspace(), CLI_DIRECTORIES.KV);
12367
- const mf = new Miniflare10({
12368
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12369
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12370
- kvPersist: kvDir,
12371
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12372
- });
12373
- try {
12374
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12375
- await kv.put(key, valueToSet);
12376
- if (options.json) {
12377
- logger.json({
12378
- key,
12379
- success: true
12380
- });
12381
- } else if (options.raw) {
12382
- logger.raw("ok");
12383
- } else {
12384
- logger.success(`Set key: ${key}`);
12385
- logger.newLine();
12386
- }
12387
- } finally {
12388
- await mf.dispose();
12799
+ if (options.remote) {
12800
+ await runKVSetRemote(key, value, options);
12801
+ } else {
12802
+ await runKVSetLocal(key, value, options);
12389
12803
  }
12390
12804
  } catch (error) {
12391
12805
  if (!options.raw && !options.json) {
@@ -12401,100 +12815,135 @@ async function runKVSet(key, value, options = {}) {
12401
12815
  // src/commands/kv/stats.ts
12402
12816
  import { join as join45 } from "path";
12403
12817
  import { Miniflare as Miniflare11 } from "miniflare";
12404
- async function runKVStats(options = {}) {
12405
- try {
12818
+ async function runKVStatsRemote(options) {
12819
+ const environment = ensureEnvironment(options.env);
12820
+ const client = await requireAuthenticatedClient();
12821
+ const workspace = getWorkspace();
12822
+ const deployedGame = await getDeployedGame(workspace);
12823
+ if (!deployedGame) {
12406
12824
  if (!options.raw && !options.json) {
12825
+ logger.admonition("warning", "Deploy First", [
12826
+ "Deploy your project before accessing remote KV: `playcademy deploy`"
12827
+ ]);
12407
12828
  logger.newLine();
12408
12829
  }
12409
- if (options.remote) {
12410
- if (!options.raw && !options.json) {
12411
- logger.newLine();
12412
- logger.warn("Remote KV operations are not yet implemented");
12413
- logger.newLine();
12414
- logger.admonition("info", "Coming Soon", [
12415
- "Remote KV support is on the roadmap and will be available soon.",
12416
- "For now, KV commands only work with local development storage."
12417
- ]);
12418
- logger.newLine();
12830
+ process.exit(1);
12831
+ }
12832
+ const game = await getGameById(client, deployedGame.gameId, {
12833
+ silent: options.raw || options.json
12834
+ });
12835
+ const stats = await client.dev.games.kv.stats(game.slug);
12836
+ if (options.json) {
12837
+ logger.json(stats);
12838
+ } else if (options.raw) {
12839
+ logger.raw(stats.totalKeys.toString());
12840
+ } else {
12841
+ if (stats.totalKeys === 0) {
12842
+ logger.remark(`No keys found in ${environment} KV namespace`);
12843
+ logger.newLine();
12844
+ return;
12845
+ }
12846
+ logger.data("Total Keys", stats.totalKeys.toString(), 1);
12847
+ logger.data("Environment", environment, 1);
12848
+ const sortedPrefixes = Object.entries(stats.prefixes).sort((a, b) => b[1] - a[1]);
12849
+ if (sortedPrefixes.length > 0) {
12850
+ logger.newLine();
12851
+ logger.data("Keys by Prefix:", "", 1);
12852
+ for (const [prefix, count] of sortedPrefixes) {
12853
+ logger.dim(`${prefix.padEnd(20)} ${count} ${pluralize(count, "key")}`, 2);
12419
12854
  }
12420
- process.exit(1);
12421
12855
  }
12422
- const config = await loadConfig();
12423
- if (!hasKVSetup(config)) {
12424
- if (!options.raw && !options.json) {
12425
- logger.error("KV storage is not configured");
12426
- logger.newLine();
12427
- logger.admonition("tip", "Getting Started", [
12428
- "Run `playcademy kv init` to enable KV storage",
12429
- "",
12430
- "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12431
- ]);
12856
+ logger.newLine();
12857
+ }
12858
+ }
12859
+ async function runKVStatsLocal(options) {
12860
+ const config = await loadConfig();
12861
+ if (!hasKVSetup(config)) {
12862
+ if (!options.raw && !options.json) {
12863
+ logger.error("KV storage is not configured");
12864
+ logger.newLine();
12865
+ logger.admonition("tip", "Getting Started", [
12866
+ "Run `playcademy kv init` to enable KV storage",
12867
+ "",
12868
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/kv>>"
12869
+ ]);
12870
+ logger.newLine();
12871
+ }
12872
+ process.exit(1);
12873
+ }
12874
+ const kvDir = join45(getWorkspace(), CLI_DIRECTORIES.KV);
12875
+ const mf = new Miniflare11({
12876
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12877
+ kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12878
+ kvPersist: kvDir,
12879
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12880
+ });
12881
+ try {
12882
+ const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12883
+ const listResult = await kv.list();
12884
+ const keys = listResult.keys || [];
12885
+ let totalSize = 0;
12886
+ let largestKey;
12887
+ const prefixes = {};
12888
+ for (const key of keys) {
12889
+ const value = await kv.get(key.name, "arrayBuffer");
12890
+ const size = value ? value.byteLength : 0;
12891
+ totalSize += size;
12892
+ if (!largestKey || size > largestKey.size) {
12893
+ largestKey = { name: key.name, size };
12894
+ }
12895
+ const prefixMatch = key.name.match(/^([^:]+):/);
12896
+ const prefix = prefixMatch ? `${prefixMatch[1]}:*` : "(no prefix)";
12897
+ prefixes[prefix] = (prefixes[prefix] || 0) + 1;
12898
+ }
12899
+ const stats = {
12900
+ totalKeys: keys.length,
12901
+ totalSize,
12902
+ largestKey,
12903
+ prefixes
12904
+ };
12905
+ if (options.json) {
12906
+ logger.json(stats);
12907
+ } else if (options.raw) {
12908
+ logger.raw(stats.totalKeys.toString());
12909
+ } else {
12910
+ if (stats.totalKeys === 0) {
12911
+ logger.remark("No keys found in KV namespace");
12432
12912
  logger.newLine();
12913
+ return;
12433
12914
  }
12434
- process.exit(1);
12435
- }
12436
- const kvDir = join45(getWorkspace(), CLI_DIRECTORIES.KV);
12437
- const mf = new Miniflare11({
12438
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
12439
- kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
12440
- kvPersist: kvDir,
12441
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
12442
- });
12443
- try {
12444
- const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
12445
- const listResult = await kv.list();
12446
- const keys = listResult.keys || [];
12447
- let totalSize = 0;
12448
- let largestKey;
12449
- const prefixes = {};
12450
- for (const key of keys) {
12451
- const value = await kv.get(key.name, "arrayBuffer");
12452
- const size = value ? value.byteLength : 0;
12453
- totalSize += size;
12454
- if (!largestKey || size > largestKey.size) {
12455
- largestKey = { name: key.name, size };
12456
- }
12457
- const prefixMatch = key.name.match(/^([^:]+):/);
12458
- const prefix = prefixMatch ? `${prefixMatch[1]}:*` : "(no prefix)";
12459
- prefixes[prefix] = (prefixes[prefix] || 0) + 1;
12460
- }
12461
- const stats = {
12462
- totalKeys: keys.length,
12463
- totalSize,
12464
- largestKey,
12465
- prefixes
12466
- };
12467
- if (options.json) {
12468
- logger.json(stats);
12469
- } else if (options.raw) {
12470
- logger.raw(stats.totalKeys.toString());
12471
- } else {
12472
- if (stats.totalKeys === 0) {
12473
- logger.remark("No keys found in KV namespace");
12474
- logger.newLine();
12475
- return;
12476
- }
12477
- logger.data("Total Keys", stats.totalKeys.toString(), 1);
12478
- const sizeKB = (stats.totalSize / 1024).toFixed(2);
12479
- const sizeMB = (stats.totalSize / 1024 / 1024).toFixed(2);
12480
- const sizeDisplay = stats.totalSize >= 1024 * 1024 ? `${sizeMB} MB` : `${sizeKB} KB`;
12481
- logger.data("Total Size", sizeDisplay, 1);
12482
- if (stats.largestKey) {
12483
- const largestKB = (stats.largestKey.size / 1024).toFixed(2);
12484
- logger.data("Largest Key", `${stats.largestKey.name} (${largestKB} KB)`, 1);
12485
- }
12486
- const sortedPrefixes = Object.entries(stats.prefixes).sort((a, b) => b[1] - a[1]);
12487
- if (sortedPrefixes.length > 0) {
12488
- logger.newLine();
12489
- logger.data("Keys by Prefix:", "", 1);
12490
- for (const [prefix, count] of sortedPrefixes) {
12491
- logger.dim(`${prefix.padEnd(20)} ${count} ${pluralize(count, "key")}`, 2);
12492
- }
12493
- }
12915
+ logger.data("Total Keys", stats.totalKeys.toString(), 1);
12916
+ const sizeKB = (stats.totalSize / 1024).toFixed(2);
12917
+ const sizeMB = (stats.totalSize / 1024 / 1024).toFixed(2);
12918
+ const sizeDisplay = stats.totalSize >= 1024 * 1024 ? `${sizeMB} MB` : `${sizeKB} KB`;
12919
+ logger.data("Total Size", sizeDisplay, 1);
12920
+ if (stats.largestKey) {
12921
+ const largestKB = (stats.largestKey.size / 1024).toFixed(2);
12922
+ logger.data("Largest Key", `${stats.largestKey.name} (${largestKB} KB)`, 1);
12923
+ }
12924
+ const sortedPrefixes = Object.entries(stats.prefixes).sort((a, b) => b[1] - a[1]);
12925
+ if (sortedPrefixes.length > 0) {
12494
12926
  logger.newLine();
12927
+ logger.data("Keys by Prefix:", "", 1);
12928
+ for (const [prefix, count] of sortedPrefixes) {
12929
+ logger.dim(`${prefix.padEnd(20)} ${count} ${pluralize(count, "key")}`, 2);
12930
+ }
12495
12931
  }
12496
- } finally {
12497
- await mf.dispose();
12932
+ logger.newLine();
12933
+ }
12934
+ } finally {
12935
+ await mf.dispose();
12936
+ }
12937
+ }
12938
+ async function runKVStats(options = {}) {
12939
+ try {
12940
+ if (!options.raw && !options.json) {
12941
+ logger.newLine();
12942
+ }
12943
+ if (options.remote) {
12944
+ await runKVStatsRemote(options);
12945
+ } else {
12946
+ await runKVStatsLocal(options);
12498
12947
  }
12499
12948
  } catch (error) {
12500
12949
  if (!options.raw && !options.json) {
@@ -12512,35 +12961,35 @@ var kvCommand = new Command20("kv").description("Manage KV storage integration")
12512
12961
  kvCommand.help();
12513
12962
  });
12514
12963
  kvCommand.command("init").description("Add KV storage integration to your project").action(runKVInit);
12515
- kvCommand.command("list").alias("ls").description("List keys in local KV namespace (dev mode)").option("--raw", "Output key names one per line, no formatting").option("--json", "Output as JSON array").option("--remote", "Use remote KV storage (not yet implemented)").option(
12964
+ kvCommand.command("list").alias("ls").description("List keys in KV namespace").option("--raw", "Output key names one per line, no formatting").option("--json", "Output as JSON array").option("--remote", "Use remote KV storage instead of local").option(
12516
12965
  "--env <environment>",
12517
12966
  "Environment to use with --remote: staging (default) or production"
12518
- ).action(runKVList);
12519
- kvCommand.command("stats").description("Show statistics about local KV namespace (dev mode)").option("--raw", "Output total key count only").option("--json", "Output statistics as JSON").option("--remote", "Use remote KV storage (not yet implemented)").option(
12967
+ ).option("--prefix <prefix>", "Filter keys by prefix").action(runKVList);
12968
+ kvCommand.command("stats").description("Show statistics about KV namespace").option("--raw", "Output total key count only").option("--json", "Output statistics as JSON").option("--remote", "Use remote KV storage instead of local").option(
12520
12969
  "--env <environment>",
12521
12970
  "Environment to use with --remote: staging (default) or production"
12522
12971
  ).action(runKVStats);
12523
- kvCommand.command("get <key>").description("Get value for a specific key in local KV namespace (dev mode)").option("--raw", "Output raw value without formatting").option("--json", "Force JSON pretty-printing (default for valid JSON)").option("--remote", "Use remote KV storage (not yet implemented)").option(
12972
+ kvCommand.command("get <key>").description("Get value for a specific key in KV namespace").option("--raw", "Output raw value without formatting").option("--json", "Force JSON pretty-printing (default for valid JSON)").option("--remote", "Use remote KV storage instead of local").option(
12524
12973
  "--env <environment>",
12525
12974
  "Environment to use with --remote: staging (default) or production"
12526
12975
  ).action(runKVGet);
12527
- kvCommand.command("inspect <key>").description("Inspect metadata and value for a specific key in local KV namespace (dev mode)").option("--raw", "Output size in bytes only").option("--json", "Output metadata as JSON").option("--remote", "Use remote KV storage (not yet implemented)").option(
12976
+ kvCommand.command("inspect <key>").description("Inspect metadata and value for a specific key in KV namespace").option("--raw", "Output size in bytes only").option("--json", "Output metadata as JSON").option("--remote", "Use remote KV storage instead of local").option(
12528
12977
  "--env <environment>",
12529
12978
  "Environment to use with --remote: staging (default) or production"
12530
12979
  ).action(runKVInspect);
12531
- kvCommand.command("set <key> [value]").description("Set a key-value pair in local KV namespace (dev mode)").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("--file <path>", "Read value from file").option("--remote", "Use remote KV storage (not yet implemented)").option(
12980
+ kvCommand.command("set <key> [value]").description("Set a key-value pair in KV namespace").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("--file <path>", "Read value from file").option("--remote", "Use remote KV storage instead of local").option(
12532
12981
  "--env <environment>",
12533
12982
  "Environment to use with --remote: staging (default) or production"
12534
12983
  ).action(runKVSet);
12535
- kvCommand.command("delete <key>").alias("del").alias("rm").description("Delete a specific key from local KV namespace (dev mode)").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("--remote", "Use remote KV storage (not yet implemented)").option(
12984
+ kvCommand.command("delete <key>").alias("del").alias("rm").description("Delete a specific key from KV namespace").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("-f, --force", "Skip confirmation prompt").option("--remote", "Use remote KV storage instead of local").option(
12536
12985
  "--env <environment>",
12537
12986
  "Environment to use with --remote: staging (default) or production"
12538
12987
  ).action(runKVDelete);
12539
- kvCommand.command("clear").description("Clear all keys from local KV namespace (dev mode)").option("--raw", "Output count of deleted keys").option("--json", "Output result as JSON").option("-f, --force", "Skip confirmation prompt").option("--remote", "Use remote KV storage (not yet implemented)").option(
12988
+ kvCommand.command("clear").description("Clear all keys from KV namespace").option("--raw", "Output count of deleted keys").option("--json", "Output result as JSON").option("-f, --force", "Skip confirmation prompt").option("--remote", "Use remote KV storage instead of local").option(
12540
12989
  "--env <environment>",
12541
12990
  "Environment to use with --remote: staging (default) or production"
12542
12991
  ).action(runKVClear);
12543
- kvCommand.command("seed <file>").description("Seed KV namespace with key-value pairs from JSON file (dev mode)").option("--raw", "Output count of seeded keys").option("--json", "Output result as JSON").option("--replace", "Clear existing keys before seeding").option("-f, --force", "Skip confirmation prompt").option("--remote", "Use remote KV storage (not yet implemented)").option(
12992
+ kvCommand.command("seed <file>").description("Seed KV namespace with key-value pairs from JSON file").option("--raw", "Output count of seeded keys").option("--json", "Output result as JSON").option("--replace", "Clear existing keys before seeding").option("-f, --force", "Skip confirmation prompt").option("--remote", "Use remote KV storage instead of local").option(
12544
12993
  "--env <environment>",
12545
12994
  "Environment to use with --remote: staging (default) or production"
12546
12995
  ).action(runKVSeed);
@@ -13405,7 +13854,7 @@ bucketCommand.command("bulk <directory>").description(
13405
13854
  import { Command as Command22 } from "commander";
13406
13855
 
13407
13856
  // src/commands/domain/add.ts
13408
- import { underline as underline5 } from "colorette";
13857
+ import { underline as underline6 } from "colorette";
13409
13858
  async function runDomainAdd(hostname, options) {
13410
13859
  try {
13411
13860
  logger.newLine();
@@ -13431,7 +13880,7 @@ async function runDomainAdd(hostname, options) {
13431
13880
  async () => {
13432
13881
  return client.dev.games.domains.add(slug, normalizedHostname);
13433
13882
  },
13434
- (domain2) => `Custom domain added: ${underline5(`<https://${domain2.hostname}>`)}`
13883
+ (domain2) => `Custom domain added: ${underline6(`<https://${domain2.hostname}>`)}`
13435
13884
  );
13436
13885
  logger.newLine();
13437
13886
  displayDomainValidationRecords(domain, normalizedHostname);
@@ -13456,7 +13905,7 @@ async function runDomainAdd(hostname, options) {
13456
13905
  }
13457
13906
 
13458
13907
  // src/commands/domain/delete.ts
13459
- import { confirm as confirm13 } from "@inquirer/prompts";
13908
+ import { confirm as confirm14 } from "@inquirer/prompts";
13460
13909
  async function runDomainDelete(hostname, options) {
13461
13910
  try {
13462
13911
  logger.newLine();
@@ -13465,7 +13914,7 @@ async function runDomainDelete(hostname, options) {
13465
13914
  const config = await loadConfig();
13466
13915
  const slug = getSlugFromConfig(config);
13467
13916
  if (!options.force) {
13468
- const shouldDelete = await confirm13({
13917
+ const shouldDelete = await confirm14({
13469
13918
  message: `Delete custom domain ${hostname}?`,
13470
13919
  default: false
13471
13920
  });
@@ -13548,7 +13997,7 @@ async function runDomainList(options) {
13548
13997
  }
13549
13998
 
13550
13999
  // src/commands/domain/verify.ts
13551
- import { underline as underline6 } from "colorette";
14000
+ import { underline as underline7 } from "colorette";
13552
14001
  async function runDomainVerify(hostname, options) {
13553
14002
  try {
13554
14003
  if (!options.json) {
@@ -13575,7 +14024,7 @@ async function runDomainVerify(hostname, options) {
13575
14024
  displayDomainStatus(hostname, domain);
13576
14025
  if (domain.status === "active" && domain.sslStatus === "active") {
13577
14026
  logger.admonition("info", "Domain Active", [
13578
- `Your app is now accessible at: ${underline6(`<https://${hostname}>`)}`
14027
+ `Your app is now accessible at: ${underline7(`<https://${hostname}>`)}`
13579
14028
  ]);
13580
14029
  logger.newLine();
13581
14030
  } else if (domain.status === "pending" || domain.status === "pending_validation" || domain.sslStatus === "pending_validation") {
@@ -13608,7 +14057,7 @@ domainCommand.command("delete <hostname>").description("Remove a custom domain")
13608
14057
  import { Command as Command26 } from "commander";
13609
14058
 
13610
14059
  // src/commands/secret/delete.ts
13611
- import { confirm as confirm14 } from "@inquirer/prompts";
14060
+ import { confirm as confirm15 } from "@inquirer/prompts";
13612
14061
  import { Command as Command23 } from "commander";
13613
14062
  var deleteCommand2 = new Command23("delete").description("Delete a project secret").argument("<key>", "Secret key to delete").option("--env <environment>", "Environment (staging or production)").option("-f, --force", "Skip confirmation").action(async (key, options) => {
13614
14063
  const { env } = options;
@@ -13637,7 +14086,7 @@ var deleteCommand2 = new Command23("delete").description("Delete a project secre
13637
14086
  process.exit(1);
13638
14087
  }
13639
14088
  if (!options.force) {
13640
- const confirmed = await confirm14({
14089
+ const confirmed = await confirm15({
13641
14090
  message: `Delete secret "${key}" from "${game.slug}" in ${environment}?`,
13642
14091
  default: false
13643
14092
  });
@@ -13840,7 +14289,7 @@ var removeCommand = new Command29("remove").alias("rm").description('Remove an a
13840
14289
  });
13841
14290
 
13842
14291
  // src/commands/profiles/reset.ts
13843
- import { confirm as confirm15 } from "@inquirer/prompts";
14292
+ import { confirm as confirm16 } from "@inquirer/prompts";
13844
14293
  import { Command as Command30 } from "commander";
13845
14294
  var resetCommand = new Command30("reset").description(
13846
14295
  "Remove all authentication profiles across all environments (requires confirmation)"
@@ -13878,7 +14327,7 @@ var resetCommand = new Command30("reset").description(
13878
14327
  logger.newLine();
13879
14328
  }
13880
14329
  }
13881
- const confirmed = await confirm15({
14330
+ const confirmed = await confirm16({
13882
14331
  message: "Are you sure you want to remove all profiles?",
13883
14332
  default: false
13884
14333
  });
@@ -13927,7 +14376,7 @@ profilesCommand.addCommand(resetCommand);
13927
14376
  import { Command as Command37 } from "commander";
13928
14377
 
13929
14378
  // src/commands/timeback/cleanup.ts
13930
- import { confirm as confirm16 } from "@inquirer/prompts";
14379
+ import { confirm as confirm17 } from "@inquirer/prompts";
13931
14380
  import { Command as Command32 } from "commander";
13932
14381
  var cleanupCommand = new Command32("cleanup").description("Remove TimeBack integration from your project").option(
13933
14382
  "--env <environment>",
@@ -13951,7 +14400,7 @@ var cleanupCommand = new Command32("cleanup").description("Remove TimeBack integ
13951
14400
  return;
13952
14401
  }
13953
14402
  displayCleanupWarning(integrations, game.displayName, logger);
13954
- const confirmed = await confirm16({
14403
+ const confirmed = await confirm17({
13955
14404
  message: "Are you sure you want to remove TimeBack integration?",
13956
14405
  default: false
13957
14406
  });
@@ -14313,7 +14762,7 @@ import { Command as Command40 } from "commander";
14313
14762
 
14314
14763
  // src/commands/vite/config.ts
14315
14764
  import path3 from "node:path";
14316
- import { confirm as confirm17 } from "@inquirer/prompts";
14765
+ import { confirm as confirm18 } from "@inquirer/prompts";
14317
14766
  import { dim as dim12 } from "colorette";
14318
14767
  async function runViteConfig() {
14319
14768
  try {
@@ -14323,7 +14772,7 @@ async function runViteConfig() {
14323
14772
  if (!existingViteConfig) {
14324
14773
  logger.warn("No vite config file found in your project");
14325
14774
  logger.newLine();
14326
- const shouldCreate = await confirm17({
14775
+ const shouldCreate = await confirm18({
14327
14776
  message: "Would you like to create a new vite.config.ts?",
14328
14777
  default: true
14329
14778
  });