playcademy 0.13.22 → 0.13.23

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.d.ts CHANGED
@@ -169,6 +169,45 @@ interface BackendFeatures {
169
169
  hasSecrets: boolean;
170
170
  }
171
171
 
172
+ /**
173
+ * Bucket command types
174
+ */
175
+ /**
176
+ * Base options shared across bucket commands
177
+ */
178
+ interface BaseBucketOptions {
179
+ /** Output in raw format */
180
+ raw?: boolean;
181
+ /** Output in JSON format */
182
+ json?: boolean;
183
+ /** Use remote bucket storage */
184
+ remote?: boolean;
185
+ /** Environment (staging or production) */
186
+ env?: string;
187
+ }
188
+ /**
189
+ * Options for the bucket list command
190
+ */
191
+ interface BucketListOptions extends BaseBucketOptions {
192
+ /** Filter files by key prefix */
193
+ prefix?: string;
194
+ }
195
+ /**
196
+ * Options for the bucket get command
197
+ */
198
+ interface BucketGetOptions extends BaseBucketOptions {
199
+ /** Output file path */
200
+ output?: string;
201
+ }
202
+ /**
203
+ * Options for the bucket put command
204
+ */
205
+ type BucketPutOptions = BaseBucketOptions;
206
+ /**
207
+ * Options for the bucket delete command
208
+ */
209
+ type BucketDeleteOptions = BaseBucketOptions;
210
+
172
211
  /**
173
212
  * @fileoverview Server SDK Type Definitions
174
213
  *
@@ -954,4 +993,4 @@ interface KeyMetadata {
954
993
  valueType?: 'json' | 'string';
955
994
  }
956
995
 
957
- export type { ApiConfig, ApiErrorResponse, ApiKeyListItem, ApiKeyWithSecret, ApiRequestOptions, AuthProfile, AuthStore, BackendBundle, BackendDeploymentWithHash, BackendDiff, BackendFeatures, BuildDiff, BundleOptions, CallbackServerResult, ConfigDiff, CreateApiKeyResponse, CustomRoutesIntegrationOptions, DatabaseIntegrationOptions, DeployConfig, DeployNewGameOptions, DeployedGameInfo, DeploymentChanges, DeploymentContext, DeploymentDiffOptions, DeploymentPlan, DeploymentResult, DevServerOptions, EmbeddedSourcePaths, EnvironmentAuthProfiles, GameStore, IntegrationChangeDetector, IntegrationChangeDetectors, IntegrationConfigChange, IntegrationsConfig, IntegrationsDiff, KeyMetadata, KeyStats, LoginCredentials, LoginResponse, PlaycademyConfig, PreviewOptions, PreviewResponse, SecretsDiff, SignInResponse, SsoCallbackData, TimebackIntegrationConfig, TokenType, UpdateExistingGameOptions };
996
+ export type { ApiConfig, ApiErrorResponse, ApiKeyListItem, ApiKeyWithSecret, ApiRequestOptions, AuthProfile, AuthStore, BackendBundle, BackendDeploymentWithHash, BackendDiff, BackendFeatures, BucketDeleteOptions, BucketGetOptions, BucketListOptions, BucketPutOptions, BuildDiff, BundleOptions, CallbackServerResult, ConfigDiff, CreateApiKeyResponse, CustomRoutesIntegrationOptions, DatabaseIntegrationOptions, DeployConfig, DeployNewGameOptions, DeployedGameInfo, DeploymentChanges, DeploymentContext, DeploymentDiffOptions, DeploymentPlan, DeploymentResult, DevServerOptions, EmbeddedSourcePaths, EnvironmentAuthProfiles, GameStore, IntegrationChangeDetector, IntegrationChangeDetectors, IntegrationConfigChange, IntegrationsConfig, IntegrationsDiff, KeyMetadata, KeyStats, LoginCredentials, LoginResponse, PlaycademyConfig, PreviewOptions, PreviewResponse, SecretsDiff, SignInResponse, SsoCallbackData, TimebackIntegrationConfig, TokenType, UpdateExistingGameOptions };
package/dist/index.js CHANGED
@@ -3724,6 +3724,57 @@ var init_import = __esm({
3724
3724
  }
3725
3725
  });
3726
3726
 
3727
+ // src/lib/core/mime.ts
3728
+ function getContentType(filePath) {
3729
+ const ext = filePath.split(".").pop()?.toLowerCase();
3730
+ const types = {
3731
+ // Images
3732
+ jpg: "image/jpeg",
3733
+ jpeg: "image/jpeg",
3734
+ png: "image/png",
3735
+ gif: "image/gif",
3736
+ webp: "image/webp",
3737
+ svg: "image/svg+xml",
3738
+ ico: "image/x-icon",
3739
+ // Audio
3740
+ mp3: "audio/mpeg",
3741
+ wav: "audio/wav",
3742
+ ogg: "audio/ogg",
3743
+ m4a: "audio/mp4",
3744
+ // Video
3745
+ mp4: "video/mp4",
3746
+ webm: "video/webm",
3747
+ mov: "video/quicktime",
3748
+ // Documents
3749
+ pdf: "application/pdf",
3750
+ txt: "text/plain",
3751
+ md: "text/markdown",
3752
+ // Web
3753
+ html: "text/html",
3754
+ htm: "text/html",
3755
+ css: "text/css",
3756
+ js: "application/javascript",
3757
+ mjs: "application/javascript",
3758
+ json: "application/json",
3759
+ xml: "application/xml",
3760
+ // Archives
3761
+ zip: "application/zip",
3762
+ gz: "application/gzip",
3763
+ tar: "application/x-tar",
3764
+ // Fonts
3765
+ woff: "font/woff",
3766
+ woff2: "font/woff2",
3767
+ ttf: "font/ttf",
3768
+ otf: "font/otf"
3769
+ };
3770
+ return types[ext || ""] || "application/octet-stream";
3771
+ }
3772
+ var init_mime2 = __esm({
3773
+ "src/lib/core/mime.ts"() {
3774
+ "use strict";
3775
+ }
3776
+ });
3777
+
3727
3778
  // src/lib/core/index.ts
3728
3779
  var core_exports = {};
3729
3780
  __export(core_exports, {
@@ -3733,6 +3784,7 @@ __export(core_exports, {
3733
3784
  getApiUrl: () => getApiUrl,
3734
3785
  getBaseUrl: () => getBaseUrl,
3735
3786
  getCliContext: () => getCliContext,
3787
+ getContentType: () => getContentType,
3736
3788
  getEnvironment: () => getEnvironment,
3737
3789
  getErrorMessage: () => getErrorMessage,
3738
3790
  getGameFromConfig: () => getGameFromConfig,
@@ -3760,6 +3812,7 @@ var init_core = __esm({
3760
3812
  init_game();
3761
3813
  init_import();
3762
3814
  init_logger();
3815
+ init_mime2();
3763
3816
  }
3764
3817
  });
3765
3818
 
@@ -4936,6 +4989,9 @@ var isDevelopment = () => {
4936
4989
  var isInteractiveTTY = () => {
4937
4990
  return typeof process !== "undefined" && Boolean(process.stdout && process.stdout.isTTY);
4938
4991
  };
4992
+ var isSilent = () => {
4993
+ return typeof process !== "undefined" && process.env.LOG_SILENT === "true";
4994
+ };
4939
4995
  var detectOutputFormat = () => {
4940
4996
  if (isBrowser()) {
4941
4997
  return "browser";
@@ -5056,6 +5112,7 @@ var getMinimumLogLevel = () => {
5056
5112
  return isProduction() ? "info" : "debug";
5057
5113
  };
5058
5114
  var shouldLog = (level) => {
5115
+ if (isSilent()) return false;
5059
5116
  const minLevel = getMinimumLogLevel();
5060
5117
  return levelPriority[level] >= levelPriority[minLevel];
5061
5118
  };
@@ -10627,83 +10684,109 @@ import { Command as Command16 } from "commander";
10627
10684
  init_constants2();
10628
10685
  import { join as join32 } from "path";
10629
10686
  import { Miniflare as Miniflare11 } from "miniflare";
10630
- async function runBucketDelete(key, options = {}) {
10631
- try {
10687
+ async function runBucketDeleteRemote(key, options) {
10688
+ const environment = ensureEnvironment(options.env);
10689
+ const client = await requireAuthenticatedClient();
10690
+ const workspace = getWorkspace();
10691
+ const deployedGame = await getDeployedGame(workspace);
10692
+ if (!deployedGame) {
10632
10693
  if (!options.raw && !options.json) {
10694
+ logger.admonition("warning", "Deploy First", [
10695
+ `Deploy your game before accessing remote bucket: \`playcademy deploy\``
10696
+ ]);
10633
10697
  logger.newLine();
10634
10698
  }
10635
- if (options.remote) {
10636
- if (!options.raw && !options.json) {
10637
- logger.newLine();
10638
- logger.warn("Remote bucket operations are not yet implemented");
10639
- logger.newLine();
10640
- logger.admonition("warning", "Coming Soon", [
10641
- "Remote bucket support is on the roadmap and will be available soon.",
10642
- "For now, bucket commands only work with local development storage."
10643
- ]);
10644
- logger.newLine();
10645
- }
10646
- process.exit(1);
10699
+ process.exit(1);
10700
+ }
10701
+ const game = await client.games.fetch(deployedGame.gameId);
10702
+ await client.dev.games.bucket.delete(game.slug, key);
10703
+ if (options.json) {
10704
+ logger.json({
10705
+ success: true,
10706
+ key,
10707
+ message: "File deleted successfully"
10708
+ });
10709
+ return;
10710
+ }
10711
+ if (options.raw) {
10712
+ logger.raw(`Deleted ${key}`);
10713
+ return;
10714
+ }
10715
+ logger.newLine();
10716
+ logger.success(`Deleted '${key}' from ${environment}`);
10717
+ logger.newLine();
10718
+ }
10719
+ async function runBucketDeleteLocal(key, options) {
10720
+ if (!key) {
10721
+ if (!options.raw && !options.json) {
10722
+ logger.error("File key is required");
10723
+ logger.newLine();
10724
+ logger.admonition("tip", "Usage", ["`playcademy bucket delete <key>`"]);
10725
+ logger.newLine();
10647
10726
  }
10648
- if (!key) {
10649
- if (!options.raw && !options.json) {
10650
- logger.error("File key is required");
10651
- logger.newLine();
10652
- logger.admonition("tip", "Usage", ["`playcademy bucket delete <key>`"]);
10653
- logger.newLine();
10654
- }
10655
- process.exit(1);
10727
+ process.exit(1);
10728
+ }
10729
+ const config = await loadConfig();
10730
+ if (!hasBucketSetup(config)) {
10731
+ if (!options.raw && !options.json) {
10732
+ logger.error("Bucket storage is not configured");
10733
+ logger.newLine();
10734
+ logger.admonition("tip", "Getting Started", [
10735
+ "Run `playcademy bucket init` to enable bucket storage"
10736
+ ]);
10737
+ logger.newLine();
10656
10738
  }
10657
- const config = await loadConfig();
10658
- if (!hasBucketSetup(config)) {
10739
+ process.exit(1);
10740
+ }
10741
+ const bucketDir = join32(getWorkspace(), CLI_DIRECTORIES.BUCKET);
10742
+ const mf = new Miniflare11({
10743
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
10744
+ r2Buckets: ["BUCKET"],
10745
+ r2Persist: bucketDir,
10746
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
10747
+ });
10748
+ try {
10749
+ const bucket = await mf.getR2Bucket("BUCKET");
10750
+ const object = await bucket.get(key);
10751
+ if (!object) {
10659
10752
  if (!options.raw && !options.json) {
10660
- logger.error("Bucket storage is not configured");
10753
+ logger.warn(`File '${key}' not found`);
10661
10754
  logger.newLine();
10662
- logger.admonition("tip", "Getting Started", [
10663
- "Run `playcademy bucket init` to enable bucket storage"
10755
+ logger.admonition("tip", "Hint", [
10756
+ "Use `playcademy bucket list` to see all available files"
10664
10757
  ]);
10665
10758
  logger.newLine();
10666
10759
  }
10667
10760
  process.exit(1);
10668
10761
  }
10669
- const bucketDir = join32(getWorkspace(), CLI_DIRECTORIES.BUCKET);
10670
- const mf = new Miniflare11({
10671
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
10672
- r2Buckets: ["BUCKET"],
10673
- r2Persist: bucketDir,
10674
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
10675
- });
10676
- try {
10677
- const bucket = await mf.getR2Bucket("BUCKET");
10678
- const object = await bucket.get(key);
10679
- if (!object) {
10680
- if (!options.raw && !options.json) {
10681
- logger.warn(`File '${key}' not found`);
10682
- logger.newLine();
10683
- logger.admonition("tip", "Hint", [
10684
- "Use `playcademy bucket list` to see all available files"
10685
- ]);
10686
- logger.newLine();
10687
- }
10688
- process.exit(1);
10689
- }
10690
- await bucket.delete(key);
10691
- if (options.json) {
10692
- logger.json({
10693
- success: true,
10694
- key,
10695
- message: "File deleted successfully"
10696
- });
10697
- return;
10698
- }
10699
- if (options.raw) {
10700
- logger.raw(`Deleted ${key}`);
10701
- return;
10702
- }
10703
- logger.success(`Deleted '${key}'`);
10762
+ await bucket.delete(key);
10763
+ if (options.json) {
10764
+ logger.json({
10765
+ success: true,
10766
+ key,
10767
+ message: "File deleted successfully"
10768
+ });
10769
+ return;
10770
+ }
10771
+ if (options.raw) {
10772
+ logger.raw(`Deleted ${key}`);
10773
+ return;
10774
+ }
10775
+ logger.success(`Deleted '${key}'`);
10776
+ logger.newLine();
10777
+ } finally {
10778
+ await mf.dispose();
10779
+ }
10780
+ }
10781
+ async function runBucketDelete(key, options = {}) {
10782
+ try {
10783
+ if (!options.raw && !options.json) {
10704
10784
  logger.newLine();
10705
- } finally {
10706
- await mf.dispose();
10785
+ }
10786
+ if (options.remote) {
10787
+ await runBucketDeleteRemote(key, options);
10788
+ } else {
10789
+ await runBucketDeleteLocal(key, options);
10707
10790
  }
10708
10791
  } catch (error) {
10709
10792
  if (!options.raw && !options.json) {
@@ -10721,106 +10804,167 @@ init_constants2();
10721
10804
  import { writeFileSync as writeFileSync10 } from "fs";
10722
10805
  import { join as join33 } from "path";
10723
10806
  import { Miniflare as Miniflare12 } from "miniflare";
10724
- async function runBucketGet(key, options = {}) {
10725
- try {
10807
+ async function runBucketGetRemote(key, options) {
10808
+ const environment = ensureEnvironment(options.env);
10809
+ const client = await requireAuthenticatedClient();
10810
+ const workspace = getWorkspace();
10811
+ const deployedGame = await getDeployedGame(workspace);
10812
+ if (!deployedGame) {
10726
10813
  if (!options.raw && !options.json) {
10814
+ logger.admonition("warning", "Deploy First", [
10815
+ `Deploy your game before accessing remote bucket: \`playcademy deploy\``
10816
+ ]);
10727
10817
  logger.newLine();
10728
10818
  }
10729
- if (options.remote) {
10819
+ process.exit(1);
10820
+ }
10821
+ const game = await client.games.fetch(deployedGame.gameId);
10822
+ let arrayBuffer;
10823
+ try {
10824
+ arrayBuffer = await client.dev.games.bucket.get(game.slug, key);
10825
+ } catch (error) {
10826
+ const errorMessage = error instanceof Error ? error.message : String(error);
10827
+ if (errorMessage.includes("not found")) {
10730
10828
  if (!options.raw && !options.json) {
10829
+ logger.warn(`File '${key}' not found in ${environment}`);
10731
10830
  logger.newLine();
10732
- logger.warn("Remote bucket operations are not yet implemented");
10733
- logger.newLine();
10734
- logger.admonition("info", "Coming Soon", [
10735
- "Remote bucket support is on the roadmap and will be available soon.",
10736
- "For now, bucket commands only work with local development storage."
10831
+ logger.admonition("note", "Hint", [
10832
+ `Use \`playcademy bucket list --remote\` to see all available files`
10737
10833
  ]);
10738
10834
  logger.newLine();
10739
10835
  }
10740
10836
  process.exit(1);
10741
10837
  }
10742
- if (!key) {
10838
+ throw error;
10839
+ }
10840
+ if (options.json) {
10841
+ logger.json({
10842
+ key,
10843
+ size: arrayBuffer.byteLength,
10844
+ message: "Use --output to save file"
10845
+ });
10846
+ return;
10847
+ }
10848
+ if (options.output) {
10849
+ writeFileSync10(options.output, Buffer.from(arrayBuffer));
10850
+ if (!options.raw) {
10851
+ logger.newLine();
10852
+ logger.success(`Downloaded '${key}' from ${environment} to '${options.output}'`);
10853
+ logger.newLine();
10854
+ logger.data("Size", `${arrayBuffer.byteLength} bytes`, 1);
10855
+ logger.newLine();
10856
+ }
10857
+ return;
10858
+ }
10859
+ if (options.raw) {
10860
+ process.stdout.write(Buffer.from(arrayBuffer));
10861
+ return;
10862
+ }
10863
+ logger.newLine();
10864
+ logger.success(`File: ${key}`);
10865
+ logger.newLine();
10866
+ logger.data("Size", `${arrayBuffer.byteLength} bytes`, 1);
10867
+ logger.data("Environment", environment, 1);
10868
+ logger.newLine();
10869
+ logger.admonition("tip", "Download File", [
10870
+ `Use \`playcademy bucket get ${key} --output path/to/file --remote\` to download`
10871
+ ]);
10872
+ logger.newLine();
10873
+ }
10874
+ async function runBucketGetLocal(key, options) {
10875
+ if (!key) {
10876
+ if (!options.raw && !options.json) {
10877
+ logger.error("File key is required");
10878
+ logger.newLine();
10879
+ logger.admonition("tip", "Usage", ["`playcademy bucket get <key> --output <file>`"]);
10880
+ logger.newLine();
10881
+ }
10882
+ process.exit(1);
10883
+ }
10884
+ const config = await loadConfig();
10885
+ if (!hasBucketSetup(config)) {
10886
+ if (!options.raw && !options.json) {
10887
+ logger.error("Bucket storage is not configured");
10888
+ logger.newLine();
10889
+ logger.admonition("tip", "Getting Started", [
10890
+ "Run `playcademy bucket init` to enable bucket storage"
10891
+ ]);
10892
+ logger.newLine();
10893
+ }
10894
+ process.exit(1);
10895
+ }
10896
+ const bucketDir = join33(getWorkspace(), CLI_DIRECTORIES.BUCKET);
10897
+ const mf = new Miniflare12({
10898
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
10899
+ r2Buckets: ["BUCKET"],
10900
+ r2Persist: bucketDir,
10901
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
10902
+ });
10903
+ try {
10904
+ const bucket = await mf.getR2Bucket("BUCKET");
10905
+ const object = await bucket.get(key);
10906
+ if (!object) {
10743
10907
  if (!options.raw && !options.json) {
10744
- logger.error("File key is required");
10908
+ logger.warn(`Failed to get object: File '${key}' not found`);
10745
10909
  logger.newLine();
10746
- logger.admonition("tip", "Usage", ["`playcademy bucket get <key> --output <file>`"]);
10910
+ logger.admonition("tip", "Hint", [
10911
+ "Use `playcademy bucket list` to see all available files"
10912
+ ]);
10747
10913
  logger.newLine();
10748
10914
  }
10749
10915
  process.exit(1);
10750
10916
  }
10751
- const config = await loadConfig();
10752
- if (!hasBucketSetup(config)) {
10753
- if (!options.raw && !options.json) {
10754
- logger.error("Bucket storage is not configured");
10917
+ if (options.json) {
10918
+ const metadata = {
10919
+ key: object.key,
10920
+ size: object.size,
10921
+ uploaded: object.uploaded.toISOString(),
10922
+ httpMetadata: object.httpMetadata,
10923
+ customMetadata: object.customMetadata
10924
+ };
10925
+ logger.json(metadata);
10926
+ return;
10927
+ }
10928
+ if (options.output) {
10929
+ const buffer = await object.arrayBuffer();
10930
+ writeFileSync10(options.output, Buffer.from(buffer));
10931
+ if (!options.raw) {
10932
+ logger.success(`Downloaded '${key}' to '${options.output}'`);
10755
10933
  logger.newLine();
10756
- logger.admonition("tip", "Getting Started", [
10757
- "Run `playcademy bucket init` to enable bucket storage"
10758
- ]);
10934
+ logger.data("Size", `${object.size} bytes`, 1);
10935
+ logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
10759
10936
  logger.newLine();
10760
10937
  }
10761
- process.exit(1);
10938
+ return;
10762
10939
  }
10763
- const bucketDir = join33(getWorkspace(), CLI_DIRECTORIES.BUCKET);
10764
- const mf = new Miniflare12({
10765
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
10766
- r2Buckets: ["BUCKET"],
10767
- r2Persist: bucketDir,
10768
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
10769
- });
10770
- try {
10771
- const bucket = await mf.getR2Bucket("BUCKET");
10772
- const object = await bucket.get(key);
10773
- if (!object) {
10774
- if (!options.raw && !options.json) {
10775
- logger.warn(`File '${key}' not found`);
10776
- logger.newLine();
10777
- logger.admonition("tip", "Hint", [
10778
- "Use `playcademy bucket list` to see all available files"
10779
- ]);
10780
- logger.newLine();
10781
- }
10782
- process.exit(1);
10783
- }
10784
- if (options.json) {
10785
- const metadata = {
10786
- key: object.key,
10787
- size: object.size,
10788
- uploaded: object.uploaded.toISOString(),
10789
- httpMetadata: object.httpMetadata,
10790
- customMetadata: object.customMetadata
10791
- };
10792
- logger.json(metadata);
10793
- return;
10794
- }
10795
- if (options.output) {
10796
- const buffer = await object.arrayBuffer();
10797
- writeFileSync10(options.output, Buffer.from(buffer));
10798
- if (!options.raw) {
10799
- logger.success(`Downloaded '${key}' to '${options.output}'`);
10800
- logger.newLine();
10801
- logger.data("Size", `${object.size} bytes`, 1);
10802
- logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
10803
- logger.newLine();
10804
- }
10805
- return;
10806
- }
10807
- if (options.raw) {
10808
- const text5 = await object.text();
10809
- logger.raw(text5);
10810
- return;
10811
- }
10812
- logger.success(`File: ${key}`);
10813
- logger.newLine();
10814
- logger.data("Size", `${object.size} bytes`, 1);
10815
- logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
10816
- logger.data("Uploaded", new Date(object.uploaded).toLocaleString(), 1);
10817
- logger.newLine();
10818
- logger.admonition("tip", "Download File", [
10819
- `Use \`playcademy bucket get ${key} --output <file>\` to download`
10820
- ]);
10940
+ if (options.raw) {
10941
+ const text5 = await object.text();
10942
+ logger.raw(text5);
10943
+ return;
10944
+ }
10945
+ logger.success(`File: ${key}`);
10946
+ logger.newLine();
10947
+ logger.data("Size", `${object.size} bytes`, 1);
10948
+ logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
10949
+ logger.data("Uploaded", new Date(object.uploaded).toLocaleString(), 1);
10950
+ logger.newLine();
10951
+ logger.admonition("tip", "Download File", [
10952
+ `Use \`playcademy bucket get ${key} --output <file>\` to download`
10953
+ ]);
10954
+ logger.newLine();
10955
+ } finally {
10956
+ await mf.dispose();
10957
+ }
10958
+ }
10959
+ async function runBucketGet(key, options = {}) {
10960
+ try {
10961
+ if (!options.raw && !options.json) {
10821
10962
  logger.newLine();
10822
- } finally {
10823
- await mf.dispose();
10963
+ }
10964
+ if (options.remote) {
10965
+ await runBucketGetRemote(key, options);
10966
+ } else {
10967
+ await runBucketGetLocal(key, options);
10824
10968
  }
10825
10969
  } catch (error) {
10826
10970
  if (!options.raw && !options.json) {
@@ -10911,92 +11055,138 @@ async function runBucketInit() {
10911
11055
  init_constants2();
10912
11056
  import { join as join34 } from "path";
10913
11057
  import { Miniflare as Miniflare13 } from "miniflare";
10914
- async function runBucketList(options = {}) {
10915
- try {
11058
+ async function runBucketListRemote(options) {
11059
+ const environment = ensureEnvironment(options.env);
11060
+ const client = await requireAuthenticatedClient();
11061
+ const workspace = getWorkspace();
11062
+ const deployedGame = await getDeployedGame(workspace);
11063
+ if (!deployedGame) {
10916
11064
  if (!options.raw && !options.json) {
11065
+ logger.admonition("warning", "Deploy First", [
11066
+ `Deploy your game before accessing remote bucket: \`playcademy deploy\``
11067
+ ]);
10917
11068
  logger.newLine();
10918
11069
  }
10919
- if (options.remote) {
10920
- if (!options.raw && !options.json) {
10921
- logger.newLine();
10922
- logger.warn("Remote bucket operations are not yet implemented");
10923
- logger.newLine();
10924
- logger.admonition("info", "Coming Soon", [
10925
- "Remote bucket support is on the roadmap and will be available soon.",
10926
- "For now, bucket commands only work with local development storage."
10927
- ]);
10928
- logger.newLine();
10929
- }
10930
- process.exit(1);
11070
+ process.exit(1);
11071
+ }
11072
+ const game = await client.games.fetch(deployedGame.gameId);
11073
+ const files = await client.dev.games.bucket.list(game.slug, options.prefix);
11074
+ if (options.json) {
11075
+ logger.json(files);
11076
+ return;
11077
+ }
11078
+ if (options.raw) {
11079
+ for (const file of files) {
11080
+ logger.raw(file.key);
10931
11081
  }
10932
- const config = await loadConfig();
10933
- if (!hasBucketSetup(config)) {
10934
- if (!options.raw && !options.json) {
10935
- logger.error("Bucket storage is not configured");
10936
- logger.newLine();
10937
- logger.admonition("tip", "Getting Started", [
10938
- "Run `playcademy bucket init` to enable bucket storage"
10939
- ]);
10940
- logger.newLine();
10941
- }
10942
- process.exit(1);
11082
+ return;
11083
+ }
11084
+ if (!options.raw && !options.json) {
11085
+ logger.newLine();
11086
+ }
11087
+ if (files.length === 0) {
11088
+ logger.remark("No files found in remote bucket");
11089
+ if (options.prefix) {
11090
+ logger.newLine();
11091
+ logger.data("Prefix", options.prefix, 1);
10943
11092
  }
10944
- const bucketDir = join34(getWorkspace(), CLI_DIRECTORIES.BUCKET);
10945
- const mf = new Miniflare13({
10946
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
10947
- r2Buckets: ["BUCKET"],
10948
- r2Persist: bucketDir,
10949
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
10950
- });
10951
- try {
10952
- const bucket = await mf.getR2Bucket("BUCKET");
10953
- const listed = await bucket.list({ prefix: options.prefix });
10954
- const files = listed.objects;
10955
- if (options.json) {
10956
- const fileData = files.map((obj) => ({
10957
- key: obj.key,
10958
- size: obj.size,
10959
- uploaded: obj.uploaded.toISOString()
10960
- }));
10961
- logger.json(fileData);
10962
- return;
10963
- }
10964
- if (options.raw) {
10965
- for (const file of files) {
10966
- logger.raw(file.key);
10967
- }
10968
- return;
10969
- }
10970
- if (files.length === 0) {
10971
- logger.remark("No files found in bucket");
10972
- if (options.prefix) {
10973
- logger.newLine();
10974
- logger.data("Prefix", options.prefix, 1);
10975
- }
10976
- logger.newLine();
10977
- return;
11093
+ logger.newLine();
11094
+ return;
11095
+ }
11096
+ logger.success(`Found ${files.length} file${files.length === 1 ? "" : "s"} in ${environment}`);
11097
+ if (options.prefix) {
11098
+ logger.data("Prefix", options.prefix, 1);
11099
+ }
11100
+ logger.newLine();
11101
+ logger.table(
11102
+ files.map((file) => ({
11103
+ Key: file.key,
11104
+ Size: formatBytes(file.size),
11105
+ Uploaded: new Date(file.uploaded).toLocaleString()
11106
+ }))
11107
+ );
11108
+ logger.newLine();
11109
+ }
11110
+ async function runBucketListLocal(options) {
11111
+ const config = await loadConfig();
11112
+ if (!hasBucketSetup(config)) {
11113
+ if (!options.raw && !options.json) {
11114
+ logger.error("Bucket storage is not configured");
11115
+ logger.newLine();
11116
+ logger.admonition("tip", "Getting Started", [
11117
+ "Run `playcademy bucket init` to enable bucket storage"
11118
+ ]);
11119
+ logger.newLine();
11120
+ }
11121
+ process.exit(1);
11122
+ }
11123
+ const bucketDir = join34(getWorkspace(), CLI_DIRECTORIES.BUCKET);
11124
+ const mf = new Miniflare13({
11125
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11126
+ r2Buckets: ["BUCKET"],
11127
+ r2Persist: bucketDir,
11128
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11129
+ });
11130
+ try {
11131
+ const bucket = await mf.getR2Bucket("BUCKET");
11132
+ const listed = await bucket.list({ prefix: options.prefix });
11133
+ const files = listed.objects;
11134
+ if (options.json) {
11135
+ const fileData = files.map((obj) => ({
11136
+ key: obj.key,
11137
+ size: obj.size,
11138
+ uploaded: obj.uploaded.toISOString()
11139
+ }));
11140
+ logger.json(fileData);
11141
+ return;
11142
+ }
11143
+ if (options.raw) {
11144
+ for (const file of files) {
11145
+ logger.raw(file.key);
10978
11146
  }
10979
- logger.success(`Found ${files.length} file${files.length === 1 ? "" : "s"}`);
11147
+ return;
11148
+ }
11149
+ if (files.length === 0) {
11150
+ logger.remark("No files found in bucket");
10980
11151
  if (options.prefix) {
11152
+ logger.newLine();
10981
11153
  logger.data("Prefix", options.prefix, 1);
10982
11154
  }
10983
11155
  logger.newLine();
10984
- logger.table(
10985
- files.map((obj) => ({
10986
- Key: obj.key,
10987
- Size: formatBytes(obj.size),
10988
- Uploaded: new Date(obj.uploaded).toLocaleString()
10989
- }))
10990
- );
11156
+ return;
11157
+ }
11158
+ logger.success(`Found ${files.length} file${files.length === 1 ? "" : "s"}`);
11159
+ if (options.prefix) {
11160
+ logger.data("Prefix", options.prefix, 1);
11161
+ }
11162
+ logger.newLine();
11163
+ logger.table(
11164
+ files.map((obj) => ({
11165
+ Key: obj.key,
11166
+ Size: formatBytes(obj.size),
11167
+ Uploaded: new Date(obj.uploaded).toLocaleString()
11168
+ }))
11169
+ );
11170
+ logger.newLine();
11171
+ if (listed.truncated) {
11172
+ logger.admonition("info", "Truncated Results", [
11173
+ "The list was truncated. Use --prefix to narrow down results."
11174
+ ]);
11175
+ logger.newLine();
11176
+ }
11177
+ } finally {
11178
+ await mf.dispose();
11179
+ }
11180
+ }
11181
+ async function runBucketList(options = {}) {
11182
+ try {
11183
+ if (!options.raw && !options.json) {
10991
11184
  logger.newLine();
10992
- if (listed.truncated) {
10993
- logger.admonition("info", "Truncated Results", [
10994
- "The list was truncated. Use --prefix to narrow down results."
10995
- ]);
10996
- logger.newLine();
10997
- }
10998
- } finally {
10999
- await mf.dispose();
11185
+ }
11186
+ if (options.remote) {
11187
+ await runBucketListRemote(options);
11188
+ } else {
11189
+ await runBucketListLocal(options);
11000
11190
  }
11001
11191
  } catch (error) {
11002
11192
  if (!options.raw && !options.json) {
@@ -11021,91 +11211,134 @@ init_constants2();
11021
11211
  import { readFileSync as readFileSync8, statSync as statSync2 } from "fs";
11022
11212
  import { join as join35 } from "path";
11023
11213
  import { Miniflare as Miniflare14 } from "miniflare";
11024
- async function runBucketPut(key, filePath, options = {}) {
11214
+ async function runBucketPutRemote(key, filePath, options) {
11215
+ const environment = ensureEnvironment(options.env);
11216
+ const client = await requireAuthenticatedClient();
11217
+ const workspace = getWorkspace();
11218
+ const deployedGame = await getDeployedGame(workspace);
11219
+ if (!deployedGame) {
11220
+ if (!options.raw && !options.json) {
11221
+ logger.admonition("warning", "Deploy First", [
11222
+ `Deploy your game before accessing remote bucket: \`playcademy deploy\``
11223
+ ]);
11224
+ logger.newLine();
11225
+ }
11226
+ process.exit(1);
11227
+ }
11228
+ let fileBuffer;
11229
+ let fileSize;
11025
11230
  try {
11231
+ fileBuffer = readFileSync8(filePath);
11232
+ fileSize = statSync2(filePath).size;
11233
+ } catch {
11026
11234
  if (!options.raw && !options.json) {
11235
+ logger.error(`File not found: ${filePath}`);
11027
11236
  logger.newLine();
11028
11237
  }
11029
- if (options.remote) {
11030
- if (!options.raw && !options.json) {
11031
- logger.newLine();
11032
- logger.warn("Remote bucket operations are not yet implemented");
11033
- logger.newLine();
11034
- logger.admonition("info", "Coming Soon", [
11035
- "Remote bucket support is on the roadmap and will be available soon.",
11036
- "For now, bucket commands only work with local development storage."
11037
- ]);
11038
- logger.newLine();
11039
- }
11040
- process.exit(1);
11238
+ process.exit(1);
11239
+ }
11240
+ const game = await client.games.fetch(deployedGame.gameId);
11241
+ const contentType = getContentType(filePath);
11242
+ await client.dev.games.bucket.put(game.slug, key, fileBuffer, contentType);
11243
+ if (options.json) {
11244
+ logger.json({
11245
+ success: true,
11246
+ key,
11247
+ size: fileSize,
11248
+ uploaded: (/* @__PURE__ */ new Date()).toISOString()
11249
+ });
11250
+ return;
11251
+ }
11252
+ if (options.raw) {
11253
+ logger.raw(`Uploaded ${key}`);
11254
+ return;
11255
+ }
11256
+ logger.newLine();
11257
+ logger.success(`Uploaded '${filePath}' to '${key}' in ${environment}`);
11258
+ logger.newLine();
11259
+ logger.data("Size", `${fileSize} bytes`, 1);
11260
+ logger.data("Content-Type", contentType, 1);
11261
+ logger.newLine();
11262
+ }
11263
+ async function runBucketPutLocal(key, filePath, options) {
11264
+ if (!key || !filePath) {
11265
+ if (!options.raw && !options.json) {
11266
+ logger.error("File key and path are required");
11267
+ logger.newLine();
11268
+ logger.admonition("tip", "Usage", ["`playcademy bucket put <key> <file>`"]);
11269
+ logger.newLine();
11041
11270
  }
11042
- if (!key || !filePath) {
11043
- if (!options.raw && !options.json) {
11044
- logger.error("File key and path are required");
11045
- logger.newLine();
11046
- logger.admonition("tip", "Usage", ["`playcademy bucket put <key> <file>`"]);
11047
- logger.newLine();
11048
- }
11049
- process.exit(1);
11271
+ process.exit(1);
11272
+ }
11273
+ const config = await loadConfig();
11274
+ if (!hasBucketSetup(config)) {
11275
+ if (!options.raw && !options.json) {
11276
+ logger.error("Bucket storage is not configured");
11277
+ logger.newLine();
11278
+ logger.admonition("tip", "Getting Started", [
11279
+ "Run `playcademy bucket init` to enable bucket storage"
11280
+ ]);
11281
+ logger.newLine();
11050
11282
  }
11051
- const config = await loadConfig();
11052
- if (!hasBucketSetup(config)) {
11053
- if (!options.raw && !options.json) {
11054
- logger.error("Bucket storage is not configured");
11055
- logger.newLine();
11056
- logger.admonition("tip", "Getting Started", [
11057
- "Run `playcademy bucket init` to enable bucket storage"
11058
- ]);
11059
- logger.newLine();
11060
- }
11061
- process.exit(1);
11283
+ process.exit(1);
11284
+ }
11285
+ let fileBuffer;
11286
+ let fileSize;
11287
+ try {
11288
+ fileBuffer = readFileSync8(filePath);
11289
+ fileSize = statSync2(filePath).size;
11290
+ } catch {
11291
+ if (!options.raw && !options.json) {
11292
+ logger.error(`File not found: ${filePath}`);
11293
+ logger.newLine();
11062
11294
  }
11063
- let fileBuffer;
11064
- let fileSize;
11065
- try {
11066
- fileBuffer = readFileSync8(filePath);
11067
- fileSize = statSync2(filePath).size;
11068
- } catch {
11069
- if (!options.raw && !options.json) {
11070
- logger.error(`File not found: ${filePath}`);
11071
- logger.newLine();
11295
+ process.exit(1);
11296
+ }
11297
+ const bucketDir = join35(getWorkspace(), CLI_DIRECTORIES.BUCKET);
11298
+ const mf = new Miniflare14({
11299
+ modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11300
+ r2Buckets: ["BUCKET"],
11301
+ r2Persist: bucketDir,
11302
+ compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11303
+ });
11304
+ try {
11305
+ const bucket = await mf.getR2Bucket("BUCKET");
11306
+ await bucket.put(key, new Uint8Array(fileBuffer).buffer, {
11307
+ httpMetadata: {
11308
+ contentType: getContentType(filePath)
11072
11309
  }
11073
- process.exit(1);
11074
- }
11075
- const bucketDir = join35(getWorkspace(), CLI_DIRECTORIES.BUCKET);
11076
- const mf = new Miniflare14({
11077
- modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
11078
- r2Buckets: ["BUCKET"],
11079
- r2Persist: bucketDir,
11080
- compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
11081
11310
  });
11082
- try {
11083
- const bucket = await mf.getR2Bucket("BUCKET");
11084
- await bucket.put(key, new Uint8Array(fileBuffer).buffer, {
11085
- httpMetadata: {
11086
- contentType: getContentType(filePath)
11087
- }
11311
+ if (options.json) {
11312
+ logger.json({
11313
+ success: true,
11314
+ key,
11315
+ size: fileSize,
11316
+ uploaded: (/* @__PURE__ */ new Date()).toISOString()
11088
11317
  });
11089
- if (options.json) {
11090
- logger.json({
11091
- success: true,
11092
- key,
11093
- size: fileSize,
11094
- uploaded: (/* @__PURE__ */ new Date()).toISOString()
11095
- });
11096
- return;
11097
- }
11098
- if (options.raw) {
11099
- logger.raw(`Uploaded ${key}`);
11100
- return;
11101
- }
11102
- logger.success(`Uploaded '${filePath}' to '${key}'`);
11103
- logger.newLine();
11104
- logger.data("Size", `${fileSize} bytes`, 1);
11105
- logger.data("Content-Type", getContentType(filePath), 1);
11318
+ return;
11319
+ }
11320
+ if (options.raw) {
11321
+ logger.raw(`Uploaded ${key}`);
11322
+ return;
11323
+ }
11324
+ logger.success(`Uploaded '${filePath}' to '${key}'`);
11325
+ logger.newLine();
11326
+ logger.data("Size", `${fileSize} bytes`, 1);
11327
+ logger.data("Content-Type", getContentType(filePath), 1);
11328
+ logger.newLine();
11329
+ } finally {
11330
+ await mf.dispose();
11331
+ }
11332
+ }
11333
+ async function runBucketPut(key, filePath, options = {}) {
11334
+ try {
11335
+ if (!options.raw && !options.json) {
11106
11336
  logger.newLine();
11107
- } finally {
11108
- await mf.dispose();
11337
+ }
11338
+ if (options.remote) {
11339
+ await runBucketPutRemote(key, filePath, options);
11340
+ } else {
11341
+ await runBucketPutLocal(key, filePath, options);
11109
11342
  }
11110
11343
  } catch (error) {
11111
11344
  if (!options.raw && !options.json) {
@@ -11117,29 +11350,6 @@ async function runBucketPut(key, filePath, options = {}) {
11117
11350
  process.exit(1);
11118
11351
  }
11119
11352
  }
11120
- function getContentType(filePath) {
11121
- const ext = filePath.split(".").pop()?.toLowerCase();
11122
- const types = {
11123
- jpg: "image/jpeg",
11124
- jpeg: "image/jpeg",
11125
- png: "image/png",
11126
- gif: "image/gif",
11127
- webp: "image/webp",
11128
- svg: "image/svg+xml",
11129
- mp3: "audio/mpeg",
11130
- wav: "audio/wav",
11131
- ogg: "audio/ogg",
11132
- mp4: "video/mp4",
11133
- webm: "video/webm",
11134
- pdf: "application/pdf",
11135
- json: "application/json",
11136
- txt: "text/plain",
11137
- html: "text/html",
11138
- css: "text/css",
11139
- js: "application/javascript"
11140
- };
11141
- return types[ext || ""] || "application/octet-stream";
11142
- }
11143
11353
 
11144
11354
  // src/commands/bucket/index.ts
11145
11355
  var bucketCommand = new Command16("bucket").description("Manage bucket storage integration").action(() => {
@@ -12003,6 +12213,7 @@ export {
12003
12213
  getBestUnit,
12004
12214
  getCallbackUrl,
12005
12215
  getCliContext,
12216
+ getContentType,
12006
12217
  getCurrentProfile,
12007
12218
  getCustomRoutesDirectory,
12008
12219
  getCustomRoutesHash,
package/dist/utils.js CHANGED
@@ -1292,6 +1292,13 @@ var init_import = __esm({
1292
1292
  }
1293
1293
  });
1294
1294
 
1295
+ // src/lib/core/mime.ts
1296
+ var init_mime2 = __esm({
1297
+ "src/lib/core/mime.ts"() {
1298
+ "use strict";
1299
+ }
1300
+ });
1301
+
1295
1302
  // src/lib/core/index.ts
1296
1303
  var init_core = __esm({
1297
1304
  "src/lib/core/index.ts"() {
@@ -1303,6 +1310,7 @@ var init_core = __esm({
1303
1310
  init_game();
1304
1311
  init_import();
1305
1312
  init_logger();
1313
+ init_mime2();
1306
1314
  }
1307
1315
  });
1308
1316
 
@@ -1434,6 +1442,9 @@ var isDevelopment = () => {
1434
1442
  var isInteractiveTTY = () => {
1435
1443
  return typeof process !== "undefined" && Boolean(process.stdout && process.stdout.isTTY);
1436
1444
  };
1445
+ var isSilent = () => {
1446
+ return typeof process !== "undefined" && process.env.LOG_SILENT === "true";
1447
+ };
1437
1448
  var detectOutputFormat = () => {
1438
1449
  if (isBrowser()) {
1439
1450
  return "browser";
@@ -1554,6 +1565,7 @@ var getMinimumLogLevel = () => {
1554
1565
  return isProduction() ? "info" : "debug";
1555
1566
  };
1556
1567
  var shouldLog = (level) => {
1568
+ if (isSilent()) return false;
1557
1569
  const minLevel = getMinimumLogLevel();
1558
1570
  return levelPriority[level] >= levelPriority[minLevel];
1559
1571
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playcademy",
3
- "version": "0.13.22",
3
+ "version": "0.13.23",
4
4
  "type": "module",
5
5
  "module": "./dist/index.js",
6
6
  "main": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@inquirer/prompts": "^7.8.6",
43
- "@playcademy/sdk": "0.1.10",
43
+ "@playcademy/sdk": "0.1.11",
44
44
  "better-sqlite3": "^12.4.1",
45
45
  "chokidar": "^4.0.3",
46
46
  "colorette": "^2.0.20",