playcademy 0.8.0 → 0.10.0

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
@@ -6261,7 +6261,8 @@ var formatLog = (level, message, context2) => {
6261
6261
  return JSON.stringify(logEntry);
6262
6262
  };
6263
6263
  var performLog = (level, message, context2) => {
6264
- if (level === "debug" && false) {
6264
+ if (level === "debug" && process.env.PLAYCADEMY_EMBEDDED) {
6265
+ return;
6265
6266
  }
6266
6267
  if (isBrowser()) {
6267
6268
  logInBrowser(level, message, context2);
@@ -8943,6 +8944,31 @@ function createNotificationsNamespace(client) {
8943
8944
  }
8944
8945
  var init_notifications = () => {
8945
8946
  };
8947
+ function createBackendNamespace(client) {
8948
+ function normalizePath(path) {
8949
+ return path.startsWith("/") ? path : `/${path}`;
8950
+ }
8951
+ return {
8952
+ async get(path, headers) {
8953
+ return client["requestGameBackend"](normalizePath(path), "GET", void 0, headers);
8954
+ },
8955
+ async post(path, body, headers) {
8956
+ return client["requestGameBackend"](normalizePath(path), "POST", body, headers);
8957
+ },
8958
+ async put(path, body, headers) {
8959
+ return client["requestGameBackend"](normalizePath(path), "PUT", body, headers);
8960
+ },
8961
+ async patch(path, body, headers) {
8962
+ return client["requestGameBackend"](normalizePath(path), "PATCH", body, headers);
8963
+ },
8964
+ async delete(path, headers) {
8965
+ return client["requestGameBackend"](normalizePath(path), "DELETE", void 0, headers);
8966
+ },
8967
+ async request(path, method, body, headers) {
8968
+ return client["requestGameBackend"](normalizePath(path), method, body, headers);
8969
+ }
8970
+ };
8971
+ }
8946
8972
  var init_namespaces = __esm2(() => {
8947
8973
  init_identity();
8948
8974
  init_runtime();
@@ -8982,6 +9008,9 @@ function buildAllowedOrigins(explicit) {
8982
9008
  return ref ? [ref] : [];
8983
9009
  }
8984
9010
  function isOriginAllowed(origin, allowlist) {
9011
+ if (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1") {
9012
+ return true;
9013
+ }
8985
9014
  if (!allowlist || allowlist.length === 0) {
8986
9015
  console.error("[Playcademy SDK] No allowed origins configured. Consider passing allowedParentOrigins explicitly to init().");
8987
9016
  return false;
@@ -9254,6 +9283,7 @@ var init_client = __esm2(() => {
9254
9283
  realtime = createRealtimeNamespace(this);
9255
9284
  achievements = createAchievementsNamespace(this);
9256
9285
  notifications = createNotificationsNamespace(this);
9286
+ backend = createBackendNamespace(this);
9257
9287
  static init = init;
9258
9288
  static login = login2;
9259
9289
  static identity = identity;
@@ -9280,9 +9310,40 @@ function customTransform(text2) {
9280
9310
  const highlightCode = (text3) => text3.replace(/`([^`]+)`/g, (_, code) => greenBright(code));
9281
9311
  return highlightCode(text2);
9282
9312
  }
9313
+ function formatTable(data, title) {
9314
+ if (data.length === 0) return;
9315
+ const keys = Object.keys(data[0]);
9316
+ const rows = data.map((item) => keys.map((key) => String(item[key] ?? "")));
9317
+ const widths = keys.map((key, i) => {
9318
+ const headerWidth = key.length;
9319
+ const dataWidth = Math.max(...rows.map((row) => row[i].length));
9320
+ return Math.max(headerWidth, dataWidth);
9321
+ });
9322
+ const totalWidth = widths.reduce((sum, w) => sum + w + 3, -1);
9323
+ const separator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u253C") + "\u2524";
9324
+ const topBorder = "\u250C" + "\u2500".repeat(totalWidth) + "\u2510";
9325
+ const titleSeparator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C") + "\u2524";
9326
+ const bottomBorder = "\u2514" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u2534") + "\u2518";
9327
+ console.log(topBorder);
9328
+ if (title) {
9329
+ const titleText = bold(title);
9330
+ const titlePadding = totalWidth - title.length - 1;
9331
+ const titleRow = "\u2502 " + titleText + " ".repeat(titlePadding) + "\u2502";
9332
+ console.log(titleRow);
9333
+ console.log(titleSeparator);
9334
+ }
9335
+ const header = "\u2502 " + keys.map((key, i) => key.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
9336
+ console.log(header);
9337
+ console.log(separator);
9338
+ rows.forEach((row) => {
9339
+ const dataRow = "\u2502 " + row.map((cell, i) => cell.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
9340
+ console.log(dataRow);
9341
+ });
9342
+ console.log(bottomBorder);
9343
+ }
9283
9344
  var logger = {
9284
- table: (data) => {
9285
- console.table(data);
9345
+ table: (data, title) => {
9346
+ formatTable(data, title);
9286
9347
  },
9287
9348
  /**
9288
9349
  * Info message - general information
@@ -10460,7 +10521,7 @@ async function confirmDeploymentPlan(plan, context2) {
10460
10521
  import { join as join6 } from "node:path";
10461
10522
  import { blueBright, underline } from "colorette";
10462
10523
  function displayCurrentConfiguration(context2) {
10463
- const { config, existingGame } = context2;
10524
+ const { config } = context2;
10464
10525
  logger.newLine();
10465
10526
  logger.highlight("Current Configuration:");
10466
10527
  logger.newLine();
@@ -10482,10 +10543,8 @@ function displayCurrentConfiguration(context2) {
10482
10543
  }
10483
10544
  if (context2.isGameDeployed) {
10484
10545
  logger.data("Status", "Deployed", 1);
10485
- } else if (existingGame) {
10486
- logger.data("Status", "Not deployed", 1);
10487
10546
  } else {
10488
- logger.data("Status", "New deployment", 1);
10547
+ logger.data("Status", "Not deployed", 1);
10489
10548
  }
10490
10549
  logger.newLine();
10491
10550
  }
@@ -10911,7 +10970,7 @@ function displayRegisteredRoutes(integrations, customRoutes = []) {
10911
10970
  // src/lib/dev/reload.ts
10912
10971
  import { join as join9 } from "path";
10913
10972
  import chokidar from "chokidar";
10914
- function startHotReload(onReload) {
10973
+ function startHotReload(onReload, options = {}) {
10915
10974
  const workspace = getWorkspace();
10916
10975
  const watchPaths = [
10917
10976
  join9(workspace, "api"),
@@ -10926,33 +10985,22 @@ function startHotReload(onReload) {
10926
10985
  pollInterval: 100
10927
10986
  }
10928
10987
  });
10929
- watcher.on("change", async () => {
10930
- try {
10931
- await onReload();
10932
- logger.success("Reloaded");
10933
- } catch (error) {
10934
- logger.newLine();
10935
- logger.error(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
10936
- }
10937
- });
10938
- watcher.on("add", async () => {
10939
- try {
10940
- await onReload();
10941
- logger.success("Reloaded");
10942
- } catch (error) {
10943
- logger.newLine();
10944
- logger.error(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
10945
- }
10988
+ const logSuccess = options.onSuccess || (() => logger.success("Reloaded"));
10989
+ const logError = options.onError || ((error) => {
10990
+ logger.newLine();
10991
+ logger.error(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
10946
10992
  });
10947
- watcher.on("unlink", async () => {
10993
+ const handleReload = async (path) => {
10948
10994
  try {
10949
10995
  await onReload();
10950
- logger.success("Reloaded");
10996
+ logSuccess(path);
10951
10997
  } catch (error) {
10952
- logger.newLine();
10953
- logger.error(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
10998
+ logError(error);
10954
10999
  }
10955
- });
11000
+ };
11001
+ watcher.on("change", handleReload);
11002
+ watcher.on("add", handleReload);
11003
+ watcher.on("unlink", handleReload);
10956
11004
  return watcher;
10957
11005
  }
10958
11006
 
@@ -11537,8 +11585,8 @@ var loginCommand = new Command4("login").description("Authenticate with Playcade
11537
11585
  const email2 = existingProfile.email || "unknown user";
11538
11586
  const otherEnv = environment === "staging" ? "production" : "staging";
11539
11587
  const otherProfile = await getProfile(otherEnv, profileName);
11540
- logger.admonition("note", "I know you!", [
11541
- "You are already logged in",
11588
+ logger.admonition("note", "Hello again", [
11589
+ bold4("You're already logged in"),
11542
11590
  "",
11543
11591
  dim6("Email: ") + bold4(email2),
11544
11592
  dim6("Environment: ") + bold4(environment),
@@ -12003,7 +12051,6 @@ var listCommand = new Command9("list").alias("ls").description("List all games")
12003
12051
  logger.newLine();
12004
12052
  });
12005
12053
  } catch (error) {
12006
- logger.newLine();
12007
12054
  logger.error(
12008
12055
  `Failed to list games: ${error instanceof Error ? error.message : "Unknown error"}`
12009
12056
  );
@@ -12210,7 +12257,6 @@ async function listProfilesAction() {
12210
12257
  }
12211
12258
  for (const [environment, profiles] of profilesMap.entries()) {
12212
12259
  if (profiles.length === 0) continue;
12213
- logger.highlight(`${environment.charAt(0).toUpperCase() + environment.slice(1)}:`);
12214
12260
  const tableData = [];
12215
12261
  for (const profileName of profiles) {
12216
12262
  const profile = await getProfile(environment, profileName);
@@ -12220,7 +12266,8 @@ async function listProfilesAction() {
12220
12266
  });
12221
12267
  }
12222
12268
  if (tableData.length > 0) {
12223
- logger.table(tableData);
12269
+ const envTitle = environment.charAt(0).toUpperCase() + environment.slice(1);
12270
+ logger.table(tableData, envTitle);
12224
12271
  logger.newLine();
12225
12272
  }
12226
12273
  }
@@ -12289,15 +12336,19 @@ var resetCommand = new Command16("reset").description(
12289
12336
  logger.newLine();
12290
12337
  for (const [environment, profiles] of profilesMap.entries()) {
12291
12338
  if (profiles.length === 0) continue;
12292
- logger.highlight(
12293
- `${environment.charAt(0).toUpperCase() + environment.slice(1)}:`,
12294
- 1
12295
- );
12339
+ const tableData = [];
12296
12340
  for (const profileName of profiles) {
12297
12341
  const profile = await getProfile(environment, profileName);
12298
- logger.data(profileName, profile?.email || "", 2);
12342
+ tableData.push({
12343
+ Profile: profileName,
12344
+ Email: profile?.email ?? ""
12345
+ });
12346
+ }
12347
+ if (tableData.length > 0) {
12348
+ const envTitle = environment.charAt(0).toUpperCase() + environment.slice(1);
12349
+ logger.table(tableData, envTitle);
12350
+ logger.newLine();
12299
12351
  }
12300
- logger.newLine();
12301
12352
  }
12302
12353
  const confirmed = await confirm6({
12303
12354
  message: "Are you sure you want to remove all profiles?",
@@ -1,3 +1,34 @@
1
+ /**
2
+ * ─────────────────────────────────────────────────────────────────
3
+ * Calling your backend from your frontend:
4
+ * ─────────────────────────────────────────────────────────────────
5
+ *
6
+ * In your game's frontend, use the Playcademy SDK client to call
7
+ * your custom backend routes:
8
+ *
9
+ * ```typescript
10
+ * import { PlaycademyClient } from 'playcademy'
11
+ *
12
+ * const client = PlaycademyClient.init()
13
+ *
14
+ * // GET request to /api/hello
15
+ * const data = await client.backend.get('/hello')
16
+ * console.log(data.message)
17
+ *
18
+ * // POST request to /api/hello
19
+ * const result = await client.backend.post('/hello', { name: 'Player' })
20
+ * console.log(result.received)
21
+ *
22
+ * // Other HTTP methods are also available:
23
+ * await client.backend.put('/settings', settings)
24
+ * await client.backend.patch('/profile', updates)
25
+ * await client.backend.delete('/cache')
26
+ *
27
+ * // Custom methods
28
+ * await client.backend.request('/custom', 'OPTIONS')
29
+ * ```
30
+ */
31
+
1
32
  /**
2
33
  * Sample API route
3
34
  *
package/dist/utils.js CHANGED
@@ -1717,7 +1717,7 @@ function sql(strings, ...params) {
1717
1717
  return new SQL([new StringChunk(str)]);
1718
1718
  }
1719
1719
  sql2.raw = raw;
1720
- function join3(chunks, separator) {
1720
+ function join4(chunks, separator) {
1721
1721
  const result = [];
1722
1722
  for (const [i, chunk] of chunks.entries()) {
1723
1723
  if (i > 0 && separator !== void 0) {
@@ -1727,7 +1727,7 @@ function sql(strings, ...params) {
1727
1727
  }
1728
1728
  return new SQL(result);
1729
1729
  }
1730
- sql2.join = join3;
1730
+ sql2.join = join4;
1731
1731
  function identifier(value) {
1732
1732
  return new Name(value);
1733
1733
  }
@@ -3478,7 +3478,8 @@ var formatLog = (level, message, context2) => {
3478
3478
  return JSON.stringify(logEntry);
3479
3479
  };
3480
3480
  var performLog = (level, message, context2) => {
3481
- if (level === "debug" && false) {
3481
+ if (level === "debug" && process.env.PLAYCADEMY_EMBEDDED) {
3482
+ return;
3482
3483
  }
3483
3484
  if (isBrowser()) {
3484
3485
  logInBrowser(level, message, context2);
@@ -6160,6 +6161,31 @@ function createNotificationsNamespace(client) {
6160
6161
  }
6161
6162
  var init_notifications = () => {
6162
6163
  };
6164
+ function createBackendNamespace(client) {
6165
+ function normalizePath(path) {
6166
+ return path.startsWith("/") ? path : `/${path}`;
6167
+ }
6168
+ return {
6169
+ async get(path, headers) {
6170
+ return client["requestGameBackend"](normalizePath(path), "GET", void 0, headers);
6171
+ },
6172
+ async post(path, body, headers) {
6173
+ return client["requestGameBackend"](normalizePath(path), "POST", body, headers);
6174
+ },
6175
+ async put(path, body, headers) {
6176
+ return client["requestGameBackend"](normalizePath(path), "PUT", body, headers);
6177
+ },
6178
+ async patch(path, body, headers) {
6179
+ return client["requestGameBackend"](normalizePath(path), "PATCH", body, headers);
6180
+ },
6181
+ async delete(path, headers) {
6182
+ return client["requestGameBackend"](normalizePath(path), "DELETE", void 0, headers);
6183
+ },
6184
+ async request(path, method, body, headers) {
6185
+ return client["requestGameBackend"](normalizePath(path), method, body, headers);
6186
+ }
6187
+ };
6188
+ }
6163
6189
  var init_namespaces = __esm2(() => {
6164
6190
  init_identity();
6165
6191
  init_runtime();
@@ -6199,6 +6225,9 @@ function buildAllowedOrigins(explicit) {
6199
6225
  return ref ? [ref] : [];
6200
6226
  }
6201
6227
  function isOriginAllowed(origin, allowlist) {
6228
+ if (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1") {
6229
+ return true;
6230
+ }
6202
6231
  if (!allowlist || allowlist.length === 0) {
6203
6232
  console.error("[Playcademy SDK] No allowed origins configured. Consider passing allowedParentOrigins explicitly to init().");
6204
6233
  return false;
@@ -6471,6 +6500,7 @@ var init_client = __esm2(() => {
6471
6500
  realtime = createRealtimeNamespace(this);
6472
6501
  achievements = createAchievementsNamespace(this);
6473
6502
  notifications = createNotificationsNamespace(this);
6503
+ backend = createBackendNamespace(this);
6474
6504
  static init = init;
6475
6505
  static login = login2;
6476
6506
  static identity = identity;
@@ -6503,9 +6533,40 @@ function customTransform(text2) {
6503
6533
  const highlightCode = (text3) => text3.replace(/`([^`]+)`/g, (_, code) => greenBright(code));
6504
6534
  return highlightCode(text2);
6505
6535
  }
6536
+ function formatTable(data, title) {
6537
+ if (data.length === 0) return;
6538
+ const keys = Object.keys(data[0]);
6539
+ const rows = data.map((item) => keys.map((key) => String(item[key] ?? "")));
6540
+ const widths = keys.map((key, i) => {
6541
+ const headerWidth = key.length;
6542
+ const dataWidth = Math.max(...rows.map((row) => row[i].length));
6543
+ return Math.max(headerWidth, dataWidth);
6544
+ });
6545
+ const totalWidth = widths.reduce((sum, w) => sum + w + 3, -1);
6546
+ const separator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u253C") + "\u2524";
6547
+ const topBorder = "\u250C" + "\u2500".repeat(totalWidth) + "\u2510";
6548
+ const titleSeparator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C") + "\u2524";
6549
+ const bottomBorder = "\u2514" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u2534") + "\u2518";
6550
+ console.log(topBorder);
6551
+ if (title) {
6552
+ const titleText = bold(title);
6553
+ const titlePadding = totalWidth - title.length - 1;
6554
+ const titleRow = "\u2502 " + titleText + " ".repeat(titlePadding) + "\u2502";
6555
+ console.log(titleRow);
6556
+ console.log(titleSeparator);
6557
+ }
6558
+ const header = "\u2502 " + keys.map((key, i) => key.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
6559
+ console.log(header);
6560
+ console.log(separator);
6561
+ rows.forEach((row) => {
6562
+ const dataRow = "\u2502 " + row.map((cell, i) => cell.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
6563
+ console.log(dataRow);
6564
+ });
6565
+ console.log(bottomBorder);
6566
+ }
6506
6567
  var logger = {
6507
- table: (data) => {
6508
- console.table(data);
6568
+ table: (data, title) => {
6569
+ formatTable(data, title);
6509
6570
  },
6510
6571
  /**
6511
6572
  * Info message - general information
@@ -6826,9 +6887,47 @@ async function startDevServer(port, config, options = {}) {
6826
6887
  port
6827
6888
  });
6828
6889
  }
6890
+
6891
+ // src/lib/dev/reload.ts
6892
+ import { join as join3 } from "path";
6893
+ import chokidar from "chokidar";
6894
+ function startHotReload(onReload, options = {}) {
6895
+ const workspace = getWorkspace();
6896
+ const watchPaths = [
6897
+ join3(workspace, "api"),
6898
+ join3(workspace, "playcademy.config.js"),
6899
+ join3(workspace, "playcademy.config.json")
6900
+ ];
6901
+ const watcher = chokidar.watch(watchPaths, {
6902
+ persistent: true,
6903
+ ignoreInitial: true,
6904
+ awaitWriteFinish: {
6905
+ stabilityThreshold: 100,
6906
+ pollInterval: 100
6907
+ }
6908
+ });
6909
+ const logSuccess = options.onSuccess || (() => logger.success("Reloaded"));
6910
+ const logError = options.onError || ((error) => {
6911
+ logger.newLine();
6912
+ logger.error(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
6913
+ });
6914
+ const handleReload = async (path) => {
6915
+ try {
6916
+ await onReload();
6917
+ logSuccess(path);
6918
+ } catch (error) {
6919
+ logError(error);
6920
+ }
6921
+ };
6922
+ watcher.on("change", handleReload);
6923
+ watcher.on("add", handleReload);
6924
+ watcher.on("unlink", handleReload);
6925
+ return watcher;
6926
+ }
6829
6927
  export {
6830
6928
  findConfigPath as findPlaycademyConfigPath,
6831
6929
  loadConfig as loadPlaycademyConfig,
6832
6930
  startDevServer as startPlaycademyDevServer,
6931
+ startHotReload as startPlaycademyHotReload,
6833
6932
  validateConfig as validatePlaycademyConfig
6834
6933
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playcademy",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "module": "./dist/index.js",
6
6
  "exports": {