playcademy 0.14.14 → 0.14.16

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
@@ -690,7 +690,14 @@ interface DeployedGameInfo {
690
690
  deployedSecrets?: string[];
691
691
  }
692
692
  interface GameStore {
693
- [projectPath: string]: DeployedGameInfo;
693
+ /** Staging environment game deployments, keyed by absolute project path */
694
+ staging: {
695
+ [projectPath: string]: DeployedGameInfo;
696
+ };
697
+ /** Production environment game deployments, keyed by absolute project path */
698
+ production: {
699
+ [projectPath: string]: DeployedGameInfo;
700
+ };
694
701
  }
695
702
  /**
696
703
  * Deployment context containing all information needed for deployment
package/dist/index.js CHANGED
@@ -7222,7 +7222,7 @@ import { join as join18 } from "path";
7222
7222
  // package.json
7223
7223
  var package_default2 = {
7224
7224
  name: "playcademy",
7225
- version: "0.14.13",
7225
+ version: "0.14.15",
7226
7226
  type: "module",
7227
7227
  exports: {
7228
7228
  ".": {
@@ -8980,6 +8980,7 @@ init_context();
8980
8980
 
8981
8981
  // src/lib/games/storage.ts
8982
8982
  init_constants2();
8983
+ init_config2();
8983
8984
  import { existsSync as existsSync19 } from "node:fs";
8984
8985
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
8985
8986
  import { homedir as homedir2 } from "node:os";
@@ -8997,33 +8998,82 @@ async function loadGameStore() {
8997
8998
  const storePath = getGamesStorePath();
8998
8999
  if (existsSync19(storePath)) {
8999
9000
  const content = await readFile3(storePath, "utf-8");
9000
- return JSON.parse(content);
9001
+ const parsed = JSON.parse(content);
9002
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
9003
+ return { staging: {}, production: {} };
9004
+ }
9005
+ const parsedObj = parsed;
9006
+ if (!("staging" in parsedObj) && !("production" in parsedObj)) {
9007
+ const entries = Object.entries(parsedObj);
9008
+ const looksValidLegacy = entries.every(
9009
+ ([, v]) => v !== null && typeof v === "object" && !Array.isArray(v)
9010
+ );
9011
+ if (!looksValidLegacy) {
9012
+ return { staging: {}, production: {} };
9013
+ }
9014
+ const migrated = { staging: {}, production: {} };
9015
+ for (const [key, value] of entries) {
9016
+ const info = value;
9017
+ if (typeof key === "string" && key.includes(":")) {
9018
+ const idx = key.lastIndexOf(":");
9019
+ const basePath = key.slice(0, idx);
9020
+ const envSuffix = key.slice(idx + 1);
9021
+ if (envSuffix === "staging") {
9022
+ migrated.staging[basePath] = info;
9023
+ continue;
9024
+ }
9025
+ if (envSuffix === "production") {
9026
+ migrated.production[basePath] = info;
9027
+ continue;
9028
+ }
9029
+ }
9030
+ migrated.staging[key] = info;
9031
+ }
9032
+ await saveGameStore(migrated);
9033
+ return migrated;
9034
+ }
9035
+ const store = parsedObj;
9036
+ return {
9037
+ staging: store.staging ?? {},
9038
+ production: store.production ?? {}
9039
+ };
9001
9040
  }
9002
9041
  } catch {
9003
9042
  }
9004
- return {};
9043
+ return {
9044
+ staging: {},
9045
+ production: {}
9046
+ };
9005
9047
  }
9006
9048
  async function saveGameStore(store) {
9007
9049
  await ensureConfigDir();
9008
9050
  const storePath = getGamesStorePath();
9009
9051
  await writeFile3(storePath, JSON.stringify(store, null, 2), "utf-8");
9010
9052
  }
9011
- async function getDeployedGame(projectPath) {
9053
+ async function getDeployedGame(projectPath, environment) {
9012
9054
  const store = await loadGameStore();
9013
- return store[projectPath] || null;
9055
+ const env = environment ?? getEnvironment();
9056
+ const bucket = env === "production" ? store.production : store.staging;
9057
+ return bucket[projectPath] || null;
9014
9058
  }
9015
- async function saveDeployedGame(projectPath, gameInfo) {
9059
+ async function saveDeployedGame(projectPath, gameInfo, environment) {
9016
9060
  const store = await loadGameStore();
9017
- store[projectPath] = {
9018
- ...store[projectPath],
9061
+ const env = environment ?? getEnvironment();
9062
+ const bucket = env === "production" ? store.production : store.staging;
9063
+ bucket[projectPath] = {
9064
+ ...bucket[projectPath],
9019
9065
  ...gameInfo
9020
9066
  };
9021
9067
  await saveGameStore(store);
9022
9068
  }
9023
- async function removeDeployedGame(projectPath) {
9069
+ async function removeDeployedGame(projectPath, environment) {
9024
9070
  const store = await loadGameStore();
9025
- delete store[projectPath];
9026
- await saveGameStore(store);
9071
+ const env = environment ?? getEnvironment();
9072
+ const bucket = env === "production" ? store.production : store.staging;
9073
+ if (bucket[projectPath]) {
9074
+ delete bucket[projectPath];
9075
+ await saveGameStore(store);
9076
+ }
9027
9077
  }
9028
9078
  async function saveDeploymentState(game, backendMetadata, context2) {
9029
9079
  const { projectPath, buildHash, buildSize, config, fullConfig } = context2;
@@ -9083,6 +9133,7 @@ async function saveDeploymentState(game, backendMetadata, context2) {
9083
9133
 
9084
9134
  // src/lib/deploy/secrets.ts
9085
9135
  init_core();
9136
+ import { ApiError as ApiError2 } from "@playcademy/sdk";
9086
9137
  function compareSecrets(current, previous) {
9087
9138
  const currentKeys = Object.keys(current);
9088
9139
  const changes = [];
@@ -9108,6 +9159,10 @@ async function fetchSecretsForDeployment(slug) {
9108
9159
  const keys = Object.keys(secrets);
9109
9160
  return { secrets, keys };
9110
9161
  } catch (error) {
9162
+ if (error instanceof ApiError2 && error.status === 404) {
9163
+ logger.debug(`[Secrets] No secrets configured for game (404)`);
9164
+ return { secrets: {}, keys: [] };
9165
+ }
9111
9166
  logger.warn(
9112
9167
  `Could not fetch secrets: ${error instanceof Error ? error.message : String(error)}`
9113
9168
  );
@@ -9153,13 +9208,21 @@ async function prepareDeploymentContext(options) {
9153
9208
  const projectPath = getWorkspace();
9154
9209
  const deployedGameInfo = await getDeployedGame(projectPath);
9155
9210
  let existingGame;
9211
+ const existingGames = await client.games.list({ force: true });
9156
9212
  if (deployedGameInfo) {
9157
- const existingGames = await client.games.list({ force: true });
9158
9213
  existingGame = existingGames.find((g) => g.id === deployedGameInfo.gameId);
9159
- } else if (finalConfig.slug) {
9160
- const existingGames = await client.games.list({ force: true });
9214
+ }
9215
+ if (!existingGame && finalConfig.slug) {
9161
9216
  existingGame = existingGames.find((g) => g.slug === finalConfig.slug);
9162
9217
  }
9218
+ if (existingGame) {
9219
+ const currentUser = await client.users.me();
9220
+ const isAdmin = currentUser.role === "admin";
9221
+ const isOwner = existingGame.developerId === currentUser.id;
9222
+ if (!isAdmin && !isOwner) {
9223
+ throw new Error(`Unable to deploy '${existingGame.slug}': You do not own this game`);
9224
+ }
9225
+ }
9163
9226
  const gameIsDeployed = existingGame ? isGameDeployed(existingGame) : false;
9164
9227
  if (existingGame && gameIsDeployed) {
9165
9228
  finalConfig.slug = existingGame.slug;
package/dist/utils.js CHANGED
@@ -3863,7 +3863,7 @@ import { join as join11 } from "path";
3863
3863
  // package.json
3864
3864
  var package_default2 = {
3865
3865
  name: "playcademy",
3866
- version: "0.14.13",
3866
+ version: "0.14.15",
3867
3867
  type: "module",
3868
3868
  exports: {
3869
3869
  ".": {
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "playcademy",
4
- version: "0.14.13",
4
+ version: "0.14.15",
5
5
  type: "module",
6
6
  exports: {
7
7
  ".": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playcademy",
3
- "version": "0.14.14",
3
+ "version": "0.14.16",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {